summaryrefslogtreecommitdiffstats
path: root/src/runtimerender/rendererimpl
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtimerender/rendererimpl')
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp543
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h472
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp2051
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImpl.h549
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp2220
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h182
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp261
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h115
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp1477
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h367
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp3007
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h452
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSVertexPipelineImpl.h463
13 files changed, 12159 insertions, 0 deletions
diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp
new file mode 100644
index 0000000..fff7e32
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.cpp
@@ -0,0 +1,543 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSRenderableObjects.h"
+#include "Qt3DSRendererImpl.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderCustomMaterialRenderContext.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderPathManager.h"
+#include "Qt3DSRenderPathRenderContext.h"
+#include "Qt3DSRenderDefaultMaterialShaderGenerator.h"
+
+using qt3ds::foundation::CRegisteredString;
+
+namespace qt3ds {
+namespace render {
+ struct SRenderableImage;
+ struct SShaderGeneratorGeneratedShader;
+ struct SSubsetRenderable;
+ using eastl::make_pair;
+ using eastl::reverse;
+
+ STextScaleAndOffset::STextScaleAndOffset(NVRenderTexture2D &inTexture,
+ const STextTextureDetails &inTextDetails,
+ const STextRenderInfo &inInfo)
+ : m_TextOffset(0, 0)
+ , m_TextScale(1, 1)
+
+ {
+ NVRenderTexture2D &theTexture = inTexture;
+ STextureDetails theDetails(theTexture.GetTextureDetails());
+ QT3DSVec2 textDimensions(inTextDetails.m_TextWidth / 2.0f, inTextDetails.m_TextHeight / 2.0f);
+ textDimensions.x /= inTextDetails.m_ScaleFactor.x;
+ textDimensions.y /= inTextDetails.m_ScaleFactor.y;
+ QT3DSVec2 theTextScale(textDimensions.x, textDimensions.y);
+ QT3DSVec2 theTextOffset(0, 0);
+
+ // Set the offsets to use after scaling the rect coordinates.
+ switch (inInfo.m_HorizontalAlignment) {
+ case TextHorizontalAlignment::Left:
+ theTextOffset[0] = theTextScale[0];
+ break;
+ case TextHorizontalAlignment::Center:
+ break;
+ case TextHorizontalAlignment::Right:
+ theTextOffset[0] = -theTextScale[0];
+ break;
+ default:
+ break;
+ }
+
+ switch (inInfo.m_VerticalAlignment) {
+ case TextVerticalAlignment::Top:
+ theTextOffset[1] = -theTextScale[1];
+ break;
+ case TextVerticalAlignment::Middle:
+ break;
+ case TextVerticalAlignment::Bottom:
+ theTextOffset[1] = theTextScale[1];
+ break;
+ default:
+ break;
+ }
+ m_TextScale = theTextScale;
+ m_TextOffset = theTextOffset;
+ }
+
+ void SSubsetRenderableBase::RenderShadowMapPass(const QT3DSVec2 &inCameraVec,
+ const SLight *inLight, const SCamera &inCamera,
+ SShadowMapEntry *inShadowMapEntry)
+ {
+ NVRenderContext &context(m_Generator.GetContext());
+ SRenderableDepthPrepassShader *shader = NULL;
+ NVRenderInputAssembler *pIA = NULL;
+
+ /*
+ if ( inLight->m_LightType == RenderLightTypes::Area )
+ shader = m_Generator.GetParaboloidDepthShader( m_TessellationMode );
+ else if ( inLight->m_LightType == RenderLightTypes::Directional )
+ shader = m_Generator.GetOrthographicDepthShader( m_TessellationMode );
+ else if ( inLight->m_LightType == RenderLightTypes::Point )
+ shader = m_Generator.GetCubeShadowDepthShader( m_TessellationMode ); // This
+ will change to include a geometry shader pass.
+ */
+
+ if (inLight->m_LightType == RenderLightTypes::Directional)
+ shader = m_Generator.GetOrthographicDepthShader(m_TessellationMode);
+ else
+ shader = m_Generator.GetCubeShadowDepthShader(m_TessellationMode);
+
+ if (shader == NULL || inShadowMapEntry == NULL)
+ return;
+
+ // for phong and npatch tesselleation we need the normals too
+ if (m_TessellationMode == TessModeValues::NoTess
+ || m_TessellationMode == TessModeValues::TessLinear)
+ pIA = m_Subset.m_InputAssemblerDepth;
+ else
+ pIA = m_Subset.m_InputAssembler;
+
+ QT3DSMat44 theModelViewProjection = inShadowMapEntry->m_LightVP * m_GlobalTransform;
+ // QT3DSMat44 theModelView = inLight->m_GlobalTransform.getInverse() * m_GlobalTransform;
+
+ context.SetActiveShader(&shader->m_Shader);
+ shader->m_MVP.Set(theModelViewProjection);
+ shader->m_CameraPosition.Set(inCamera.m_Position);
+ shader->m_GlobalTransform.Set(m_GlobalTransform);
+ shader->m_CameraProperties.Set(inCameraVec);
+ /*
+ shader->m_CameraDirection.Set( inCamera.GetDirection() );
+
+ shader->m_ShadowMV[0].Set( inShadowMapEntry->m_LightCubeView[0] * m_GlobalTransform );
+ shader->m_ShadowMV[1].Set( inShadowMapEntry->m_LightCubeView[1] * m_GlobalTransform );
+ shader->m_ShadowMV[2].Set( inShadowMapEntry->m_LightCubeView[2] * m_GlobalTransform );
+ shader->m_ShadowMV[3].Set( inShadowMapEntry->m_LightCubeView[3] * m_GlobalTransform );
+ shader->m_ShadowMV[4].Set( inShadowMapEntry->m_LightCubeView[4] * m_GlobalTransform );
+ shader->m_ShadowMV[5].Set( inShadowMapEntry->m_LightCubeView[5] * m_GlobalTransform );
+ shader->m_Projection.Set( inCamera.m_Projection );
+ */
+
+ // tesselation
+ if (m_TessellationMode != TessModeValues::NoTess) {
+ // set uniforms we need
+ shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor);
+ shader->m_Tessellation.m_InsideTessLevel.Set(m_Subset.m_InnerTessFactor);
+ // the blend value is hardcoded
+ shader->m_Tessellation.m_PhongBlend.Set(0.75);
+ // set distance range value
+ shader->m_Tessellation.m_DistanceRange.Set(inCameraVec);
+ // disable culling
+ shader->m_Tessellation.m_DisableCulling.Set(1.0);
+ }
+
+ context.SetInputAssembler(pIA);
+ context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset);
+ }
+
+ void SSubsetRenderableBase::RenderDepthPass(const QT3DSVec2 &inCameraVec,
+ SRenderableImage *inDisplacementImage,
+ float inDisplacementAmount)
+ {
+ NVRenderContext &context(m_Generator.GetContext());
+ SRenderableDepthPrepassShader *shader = NULL;
+ NVRenderInputAssembler *pIA = NULL;
+ SRenderableImage *displacementImage = inDisplacementImage;
+
+ if (m_Subset.m_PrimitiveType != NVRenderDrawMode::Patches)
+ shader = m_Generator.GetDepthPrepassShader(displacementImage != NULL);
+ else
+ shader = m_Generator.GetDepthTessPrepassShader(m_TessellationMode,
+ displacementImage != NULL);
+
+ if (shader == NULL)
+ return;
+
+ // for phong and npatch tesselleation or displacement mapping we need the normals (and uv's)
+ // too
+ if ((m_TessellationMode == TessModeValues::NoTess
+ || m_TessellationMode == TessModeValues::TessLinear)
+ && !displacementImage)
+ pIA = m_Subset.m_InputAssemblerDepth;
+ else
+ pIA = m_Subset.m_InputAssembler;
+
+ context.SetActiveShader(&shader->m_Shader);
+ context.SetCullingEnabled(true);
+
+ shader->m_MVP.Set(m_ModelContext.m_ModelViewProjection);
+
+ if (displacementImage) {
+ // setup image transform
+ const QT3DSMat44 &textureTransform = displacementImage->m_Image.m_TextureTransform;
+ const QT3DSF32 *dataPtr(textureTransform.front());
+ QT3DSVec3 offsets(dataPtr[12], dataPtr[13],
+ displacementImage->m_Image.m_TextureData.m_TextureFlags.IsPreMultiplied()
+ ? 1.0f
+ : 0.0f);
+ QT3DSVec4 rotations(dataPtr[0], dataPtr[4], dataPtr[1], dataPtr[5]);
+ displacementImage->m_Image.m_TextureData.m_Texture->SetTextureWrapS(
+ displacementImage->m_Image.m_HorizontalTilingMode);
+ displacementImage->m_Image.m_TextureData.m_Texture->SetTextureWrapT(
+ displacementImage->m_Image.m_VerticalTilingMode);
+
+ shader->m_DisplaceAmount.Set(inDisplacementAmount);
+ shader->m_DisplacementProps.m_Offsets.Set(offsets);
+ shader->m_DisplacementProps.m_Rotations.Set(rotations);
+ shader->m_DisplacementProps.m_Sampler.Set(
+ displacementImage->m_Image.m_TextureData.m_Texture);
+ }
+
+ // tesselation
+ if (m_TessellationMode != TessModeValues::NoTess) {
+ // set uniforms we need
+ shader->m_GlobalTransform.Set(m_GlobalTransform);
+
+ if (m_Generator.GetLayerRenderData() && m_Generator.GetLayerRenderData()->m_Camera)
+ shader->m_CameraPosition.Set(
+ m_Generator.GetLayerRenderData()->m_Camera->GetGlobalPos());
+ else if (m_Generator.GetLayerRenderData()->m_Camera)
+ shader->m_CameraPosition.Set(QT3DSVec3(0.0, 0.0, 1.0));
+
+ shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor);
+ shader->m_Tessellation.m_InsideTessLevel.Set(m_Subset.m_InnerTessFactor);
+ // the blend value is hardcoded
+ shader->m_Tessellation.m_PhongBlend.Set(0.75);
+ // set distance range value
+ shader->m_Tessellation.m_DistanceRange.Set(inCameraVec);
+ // enable culling
+ shader->m_Tessellation.m_DisableCulling.Set(0.0);
+ }
+
+ context.SetInputAssembler(pIA);
+ context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset);
+ }
+
+ // An interface to the shader generator that is available to the renderables
+
+ void SSubsetRenderable::Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet)
+ {
+ NVRenderContext &context(m_Generator.GetContext());
+
+ SShaderGeneratorGeneratedShader *shader = m_Generator.GetShader(*this, inFeatureSet);
+ if (shader == NULL)
+ return;
+
+ context.SetActiveShader(&shader->m_Shader);
+
+ m_Generator.GetQt3DSContext().GetDefaultMaterialShaderGenerator().SetMaterialProperties(
+ shader->m_Shader, m_Material, inCameraVec, m_ModelContext.m_ModelViewProjection,
+ m_ModelContext.m_NormalMatrix, m_ModelContext.m_Model.m_GlobalTransform, m_FirstImage,
+ m_Opacity, m_Generator.GetLayerGlobalRenderProperties());
+
+ // tesselation
+ if (m_Subset.m_PrimitiveType == NVRenderDrawMode::Patches) {
+ shader->m_Tessellation.m_EdgeTessLevel.Set(m_Subset.m_EdgeTessFactor);
+ shader->m_Tessellation.m_InsideTessLevel.Set(m_Subset.m_InnerTessFactor);
+ // the blend value is hardcoded
+ shader->m_Tessellation.m_PhongBlend.Set(0.75);
+ // this should finally be based on some user input
+ shader->m_Tessellation.m_DistanceRange.Set(inCameraVec);
+ // enable culling
+ shader->m_Tessellation.m_DisableCulling.Set(0.0);
+
+ if (m_Subset.m_WireframeMode) {
+ // we need the viewport matrix
+ NVRenderRect theViewport(context.GetViewport());
+ QT3DSMat44 vpMatrix;
+ vpMatrix.column0 = QT3DSVec4((float)theViewport.m_Width / 2.0f, 0.0, 0.0, 0.0);
+ vpMatrix.column1 = QT3DSVec4(0.0, (float)theViewport.m_Height / 2.0f, 0.0, 0.0);
+ vpMatrix.column2 = QT3DSVec4(0.0, 0.0, 1.0, 0.0);
+ vpMatrix.column3 =
+ QT3DSVec4((float)theViewport.m_Width / 2.0f + (float)theViewport.m_X,
+ (float)theViewport.m_Height / 2.0f + (float)theViewport.m_Y, 0.0, 1.0);
+
+ shader->m_ViewportMatrix.Set(vpMatrix);
+ }
+ }
+
+ context.SetCullingEnabled(true);
+ context.SetInputAssembler(m_Subset.m_InputAssembler);
+ context.Draw(m_Subset.m_PrimitiveType, m_Subset.m_Count, m_Subset.m_Offset);
+ }
+
+ void SSubsetRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec)
+ {
+ SRenderableImage *displacementImage = NULL;
+ for (SRenderableImage *theImage = m_FirstImage;
+ theImage != NULL && displacementImage == NULL; theImage = theImage->m_NextImage) {
+ if (theImage->m_MapType == ImageMapTypes::Displacement)
+ displacementImage = theImage;
+ }
+ SSubsetRenderableBase::RenderDepthPass(inCameraVec, displacementImage,
+ m_Material.m_DisplaceAmount);
+ }
+
+ void STextRenderable::Render(const QT3DSVec2 &inCameraVec)
+ {
+ NVRenderContext &context(m_Generator.GetContext());
+
+ if (!m_Text.m_PathFontDetails) {
+
+ STextRenderHelper theInfo = m_Generator.GetShader(*this, false);
+ if (theInfo.m_Shader == NULL)
+ return;
+ // All of our shaders produce premultiplied values.
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha);
+
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu(NVRenderBlendEquation::Add,
+ NVRenderBlendEquation::Add);
+
+ context.SetBlendFunction(blendFunc);
+ context.SetBlendEquation(blendEqu);
+ QT3DSVec4 theColor(m_Text.m_TextColor.x, m_Text.m_TextColor.y, m_Text.m_TextColor.z,
+ m_Text.m_GlobalOpacity);
+
+ STextShader &shader(*theInfo.m_Shader);
+ shader.Render(*m_Text.m_TextTexture, *this, theColor, m_ModelViewProjection,
+ inCameraVec, context, theInfo.m_QuadInputAssembler,
+ theInfo.m_QuadInputAssembler.GetIndexCount(), m_Text.m_TextTextureDetails,
+ QT3DSVec3(0, 0, 0));
+ } else {
+ QT3DS_ASSERT(context.IsPathRenderingSupported() && context.IsProgramPipelineSupported());
+
+ STextRenderHelper theInfo = m_Generator.GetShader(*this, true);
+ if (theInfo.m_Shader == NULL)
+ return;
+
+ // All of our shaders produce premultiplied values.
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha);
+
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu(NVRenderBlendEquation::Add,
+ NVRenderBlendEquation::Add);
+
+ context.SetBlendFunction(blendFunc);
+ context.SetBlendEquation(blendEqu);
+ QT3DSVec4 theColor(m_Text.m_TextColor.x, m_Text.m_TextColor.y, m_Text.m_TextColor.z,
+ m_Text.m_GlobalOpacity);
+ STextShader &shader(*theInfo.m_Shader);
+
+ shader.RenderPath(*m_Text.m_PathFontItem, *m_Text.m_PathFontDetails, *this, theColor,
+ m_ViewProjection, m_GlobalTransform, inCameraVec, context,
+ m_Text.m_TextTextureDetails, QT3DSVec3(0, 0, 0));
+ }
+ }
+
+ void STextRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec)
+ {
+ NVRenderContext &context(m_Generator.GetContext());
+ STextDepthShader *theDepthShader = m_Generator.GetTextDepthShader();
+ if (theDepthShader == NULL)
+ return;
+
+ if (!m_Text.m_PathFontDetails) {
+ // we may change stencil test state
+ qt3ds::render::NVRenderContextScopedProperty<bool> __stencilTest(
+ context, &NVRenderContext::IsStencilTestEnabled,
+ &NVRenderContext::SetStencilTestEnabled, true);
+
+ NVRenderShaderProgram &theShader(theDepthShader->m_Shader);
+ context.SetCullingEnabled(false);
+ context.SetActiveShader(&theShader);
+ theDepthShader->m_MVP.Set(m_ModelViewProjection);
+ theDepthShader->m_Sampler.Set(m_Text.m_TextTexture);
+ const STextScaleAndOffset &theScaleAndOffset(*this);
+ theDepthShader->m_Dimensions.Set(
+ QT3DSVec4(theScaleAndOffset.m_TextScale.x, theScaleAndOffset.m_TextScale.y,
+ theScaleAndOffset.m_TextOffset.x, theScaleAndOffset.m_TextOffset.y));
+ theDepthShader->m_CameraProperties.Set(inCameraVec);
+
+ STextureDetails theTextureDetails = m_Text.m_TextTexture->GetTextureDetails();
+ const STextTextureDetails &theTextTextureDetails(m_Text.m_TextTextureDetails);
+ QT3DSF32 theWidthScale =
+ (QT3DSF32)theTextTextureDetails.m_TextWidth / (QT3DSF32)theTextureDetails.m_Width;
+ QT3DSF32 theHeightScale =
+ (QT3DSF32)theTextTextureDetails.m_TextHeight / (QT3DSF32)theTextureDetails.m_Height;
+ theDepthShader->m_TextDimensions.Set(
+ QT3DSVec3(theWidthScale, theHeightScale, theTextTextureDetails.m_FlipY ? 1.0f : 0.0f));
+ context.SetInputAssembler(&theDepthShader->m_QuadInputAssembler);
+ context.Draw(NVRenderDrawMode::Triangles,
+ theDepthShader->m_QuadInputAssembler.GetIndexCount(), 0);
+ } else {
+ qt3ds::render::NVRenderBoolOp::Enum theDepthFunction = context.GetDepthFunction();
+ bool isDepthEnabled = context.IsDepthTestEnabled();
+ bool isStencilEnabled = context.IsStencilTestEnabled();
+ bool isDepthWriteEnabled = context.IsDepthWriteEnabled();
+ qt3ds::render::NVRenderStencilFunctionArgument theArg(qt3ds::render::NVRenderBoolOp::NotEqual,
+ 0, 0xFF);
+ qt3ds::render::NVRenderStencilOperationArgument theOpArg(
+ qt3ds::render::NVRenderStencilOp::Keep, qt3ds::render::NVRenderStencilOp::Keep,
+ qt3ds::render::NVRenderStencilOp::Zero);
+ NVScopedRefCounted<NVRenderDepthStencilState> depthStencilState =
+ context.CreateDepthStencilState(isDepthEnabled, isDepthWriteEnabled,
+ theDepthFunction, false, theArg, theArg, theOpArg,
+ theOpArg);
+
+ context.SetActiveShader(NULL);
+ context.SetCullingEnabled(false);
+
+ context.SetDepthStencilState(depthStencilState);
+
+ // setup transform
+ QT3DSMat44 offsetMatrix = QT3DSMat44::createIdentity();
+ offsetMatrix.setPosition(QT3DSVec3(
+ m_TextOffset.x - (QT3DSF32)m_Text.m_TextTextureDetails.m_TextWidth / 2.0f,
+ m_TextOffset.y - (QT3DSF32)m_Text.m_TextTextureDetails.m_TextHeight / 2.0f, 0.0));
+
+ QT3DSMat44 pathMatrix = m_Text.m_PathFontItem->GetTransform();
+
+ context.SetPathProjectionMatrix(m_ViewProjection);
+ context.SetPathModelViewMatrix(m_GlobalTransform * offsetMatrix * pathMatrix);
+
+ // first pass
+ m_Text.m_PathFontDetails->StencilFillPathInstanced(*m_Text.m_PathFontItem);
+
+ // second pass
+ context.SetStencilTestEnabled(true);
+ m_Text.m_PathFontDetails->CoverFillPathInstanced(*m_Text.m_PathFontItem);
+
+ context.SetStencilTestEnabled(isStencilEnabled);
+ context.SetDepthFunction(theDepthFunction);
+ }
+ }
+
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ void SDistanceFieldRenderable::Render(const QT3DSVec2 &inCameraVec)
+ {
+ m_distanceFieldText.renderText(m_text, m_mvp);
+ }
+
+ void SDistanceFieldRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec)
+ {
+ m_distanceFieldText.renderTextDepth(m_text, m_mvp);
+ }
+#endif
+
+ void SCustomMaterialRenderable::Render(const QT3DSVec2 & /*inCameraVec*/,
+ const SLayerRenderData &inLayerData,
+ const SLayer &inLayer, NVDataRef<SLight *> inLights,
+ const SCamera &inCamera,
+ const NVRenderTexture2D *inDepthTexture,
+ const NVRenderTexture2D *inSsaoTexture,
+ TShaderFeatureSet inFeatureSet)
+ {
+ IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext());
+ SCustomMaterialRenderContext theRenderContext(
+ inLayer, inLayerData, inLights, inCamera, m_ModelContext.m_Model, m_Subset,
+ m_ModelContext.m_ModelViewProjection, m_GlobalTransform, m_ModelContext.m_NormalMatrix,
+ m_Material, inDepthTexture, inSsaoTexture, m_ShaderDescription, m_FirstImage,
+ m_Opacity);
+
+ qt3dsContext.GetCustomMaterialSystem().RenderSubset(theRenderContext, inFeatureSet);
+ }
+
+ void SCustomMaterialRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec,
+ const SLayer & /*inLayer*/,
+ NVConstDataRef<SLight *> /*inLights*/
+ ,
+ const SCamera & /*inCamera*/,
+ const NVRenderTexture2D * /*inDepthTexture*/)
+ {
+
+ IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext());
+ if (!qt3dsContext.GetCustomMaterialSystem().RenderDepthPrepass(
+ m_ModelContext.m_ModelViewProjection, m_Material, m_Subset)) {
+ SRenderableImage *displacementImage = NULL;
+ for (SRenderableImage *theImage = m_FirstImage;
+ theImage != NULL && displacementImage == NULL; theImage = theImage->m_NextImage) {
+ if (theImage->m_MapType == ImageMapTypes::Displacement)
+ displacementImage = theImage;
+ }
+
+ SSubsetRenderableBase::RenderDepthPass(inCameraVec, displacementImage,
+ m_Material.m_DisplaceAmount);
+ }
+ }
+
+ void SPathRenderable::RenderDepthPass(const QT3DSVec2 &inCameraVec, const SLayer & /*inLayer*/,
+ NVConstDataRef<SLight *> inLights,
+ const SCamera &inCamera,
+ const NVRenderTexture2D * /*inDepthTexture*/)
+ {
+ IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext());
+ SPathRenderContext theRenderContext(
+ inLights, inCamera, m_Path, m_ModelViewProjection, m_GlobalTransform, m_NormalMatrix,
+ m_Opacity, m_Material, m_ShaderDescription, m_FirstImage, qt3dsContext.GetWireframeMode(),
+ inCameraVec, false, m_IsStroke);
+
+ qt3dsContext.GetPathManager().RenderDepthPrepass(
+ theRenderContext, m_Generator.GetLayerGlobalRenderProperties(), TShaderFeatureSet());
+ }
+
+ void SPathRenderable::Render(const QT3DSVec2 &inCameraVec, const SLayer & /*inLayer*/,
+ NVConstDataRef<SLight *> inLights, const SCamera &inCamera,
+ const NVRenderTexture2D * /*inDepthTexture*/
+ ,
+ const NVRenderTexture2D * /*inSsaoTexture*/
+ ,
+ TShaderFeatureSet inFeatureSet)
+ {
+ IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext());
+ SPathRenderContext theRenderContext(
+ inLights, inCamera, m_Path, m_ModelViewProjection, m_GlobalTransform, m_NormalMatrix,
+ m_Opacity, m_Material, m_ShaderDescription, m_FirstImage, qt3dsContext.GetWireframeMode(),
+ inCameraVec, m_RenderableFlags.HasTransparency(), m_IsStroke);
+
+ qt3dsContext.GetPathManager().RenderPath(
+ theRenderContext, m_Generator.GetLayerGlobalRenderProperties(), inFeatureSet);
+ }
+
+ void SPathRenderable::RenderShadowMapPass(const QT3DSVec2 &inCameraVec, const SLight *inLight,
+ const SCamera &inCamera,
+ SShadowMapEntry *inShadowMapEntry)
+ {
+ NVConstDataRef<SLight *> theLights;
+ IQt3DSRenderContext &qt3dsContext(m_Generator.GetQt3DSContext());
+
+ QT3DSMat44 theModelViewProjection = inShadowMapEntry->m_LightVP * m_GlobalTransform;
+ SPathRenderContext theRenderContext(
+ theLights, inCamera, m_Path, theModelViewProjection, m_GlobalTransform, m_NormalMatrix,
+ m_Opacity, m_Material, m_ShaderDescription, m_FirstImage, qt3dsContext.GetWireframeMode(),
+ inCameraVec, false, m_IsStroke);
+
+ if (inLight->m_LightType != RenderLightTypes::Directional) {
+ qt3dsContext.GetPathManager().RenderCubeFaceShadowPass(
+ theRenderContext, m_Generator.GetLayerGlobalRenderProperties(),
+ TShaderFeatureSet());
+ } else
+ qt3dsContext.GetPathManager().RenderShadowMapPass(
+ theRenderContext, m_Generator.GetLayerGlobalRenderProperties(),
+ TShaderFeatureSet());
+ }
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h
new file mode 100644
index 0000000..a369f7a
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRenderableObjects.h
@@ -0,0 +1,472 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_RENDER_IMPL_RENDERABLE_OBJECTS_H
+#define QT3DS_RENDER_IMPL_RENDERABLE_OBJECTS_H
+#include "Qt3DSRender.h"
+#include "foundation/Qt3DSFlags.h"
+#include "Qt3DSRenderModel.h"
+#include "foundation/Qt3DSContainers.h"
+#include "Qt3DSRenderDefaultMaterial.h"
+#include "Qt3DSRenderCustomMaterial.h"
+#include "Qt3DSRenderText.h"
+#include "Qt3DSRenderMesh.h"
+#include "Qt3DSRenderShaderKeys.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "foundation/Qt3DSInvasiveLinkedList.h"
+#include "Qt3DSRenderableImage.h"
+#include "Qt3DSDistanceFieldRenderer.h"
+
+namespace qt3ds {
+namespace render {
+
+ struct RenderPreparationResultFlagValues
+ {
+ enum Enum {
+ HasTransparency = 1 << 0,
+ CompletelyTransparent = 1 << 1,
+ Dirty = 1 << 2,
+ Pickable = 1 << 3,
+ DefaultMaterialMeshSubset = 1 << 4,
+ Text = 1 << 5,
+ Custom = 1 << 6,
+ CustomMaterialMeshSubset = 1 << 7,
+ HasRefraction = 1 << 8,
+ Path = 1 << 9,
+ ShadowCaster = 1 << 10,
+ DistanceField = 1 << 11,
+ };
+ };
+
+ struct SRenderableObjectFlags : public NVFlags<RenderPreparationResultFlagValues::Enum, QT3DSU32>
+ {
+ void ClearOrSet(bool value, RenderPreparationResultFlagValues::Enum enumVal)
+ {
+ if (value)
+ this->operator|=(enumVal);
+ else
+ clear(enumVal);
+ }
+
+ void SetHasTransparency(bool inHasTransparency)
+ {
+ ClearOrSet(inHasTransparency, RenderPreparationResultFlagValues::HasTransparency);
+ }
+ bool HasTransparency() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::HasTransparency);
+ }
+ bool HasRefraction() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::HasRefraction);
+ }
+ void SetCompletelyTransparent(bool inTransparent)
+ {
+ ClearOrSet(inTransparent, RenderPreparationResultFlagValues::CompletelyTransparent);
+ }
+ bool IsCompletelyTransparent() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::CompletelyTransparent);
+ }
+ void SetDirty(bool inDirty)
+ {
+ ClearOrSet(inDirty, RenderPreparationResultFlagValues::Dirty);
+ }
+ bool IsDirty() const { return this->operator&(RenderPreparationResultFlagValues::Dirty); }
+ void SetPickable(bool inPickable)
+ {
+ ClearOrSet(inPickable, RenderPreparationResultFlagValues::Pickable);
+ }
+ bool GetPickable() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::Pickable);
+ }
+
+ // Mutually exclusive values
+ void SetDefaultMaterialMeshSubset(bool inMeshSubset)
+ {
+ ClearOrSet(inMeshSubset, RenderPreparationResultFlagValues::DefaultMaterialMeshSubset);
+ }
+ bool IsDefaultMaterialMeshSubset() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::DefaultMaterialMeshSubset);
+ }
+
+ void SetCustomMaterialMeshSubset(bool inMeshSubset)
+ {
+ ClearOrSet(inMeshSubset, RenderPreparationResultFlagValues::CustomMaterialMeshSubset);
+ }
+ bool IsCustomMaterialMeshSubset() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::CustomMaterialMeshSubset);
+ }
+
+ void SetText(bool inText) { ClearOrSet(inText, RenderPreparationResultFlagValues::Text); }
+ bool IsText() const { return this->operator&(RenderPreparationResultFlagValues::Text); }
+
+ void setDistanceField(bool inText)
+ {
+ ClearOrSet(inText, RenderPreparationResultFlagValues::DistanceField);
+ }
+
+ bool isDistanceField() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::DistanceField);
+ }
+
+ void SetCustom(bool inCustom)
+ {
+ ClearOrSet(inCustom, RenderPreparationResultFlagValues::Custom);
+ }
+ bool IsCustom() const { return this->operator&(RenderPreparationResultFlagValues::Custom); }
+
+ void SetPath(bool inPath) { ClearOrSet(inPath, RenderPreparationResultFlagValues::Path); }
+ bool IsPath() const { return this->operator&(RenderPreparationResultFlagValues::Path); }
+
+ void SetShadowCaster(bool inCaster)
+ {
+ ClearOrSet(inCaster, RenderPreparationResultFlagValues::ShadowCaster);
+ }
+ bool IsShadowCaster() const
+ {
+ return this->operator&(RenderPreparationResultFlagValues::ShadowCaster);
+ }
+ };
+
+ struct SNodeLightEntry
+ {
+ SLight *m_Light;
+ QT3DSU32 m_LightIndex;
+ SNodeLightEntry *m_NextNode;
+ SNodeLightEntry()
+ : m_Light(NULL)
+ , m_NextNode(NULL)
+ {
+ }
+ SNodeLightEntry(SLight *inLight, QT3DSU32 inLightIndex)
+ : m_Light(inLight)
+ , m_LightIndex(inLightIndex)
+ , m_NextNode(NULL)
+ {
+ }
+ };
+
+ DEFINE_INVASIVE_SINGLE_LIST(NodeLightEntry);
+
+ IMPLEMENT_INVASIVE_SINGLE_LIST(NodeLightEntry, m_NextNode);
+
+ struct SRenderableObject;
+
+ typedef void (*TRenderFunction)(SRenderableObject &inObject, const QT3DSVec2 &inCameraProperties);
+
+ struct SRenderableObject
+ {
+ // Variables used for picking
+ const QT3DSMat44 &m_GlobalTransform;
+ const NVBounds3 &m_Bounds;
+ SRenderableObjectFlags m_RenderableFlags;
+ // For rough sorting for transparency and for depth
+ QT3DSVec3 m_WorldCenterPoint;
+ QT3DSF32 m_CameraDistanceSq;
+ TessModeValues::Enum m_TessellationMode;
+ bool m_ShadowCaster;
+ // For custom renderable objects the render function must be defined
+ TRenderFunction m_RenderFunction;
+ TNodeLightEntryList m_ScopedLights;
+ SRenderableObject(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ const QT3DSMat44 &inGlobalTransform, const NVBounds3 &inBounds,
+ TessModeValues::Enum inTessMode = TessModeValues::NoTess,
+ bool inShadowCaster = true, TRenderFunction inFunction = nullptr)
+
+ : m_GlobalTransform(inGlobalTransform)
+ , m_Bounds(inBounds)
+ , m_RenderableFlags(inFlags)
+ , m_WorldCenterPoint(inWorldCenterPt)
+ , m_CameraDistanceSq(0)
+ , m_TessellationMode(inTessMode)
+ , m_ShadowCaster(inShadowCaster)
+ , m_RenderFunction(inFunction)
+ {
+ }
+ bool operator<(SRenderableObject *inOther) const
+ {
+ return m_CameraDistanceSq < inOther->m_CameraDistanceSq;
+ }
+ };
+
+ typedef nvvector<SRenderableObject *> TRenderableObjectList;
+
+ // Different subsets from the same model will get the same
+ // model context so we can generate the MVP and normal matrix once
+ // and only once per subset.
+ struct SModelContext
+ {
+ const SModel &m_Model;
+ QT3DSMat44 m_ModelViewProjection;
+ QT3DSMat33 m_NormalMatrix;
+
+ SModelContext(const SModel &inModel, const QT3DSMat44 &inViewProjection)
+ : m_Model(inModel)
+ {
+ m_Model.CalculateMVPAndNormalMatrix(inViewProjection, m_ModelViewProjection,
+ m_NormalMatrix);
+ }
+ SModelContext(const SModelContext &inOther)
+ : m_Model(inOther.m_Model)
+ {
+ // The default copy constructor for these objects is pretty darn slow.
+ memCopy(&m_ModelViewProjection, &inOther.m_ModelViewProjection,
+ sizeof(m_ModelViewProjection));
+ memCopy(&m_NormalMatrix, &inOther.m_NormalMatrix, sizeof(m_NormalMatrix));
+ }
+ };
+
+ typedef nvvector<SModelContext *> TModelContextPtrList;
+
+ class Qt3DSRendererImpl;
+ struct SLayerRenderData;
+ struct SShadowMapEntry;
+
+ struct SSubsetRenderableBase : public SRenderableObject
+ {
+ Qt3DSRendererImpl &m_Generator;
+ const SModelContext &m_ModelContext;
+ SRenderSubset m_Subset;
+ QT3DSF32 m_Opacity;
+
+ SSubsetRenderableBase(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ Qt3DSRendererImpl &gen, const SRenderSubset &subset,
+ const SModelContext &modelContext, QT3DSF32 inOpacity)
+
+ : SRenderableObject(inFlags, inWorldCenterPt, modelContext.m_Model.m_GlobalTransform,
+ m_Subset.m_Bounds)
+ , m_Generator(gen)
+ , m_ModelContext(modelContext)
+ , m_Subset(subset)
+ , m_Opacity(inOpacity)
+ {
+ }
+ void RenderShadowMapPass(const QT3DSVec2 &inCameraVec, const SLight *inLight,
+ const SCamera &inCamera, SShadowMapEntry *inShadowMapEntry);
+
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec, SRenderableImage *inDisplacementImage,
+ float inDisplacementAmount);
+ };
+
+ /**
+ * A renderable that corresponds to a subset (a part of a model).
+ * These are created per subset per layer and are responsible for actually
+ * rendering this type of object.
+ */
+ struct SSubsetRenderable : public SSubsetRenderableBase
+ {
+ const SDefaultMaterial &m_Material;
+ SRenderableImage *m_FirstImage;
+ SShaderDefaultMaterialKey m_ShaderDescription;
+ NVConstDataRef<QT3DSMat44> m_Bones;
+
+ SSubsetRenderable(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ Qt3DSRendererImpl &gen, const SRenderSubset &subset,
+ const SDefaultMaterial &mat, const SModelContext &modelContext,
+ QT3DSF32 inOpacity, SRenderableImage *inFirstImage,
+ SShaderDefaultMaterialKey inShaderKey,
+ NVConstDataRef<QT3DSMat44> inBoneGlobals)
+
+ : SSubsetRenderableBase(inFlags, inWorldCenterPt, gen, subset, modelContext, inOpacity)
+ , m_Material(mat)
+ , m_FirstImage(inFirstImage)
+ , m_ShaderDescription(inShaderKey)
+ , m_Bones(inBoneGlobals)
+ {
+ m_RenderableFlags.SetDefaultMaterialMeshSubset(true);
+ m_RenderableFlags.SetCustom(false);
+ m_RenderableFlags.SetText(false);
+ m_RenderableFlags.setDistanceField(false);
+ }
+
+ void Render(const QT3DSVec2 &inCameraVec, TShaderFeatureSet inFeatureSet);
+
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec);
+
+ DefaultMaterialBlendMode::Enum getBlendingMode()
+ {
+ return m_Material.m_BlendMode;
+ }
+ };
+
+ struct SCustomMaterialRenderable : public SSubsetRenderableBase
+ {
+ const SCustomMaterial &m_Material;
+ SRenderableImage *m_FirstImage;
+ SShaderDefaultMaterialKey m_ShaderDescription;
+
+ SCustomMaterialRenderable(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ Qt3DSRendererImpl &gen, const SRenderSubset &subset,
+ const SCustomMaterial &mat, const SModelContext &modelContext,
+ QT3DSF32 inOpacity, SRenderableImage *inFirstImage,
+ SShaderDefaultMaterialKey inShaderKey)
+ : SSubsetRenderableBase(inFlags, inWorldCenterPt, gen, subset, modelContext, inOpacity)
+ , m_Material(mat)
+ , m_FirstImage(inFirstImage)
+ , m_ShaderDescription(inShaderKey)
+ {
+ m_RenderableFlags.SetCustomMaterialMeshSubset(true);
+ }
+
+ void Render(const QT3DSVec2 &inCameraVec, const SLayerRenderData &inLayerData,
+ const SLayer &inLayer, NVDataRef<SLight *> inLights, const SCamera &inCamera,
+ const NVRenderTexture2D *inDepthTexture, const NVRenderTexture2D *inSsaoTexture,
+ TShaderFeatureSet inFeatureSet);
+
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec, const SLayer &inLayer,
+ NVConstDataRef<SLight *> inLights, const SCamera &inCamera,
+ const NVRenderTexture2D *inDepthTexture);
+ };
+
+ struct STextScaleAndOffset
+ {
+ QT3DSVec2 m_TextOffset;
+ QT3DSVec2 m_TextScale;
+ STextScaleAndOffset(const QT3DSVec2 &inTextOffset, const QT3DSVec2 &inTextScale)
+ : m_TextOffset(inTextOffset)
+ , m_TextScale(inTextScale)
+ {
+ }
+ STextScaleAndOffset(NVRenderTexture2D &inTexture, const STextTextureDetails &inTextDetails,
+ const STextRenderInfo &inInfo);
+ };
+
+ struct STextRenderable : public SRenderableObject, public STextScaleAndOffset
+ {
+ Qt3DSRendererImpl &m_Generator;
+ const SText &m_Text;
+ NVRenderTexture2D &m_Texture;
+ QT3DSMat44 m_ModelViewProjection;
+ QT3DSMat44 m_ViewProjection;
+
+ STextRenderable(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ Qt3DSRendererImpl &gen, const SText &inText, const NVBounds3 &inBounds,
+ const QT3DSMat44 &inModelViewProjection, const QT3DSMat44 &inViewProjection,
+ NVRenderTexture2D &inTextTexture, const QT3DSVec2 &inTextOffset,
+ const QT3DSVec2 &inTextScale)
+ : SRenderableObject(inFlags, inWorldCenterPt, inText.m_GlobalTransform, inBounds)
+ , STextScaleAndOffset(inTextOffset, inTextScale)
+ , m_Generator(gen)
+ , m_Text(inText)
+ , m_Texture(inTextTexture)
+ , m_ModelViewProjection(inModelViewProjection)
+ , m_ViewProjection(inViewProjection)
+ {
+ m_RenderableFlags.SetDefaultMaterialMeshSubset(false);
+ m_RenderableFlags.SetCustom(false);
+ m_RenderableFlags.SetText(true);
+ m_RenderableFlags.setDistanceField(false);
+ }
+
+ void Render(const QT3DSVec2 &inCameraVec);
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec);
+ };
+
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ struct SDistanceFieldRenderable : public SRenderableObject
+ {
+ Q3DSDistanceFieldRenderer &m_distanceFieldText;
+ QT3DSMat44 m_mvp;
+ SText &m_text;
+
+ SDistanceFieldRenderable(SRenderableObjectFlags flags, QT3DSVec3 worldCenterPt,
+ SText &text, const NVBounds3 &bounds, const QT3DSMat44 &mvp,
+ Q3DSDistanceFieldRenderer &distanceFieldText)
+ : SRenderableObject(flags, worldCenterPt, text.m_GlobalTransform, bounds)
+ , m_distanceFieldText(distanceFieldText)
+ , m_mvp(mvp)
+ , m_text(text)
+ {
+ m_RenderableFlags.SetDefaultMaterialMeshSubset(false);
+ m_RenderableFlags.SetCustom(false);
+ m_RenderableFlags.SetText(false);
+ m_RenderableFlags.setDistanceField(true);
+ m_distanceFieldText.checkAndBuildGlyphs(text);
+ }
+
+ void Render(const QT3DSVec2 &inCameraVec);
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec);
+ };
+#endif
+
+ struct SPathRenderable : public SRenderableObject
+ {
+ Qt3DSRendererImpl &m_Generator;
+ SPath &m_Path;
+ NVBounds3 m_Bounds;
+ QT3DSMat44 m_ModelViewProjection;
+ QT3DSMat33 m_NormalMatrix;
+ const SGraphObject &m_Material;
+ QT3DSF32 m_Opacity;
+ SRenderableImage *m_FirstImage;
+ SShaderDefaultMaterialKey m_ShaderDescription;
+ bool m_IsStroke;
+
+ SPathRenderable(SRenderableObjectFlags inFlags, QT3DSVec3 inWorldCenterPt,
+ Qt3DSRendererImpl &gen, const QT3DSMat44 &inGlobalTransform,
+ NVBounds3 &inBounds, SPath &inPath, const QT3DSMat44 &inModelViewProjection,
+ const QT3DSMat33 inNormalMat, const SGraphObject &inMaterial, QT3DSF32 inOpacity,
+ SShaderDefaultMaterialKey inShaderKey, bool inIsStroke)
+
+ : SRenderableObject(inFlags, inWorldCenterPt, inGlobalTransform, m_Bounds)
+ , m_Generator(gen)
+ , m_Path(inPath)
+ , m_Bounds(inBounds)
+ , m_ModelViewProjection(inModelViewProjection)
+ , m_NormalMatrix(inNormalMat)
+ , m_Material(inMaterial)
+ , m_Opacity(inOpacity)
+ , m_FirstImage(NULL)
+ , m_ShaderDescription(inShaderKey)
+ , m_IsStroke(inIsStroke)
+ {
+ m_RenderableFlags.SetPath(true);
+ }
+ void Render(const QT3DSVec2 &inCameraVec, const SLayer &inLayer,
+ NVConstDataRef<SLight *> inLights, const SCamera &inCamera,
+ const NVRenderTexture2D *inDepthTexture, const NVRenderTexture2D *inSsaoTexture,
+ TShaderFeatureSet inFeatureSet);
+
+ void RenderDepthPass(const QT3DSVec2 &inCameraVec, const SLayer &inLayer,
+ NVConstDataRef<SLight *> inLights, const SCamera &inCamera,
+ const NVRenderTexture2D *inDepthTexture);
+
+ void RenderShadowMapPass(const QT3DSVec2 &inCameraVec, const SLight *inLight,
+ const SCamera &inCamera, SShadowMapEntry *inShadowMapEntry);
+ };
+}
+}
+
+#endif
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp
new file mode 100644
index 0000000..0b3f665
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.cpp
@@ -0,0 +1,2051 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSRender.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRendererImpl.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderImage.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSAllocatorCallback.h"
+#include "Qt3DSOffscreenRenderManager.h"
+#include "EASTL/sort.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderScene.h"
+#include "Qt3DSRenderPresentation.h"
+#include "Qt3DSRenderEffect.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "Qt3DSRenderResourceManager.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "Qt3DSRenderTextTextureCache.h"
+#include "Qt3DSRenderTextTextureAtlas.h"
+#include "Qt3DSRenderMaterialHelpers.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderRenderList.h"
+#include "Qt3DSRenderPath.h"
+#include "Qt3DSRenderShaderCodeGeneratorV2.h"
+#include "Qt3DSRenderDefaultMaterialShaderGenerator.h"
+#include <stdlib.h>
+
+#ifdef _WIN32
+#pragma warning(disable : 4355)
+#endif
+
+// Quick tests you can run to find performance problems
+
+//#define QT3DS_RENDER_DISABLE_HARDWARE_BLENDING 1
+//#define QT3DS_RENDER_DISABLE_LIGHTING 1
+//#define QT3DS_RENDER_DISABLE_TEXTURING 1
+//#define QT3DS_RENDER_DISABLE_TRANSPARENCY 1
+//#define QT3DS_RENDER_DISABLE_FRUSTUM_CULLING 1
+
+// If you are fillrate bound then sorting opaque objects can help in some circumstances
+//#define QT3DS_RENDER_DISABLE_OPAQUE_SORT 1
+
+using qt3ds::foundation::CRegisteredString;
+
+namespace qt3ds {
+namespace render {
+
+ struct SRenderableImage;
+ struct SShaderGeneratorGeneratedShader;
+ struct SSubsetRenderable;
+ using eastl::make_pair;
+ using eastl::reverse;
+ using eastl::stable_sort;
+
+ SEndlType Endl;
+
+ static SRenderInstanceId combineLayerAndId(const SLayer *layer, const SRenderInstanceId id)
+ {
+ uint64_t x = (uint64_t)layer;
+ x += 31u * (uint64_t)id;
+ return (SRenderInstanceId)x;
+ }
+
+ Qt3DSRendererImpl::Qt3DSRendererImpl(IQt3DSRenderContext &ctx)
+ : m_qt3dsContext(ctx)
+ , m_Context(ctx.GetRenderContext())
+ , m_BufferManager(ctx.GetBufferManager())
+ , m_OffscreenRenderManager(ctx.GetOffscreenRenderManager())
+ , m_StringTable(IStringTable::CreateStringTable(ctx.GetAllocator()))
+ , m_LayerShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LayerShaders")
+ , m_Shaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_Shaders")
+ , m_ConstantBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_ConstantBuffers")
+ , m_TextShader(ctx.GetAllocator())
+ , m_TextPathShader(ctx.GetAllocator())
+ , m_TextWidgetShader(ctx.GetAllocator())
+ , m_TextOnscreenShader(ctx.GetAllocator())
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ , m_LayerBlendTexture(ctx.GetResourceManager())
+ , m_BlendFB(NULL)
+#endif
+ , m_InstanceRenderMap(ctx.GetAllocator(), "Qt3DSRendererImpl::m_InstanceRenderMap")
+ , m_LastFrameLayers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LastFrameLayers")
+ , mRefCount(0)
+ , m_LastPickResults(ctx.GetAllocator(), "Qt3DSRendererImpl::m_LastPickResults")
+ , m_CurrentLayer(NULL)
+ , m_WidgetVertexBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetVertexBuffers")
+ , m_WidgetIndexBuffers(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetIndexBuffers")
+ , m_WidgetShaders(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetShaders")
+ , m_WidgetInputAssembler(ctx.GetAllocator(), "Qt3DSRendererImpl::m_WidgetInputAssembler")
+ , m_BoneIdNodeMap(ctx.GetAllocator(), "Qt3DSRendererImpl::m_BoneIdNodeMap")
+ , m_PickRenderPlugins(true)
+ , m_LayerCachingEnabled(true)
+ , m_LayerGPuProfilingEnabled(false)
+ {
+ }
+ Qt3DSRendererImpl::~Qt3DSRendererImpl()
+ {
+ m_LayerShaders.clear();
+ for (TShaderMap::iterator iter = m_Shaders.begin(), end = m_Shaders.end(); iter != end;
+ ++iter)
+ NVDelete(m_Context->GetAllocator(), iter->second);
+
+ m_Shaders.clear();
+ m_InstanceRenderMap.clear();
+ m_ConstantBuffers.clear();
+ }
+
+ void Qt3DSRendererImpl::addRef() { atomicIncrement(&mRefCount); }
+
+ void Qt3DSRendererImpl::release() { QT3DS_IMPLEMENT_REF_COUNT_RELEASE(m_Context->GetAllocator()); }
+
+ void Qt3DSRendererImpl::ChildrenUpdated(SNode &inParent)
+ {
+ if (inParent.m_Type == GraphObjectTypes::Layer) {
+ TInstanceRenderMap::iterator theIter
+ = m_InstanceRenderMap.find(static_cast<SRenderInstanceId>(&inParent));
+ if (theIter == m_InstanceRenderMap.end()) {
+ // The layer is not in main presentation, but it might be in subpresentation
+ theIter = m_InstanceRenderMap.begin();
+ while (theIter != m_InstanceRenderMap.end()) {
+ if (static_cast<SNode *>(&theIter->second.mPtr->m_Layer) == &inParent)
+ break;
+ theIter++;
+ }
+ }
+ if (theIter != m_InstanceRenderMap.end()) {
+ theIter->second->m_CamerasAndLights.clear();
+ theIter->second->m_RenderableNodes.clear();
+ }
+ } else if (inParent.m_Parent)
+ ChildrenUpdated(*inParent.m_Parent);
+ }
+
+ QT3DSF32 Qt3DSRendererImpl::GetTextScale(const SText &inText)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inText);
+ if (theData)
+ return theData->m_TextScale;
+ return 1.0f;
+ }
+
+ static inline SLayer *GetNextLayer(SLayer &inLayer)
+ {
+ if (inLayer.m_NextSibling && inLayer.m_NextSibling->m_Type == GraphObjectTypes::Layer)
+ return static_cast<SLayer *>(inLayer.m_NextSibling);
+ return NULL;
+ }
+
+ static inline void MaybePushLayer(SLayer &inLayer, nvvector<SLayer *> &outLayerList)
+ {
+ inLayer.CalculateGlobalVariables();
+ if (inLayer.m_Flags.IsGloballyActive() && inLayer.m_Flags.IsLayerRenderToTarget())
+ outLayerList.push_back(&inLayer);
+ }
+ static void BuildRenderableLayers(SLayer &inLayer, nvvector<SLayer *> &renderableLayers,
+ bool inRenderSiblings)
+ {
+ MaybePushLayer(inLayer, renderableLayers);
+ if (inRenderSiblings) {
+ for (SLayer *theNextLayer = GetNextLayer(inLayer); theNextLayer;
+ theNextLayer = GetNextLayer(*theNextLayer))
+ MaybePushLayer(*theNextLayer, renderableLayers);
+ }
+ }
+
+ void Qt3DSRendererImpl::EnableLayerGpuProfiling(bool inEnabled)
+ {
+ if (m_LayerGPuProfilingEnabled != inEnabled) {
+ TInstanceRenderMap::iterator theIter;
+ for (theIter = m_InstanceRenderMap.begin(); theIter != m_InstanceRenderMap.end();
+ theIter++) {
+ SLayerRenderData *data = theIter->second;
+ if (!inEnabled)
+ data->m_LayerProfilerGpu = nullptr;
+ else
+ data->CreateGpuProfiler();
+ }
+ }
+ m_LayerGPuProfilingEnabled = inEnabled;
+ }
+
+ bool Qt3DSRendererImpl::PrepareLayerForRender(SLayer &inLayer,
+ const QT3DSVec2 &inViewportDimensions,
+ bool inRenderSiblings,
+ const SRenderInstanceId id)
+ {
+ (void)inViewportDimensions;
+ nvvector<SLayer *> renderableLayers(m_qt3dsContext.GetPerFrameAllocator(), "LayerVector");
+ // Found by fair roll of the dice.
+ renderableLayers.reserve(4);
+
+ BuildRenderableLayers(inLayer, renderableLayers, inRenderSiblings);
+
+ bool retval = false;
+
+ for (nvvector<SLayer *>::reverse_iterator iter = renderableLayers.rbegin(),
+ end = renderableLayers.rend();
+ iter != end; ++iter) {
+ // Store the previous state of if we were rendering a layer.
+ SLayer *theLayer = *iter;
+ SLayerRenderData *theRenderData = GetOrCreateLayerRenderDataForNode(*theLayer, id);
+
+ if (theRenderData) {
+ theRenderData->PrepareForRender();
+ retval = retval || theRenderData->m_LayerPrepResult->m_Flags.WasDirty();
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ return retval;
+ }
+
+ void Qt3DSRendererImpl::RenderLayer(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions,
+ bool clear, QT3DSVec4 clearColor, bool inRenderSiblings,
+ const SRenderInstanceId id)
+ {
+ (void)inViewportDimensions;
+ nvvector<SLayer *> renderableLayers(m_qt3dsContext.GetPerFrameAllocator(), "LayerVector");
+ // Found by fair roll of the dice.
+ renderableLayers.reserve(4);
+
+ BuildRenderableLayers(inLayer, renderableLayers, inRenderSiblings);
+
+ NVRenderContext &theRenderContext(m_qt3dsContext.GetRenderContext());
+ qt3ds::render::NVRenderFrameBuffer *theFB = theRenderContext.GetRenderTarget();
+ for (nvvector<SLayer *>::reverse_iterator iter = renderableLayers.rbegin(),
+ end = renderableLayers.rend();
+ iter != end; ++iter) {
+ SLayer *theLayer = *iter;
+ SLayerRenderData *theRenderData = GetOrCreateLayerRenderDataForNode(*theLayer, id);
+ SLayerRenderPreparationResult &prepRes(*theRenderData->m_LayerPrepResult);
+ LayerBlendTypes::Enum layerBlend = prepRes.GetLayer()->GetLayerBlend();
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ if ((layerBlend == LayerBlendTypes::Overlay ||
+ layerBlend == LayerBlendTypes::ColorBurn ||
+ layerBlend == LayerBlendTypes::ColorDodge) &&
+ !theRenderContext.IsAdvancedBlendHwSupported() &&
+ !theRenderContext.IsAdvancedBlendHwSupportedKHR()) {
+ // Create and set up FBO and texture for advanced blending SW fallback
+ NVRenderRect viewport = theRenderContext.GetViewport();
+ m_LayerBlendTexture.EnsureTexture(viewport.m_Width + viewport.m_X,
+ viewport.m_Height + viewport.m_Y,
+ NVRenderTextureFormats::RGBA8);
+ if (m_BlendFB == NULL)
+ m_BlendFB = theRenderContext.CreateFrameBuffer();
+ m_BlendFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerBlendTexture);
+ theRenderContext.SetRenderTarget(m_BlendFB);
+ theRenderContext.SetScissorTestEnabled(false);
+ QT3DSVec4 color(0.0f);
+ if (clear)
+ color = clearColor;
+
+ QT3DSVec4 origColor = theRenderContext.GetClearColor();
+ theRenderContext.SetClearColor(color);
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ theRenderContext.SetClearColor(origColor);
+ theRenderContext.SetRenderTarget(theFB);
+ break;
+ } else {
+ m_LayerBlendTexture.ReleaseTexture();
+ }
+#endif
+ }
+ for (nvvector<SLayer *>::reverse_iterator iter = renderableLayers.rbegin(),
+ end = renderableLayers.rend();
+ iter != end; ++iter) {
+ // Store the previous state of if we were rendering a layer.
+ SLayer *theLayer = *iter;
+ SLayerRenderData *theRenderData = GetOrCreateLayerRenderDataForNode(*theLayer, id);
+
+ if (theRenderData) {
+ if (theRenderData->m_LayerPrepResult->IsLayerVisible())
+ theRenderData->RunnableRenderToViewport(theFB);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+ }
+
+ SLayer *Qt3DSRendererImpl::GetLayerForNode(const SNode &inNode) const
+ {
+ if (inNode.m_Type == GraphObjectTypes::Layer) {
+ return &const_cast<SLayer &>(static_cast<const SLayer &>(inNode));
+ }
+ if (inNode.m_Parent)
+ return GetLayerForNode(*inNode.m_Parent);
+ return NULL;
+ }
+
+ SLayerRenderData *Qt3DSRendererImpl::GetOrCreateLayerRenderDataForNode(const SNode &inNode,
+ const SRenderInstanceId id)
+ {
+ const SLayer *theLayer = GetLayerForNode(inNode);
+ if (theLayer) {
+ TInstanceRenderMap::const_iterator theIter
+ = m_InstanceRenderMap.find(combineLayerAndId(theLayer, id));
+ if (theIter != m_InstanceRenderMap.end())
+ return const_cast<SLayerRenderData *>(theIter->second.mPtr);
+
+ SLayerRenderData *theRenderData = QT3DS_NEW(m_Context->GetAllocator(), SLayerRenderData)(
+ const_cast<SLayer &>(*theLayer), *this);
+ m_InstanceRenderMap.insert(make_pair(combineLayerAndId(theLayer, id), theRenderData));
+
+ // create a profiler if enabled
+ if (IsLayerGpuProfilingEnabled() && theRenderData)
+ theRenderData->CreateGpuProfiler();
+
+ return theRenderData;
+ }
+ return NULL;
+ }
+
+ SCamera *Qt3DSRendererImpl::GetCameraForNode(const SNode &inNode) const
+ {
+ SLayerRenderData *theLayer =
+ const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode);
+ if (theLayer)
+ return theLayer->m_Camera;
+ return NULL;
+ }
+
+ Option<SCuboidRect> Qt3DSRendererImpl::GetCameraBounds(const SGraphObject &inObject)
+ {
+ if (GraphObjectTypes::IsNodeType(inObject.m_Type)) {
+ const SNode &theNode = static_cast<const SNode &>(inObject);
+ SLayerRenderData *theLayer = GetOrCreateLayerRenderDataForNode(theNode);
+ if (theLayer->GetOffscreenRenderer() == false) {
+ SCamera *theCamera = theLayer->m_Camera;
+ if (theCamera)
+ return theCamera->GetCameraBounds(
+ theLayer->m_LayerPrepResult->GetLayerToPresentationViewport(),
+ theLayer->m_LayerPrepResult->GetPresentationDesignDimensions());
+ }
+ }
+ return Option<SCuboidRect>();
+ }
+
+ void Qt3DSRendererImpl::DrawScreenRect(NVRenderRectF inRect, const QT3DSVec3 &inColor)
+ {
+ SCamera theScreenCamera;
+ theScreenCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ NVRenderRectF theViewport(m_Context->GetViewport());
+ theScreenCamera.m_Flags.SetOrthographic(true);
+ theScreenCamera.CalculateGlobalVariables(theViewport,
+ QT3DSVec2(theViewport.m_Width, theViewport.m_Height));
+ GenerateXYQuad();
+ if (!m_ScreenRectShader) {
+ IShaderProgramGenerator &theGenerator(GetProgramGenerator());
+ theGenerator.BeginProgram();
+ IShaderStageGenerator &vertexGenerator(
+ *theGenerator.GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *theGenerator.GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddUniform("rectangle_dims", "vec3");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append(
+ "\tgl_Position = model_view_projection * vec4(attr_pos * rectangle_dims, 1.0);");
+ vertexGenerator.Append("}");
+ fragmentGenerator.AddUniform("output_color", "vec3");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tgl_FragColor.rgb = output_color;");
+ fragmentGenerator.Append("\tgl_FragColor.a = 1.0;");
+ fragmentGenerator.Append("}");
+ // No flags enabled
+ m_ScreenRectShader = theGenerator.CompileGeneratedShader(
+ "DrawScreenRect", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ }
+ if (m_ScreenRectShader) {
+ // Fudge the rect by one pixel to ensure we see all the corners.
+ if (inRect.m_Width > 1)
+ inRect.m_Width -= 1;
+ if (inRect.m_Height > 1)
+ inRect.m_Height -= 1;
+ inRect.m_X += 1;
+ inRect.m_Y += 1;
+ // Figure out the rect center.
+ SNode theNode;
+
+ QT3DSVec2 rectGlobalCenter = inRect.Center();
+ QT3DSVec2 rectCenter(theViewport.ToNormalizedRectRelative(rectGlobalCenter));
+ theNode.m_Position.x = rectCenter.x;
+ theNode.m_Position.y = rectCenter.y;
+ theNode.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ theNode.CalculateGlobalVariables();
+ QT3DSMat44 theViewProjection;
+ theScreenCamera.CalculateViewProjectionMatrix(theViewProjection);
+ QT3DSMat44 theMVP;
+ QT3DSMat33 theNormal;
+ theNode.CalculateMVPAndNormalMatrix(theViewProjection, theMVP, theNormal);
+ m_Context->SetBlendingEnabled(false);
+ m_Context->SetDepthWriteEnabled(false);
+ m_Context->SetDepthTestEnabled(false);
+ m_Context->SetCullingEnabled(false);
+ m_Context->SetActiveShader(m_ScreenRectShader);
+ m_ScreenRectShader->SetPropertyValue("model_view_projection", theMVP);
+ m_ScreenRectShader->SetPropertyValue("output_color", inColor);
+ m_ScreenRectShader->SetPropertyValue(
+ "rectangle_dims", QT3DSVec3(inRect.m_Width / 2.0f, inRect.m_Height / 2.0f, 0.0f));
+ }
+ if (!m_RectInputAssembler) {
+ QT3DS_ASSERT(m_QuadVertexBuffer);
+ QT3DSU8 indexData[] = { 0, 1, 1, 2, 2, 3, 3, 0 };
+
+ m_RectIndexBuffer = m_Context->CreateIndexBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Static,
+ qt3ds::render::NVRenderComponentTypes::QT3DSU8, sizeof(indexData),
+ toConstDataRef(indexData, sizeof(indexData)));
+
+ qt3ds::render::NVRenderVertexBufferEntry theEntries[] = {
+ qt3ds::render::NVRenderVertexBufferEntry("attr_pos",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3),
+ };
+
+ // create our attribute layout
+ m_RectAttribLayout = m_Context->CreateAttributeLayout(toConstDataRef(theEntries, 1));
+
+ QT3DSU32 strides = m_QuadVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ m_RectInputAssembler = m_Context->CreateInputAssembler(
+ m_RectAttribLayout, toConstDataRef(&m_QuadVertexBuffer.mPtr, 1), m_RectIndexBuffer,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ }
+
+ m_Context->SetInputAssembler(m_RectInputAssembler);
+ m_Context->Draw(NVRenderDrawMode::Lines, m_RectIndexBuffer->GetNumIndices(), 0);
+ }
+
+ void Qt3DSRendererImpl::SetupWidgetLayer()
+ {
+ NVRenderContext &theContext = m_qt3dsContext.GetRenderContext();
+
+ if (!m_WidgetTexture) {
+ IResourceManager &theManager = m_qt3dsContext.GetResourceManager();
+ m_WidgetTexture = theManager.AllocateTexture2D(m_BeginFrameViewport.m_Width,
+ m_BeginFrameViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ m_WidgetFBO = theManager.AllocateFrameBuffer();
+ m_WidgetFBO->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*m_WidgetTexture));
+ theContext.SetRenderTarget(m_WidgetFBO);
+
+ // NVRenderRect theScissorRect( 0, 0, m_BeginFrameViewport.m_Width,
+ // m_BeginFrameViewport.m_Height );
+ // NVRenderContextScopedProperty<NVRenderRect> __scissorRect( theContext,
+ // &NVRenderContext::GetScissorRect, &NVRenderContext::SetScissorRect, theScissorRect );
+ qt3ds::render::NVRenderContextScopedProperty<bool> __scissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled, false);
+ m_Context->SetClearColor(QT3DSVec4(0, 0, 0, 0));
+ m_Context->Clear(NVRenderClearValues::Color);
+
+ } else
+ theContext.SetRenderTarget(m_WidgetFBO);
+ }
+
+ void Qt3DSRendererImpl::BeginFrame()
+ {
+ for (QT3DSU32 idx = 0, end = m_LastFrameLayers.size(); idx < end; ++idx)
+ m_LastFrameLayers[idx]->ResetForFrame();
+ m_LastFrameLayers.clear();
+ m_BeginFrameViewport = m_qt3dsContext.GetRenderList().GetViewport();
+ }
+ void Qt3DSRendererImpl::EndFrame()
+ {
+ if (m_WidgetTexture) {
+ using qt3ds::render::NVRenderContextScopedProperty;
+ // Releasing the widget FBO can set it as the active frame buffer.
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __fbo(
+ *m_Context, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ STextureDetails theDetails = m_WidgetTexture->GetTextureDetails();
+ m_Context->SetBlendingEnabled(true);
+ // Colors are expected to be non-premultiplied, so we premultiply alpha into them at
+ // this point.
+ m_Context->SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha));
+ m_Context->SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add));
+
+ m_Context->SetDepthTestEnabled(false);
+ m_Context->SetScissorTestEnabled(false);
+ m_Context->SetViewport(m_BeginFrameViewport);
+ SCamera theCamera;
+ theCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ theCamera.m_Flags.SetOrthographic(true);
+ QT3DSVec2 theTextureDims((QT3DSF32)theDetails.m_Width, (QT3DSF32)theDetails.m_Height);
+ theCamera.CalculateGlobalVariables(
+ NVRenderRect(0, 0, theDetails.m_Width, theDetails.m_Height), theTextureDims);
+ QT3DSMat44 theViewProj;
+ theCamera.CalculateViewProjectionMatrix(theViewProj);
+ RenderQuad(theTextureDims, theViewProj, *m_WidgetTexture);
+
+ IResourceManager &theManager(m_qt3dsContext.GetResourceManager());
+ theManager.Release(*m_WidgetFBO);
+ theManager.Release(*m_WidgetTexture);
+ m_WidgetTexture = NULL;
+ m_WidgetFBO = NULL;
+ }
+ }
+
+ inline bool PickResultLessThan(const Qt3DSRenderPickResult &lhs, const Qt3DSRenderPickResult &rhs)
+ {
+ return FloatLessThan(lhs.m_CameraDistanceSq, rhs.m_CameraDistanceSq);
+ }
+
+ inline QT3DSF32 ClampUVCoord(QT3DSF32 inUVCoord, NVRenderTextureCoordOp::Enum inCoordOp)
+ {
+ if (inUVCoord > 1.0f || inUVCoord < 0.0f) {
+ switch (inCoordOp) {
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ case NVRenderTextureCoordOp::ClampToEdge:
+ inUVCoord = NVMin(inUVCoord, 1.0f);
+ inUVCoord = NVMax(inUVCoord, 0.0f);
+ break;
+ case NVRenderTextureCoordOp::Repeat: {
+ QT3DSF32 multiplier = inUVCoord > 0.0f ? 1.0f : -1.0f;
+ QT3DSF32 clamp = fabs(inUVCoord);
+ clamp = clamp - floor(clamp);
+ if (multiplier < 0)
+ inUVCoord = 1.0f - clamp;
+ else
+ inUVCoord = clamp;
+ } break;
+ case NVRenderTextureCoordOp::MirroredRepeat: {
+ QT3DSF32 multiplier = inUVCoord > 0.0f ? 1.0f : -1.0f;
+ QT3DSF32 clamp = fabs(inUVCoord);
+ if (multiplier > 0.0f)
+ clamp -= 1.0f;
+ QT3DSU32 isMirrored = ((QT3DSU32)clamp) % 2 == 0;
+ QT3DSF32 remainder = clamp - floor(clamp);
+ inUVCoord = remainder;
+ if (isMirrored) {
+ if (multiplier > 0.0f)
+ inUVCoord = 1.0f - inUVCoord;
+ } else {
+ if (multiplier < 0.0f)
+ inUVCoord = 1.0f - remainder;
+ }
+ } break;
+ }
+ }
+ return inUVCoord;
+ }
+
+ static eastl::pair<QT3DSVec2, QT3DSVec2>
+ GetMouseCoordsAndViewportFromSubObject(QT3DSVec2 inLocalHitUVSpace,
+ Qt3DSRenderPickSubResult &inSubResult)
+ {
+ QT3DSMat44 theTextureMatrix(inSubResult.m_TextureMatrix);
+ QT3DSVec3 theNewUVCoords(
+ theTextureMatrix.transform(QT3DSVec3(inLocalHitUVSpace.x, inLocalHitUVSpace.y, 0)));
+ theNewUVCoords.x = ClampUVCoord(theNewUVCoords.x, inSubResult.m_HorizontalTilingMode);
+ theNewUVCoords.y = ClampUVCoord(theNewUVCoords.y, inSubResult.m_VerticalTilingMode);
+ QT3DSVec2 theViewportDimensions =
+ QT3DSVec2((QT3DSF32)inSubResult.m_ViewportWidth, (QT3DSF32)inSubResult.m_ViewportHeight);
+ QT3DSVec2 theMouseCoords(theNewUVCoords.x * theViewportDimensions.x,
+ (1.0f - theNewUVCoords.y) * theViewportDimensions.y);
+
+ return eastl::make_pair(theMouseCoords, theViewportDimensions);
+ }
+
+ SPickResultProcessResult Qt3DSRendererImpl::ProcessPickResultList(bool inPickEverything)
+ {
+ if (m_LastPickResults.empty())
+ return SPickResultProcessResult();
+ // Things are rendered in a particular order and we need to respect that ordering.
+ eastl::stable_sort(m_LastPickResults.begin(), m_LastPickResults.end(), PickResultLessThan);
+
+ // We need to pick against sub objects basically somewhat recursively
+ // but if we don't hit any sub objects and the parent isn't pickable then
+ // we need to move onto the next item in the list.
+ // We need to keep in mind that theQuery->Pick will enter this method in a later
+ // stack frame so *if* we get to sub objects we need to pick against them but if the pick
+ // completely misses *and* the parent object locally pickable is false then we need to move
+ // onto the next object.
+
+ QT3DSU32 maxPerFrameAllocationPickResultCount =
+ SFastAllocator<>::SlabSize / sizeof(Qt3DSRenderPickResult);
+ QT3DSU32 numToCopy =
+ NVMin(maxPerFrameAllocationPickResultCount, (QT3DSU32)m_LastPickResults.size());
+ QT3DSU32 numCopyBytes = numToCopy * sizeof(Qt3DSRenderPickResult);
+ Qt3DSRenderPickResult *thePickResults = reinterpret_cast<Qt3DSRenderPickResult *>(
+ GetPerFrameAllocator().allocate(numCopyBytes, "tempPickData", __FILE__, __LINE__));
+ memCopy(thePickResults, m_LastPickResults.data(), numCopyBytes);
+ m_LastPickResults.clear();
+ bool foundValidResult = false;
+ SPickResultProcessResult thePickResult(thePickResults[0]);
+ for (size_t idx = 0; idx < numToCopy && foundValidResult == false; ++idx) {
+ thePickResult = thePickResults[idx];
+ // Here we do a hierarchy. Picking against sub objects takes precedence.
+ // If picking against the sub object doesn't return a valid result *and*
+ // the current object isn't globally pickable then we move onto the next object returned
+ // by the pick query.
+ if (thePickResult.m_HitObject != NULL && thePickResult.m_FirstSubObject != NULL
+ && m_PickRenderPlugins) {
+ QT3DSVec2 theUVCoords(thePickResult.m_LocalUVCoords.x,
+ thePickResult.m_LocalUVCoords.y);
+ IOffscreenRenderer *theSubRenderer(thePickResult.m_FirstSubObject->m_SubRenderer);
+ eastl::pair<QT3DSVec2, QT3DSVec2> mouseAndViewport =
+ GetMouseCoordsAndViewportFromSubObject(theUVCoords,
+ *thePickResult.m_FirstSubObject);
+ QT3DSVec2 theMouseCoords = mouseAndViewport.first;
+ QT3DSVec2 theViewportDimensions = mouseAndViewport.second;
+ IGraphObjectPickQuery *theQuery = theSubRenderer->GetGraphObjectPickQuery(this);
+ if (theQuery) {
+ Qt3DSRenderPickResult theInnerPickResult =
+ theQuery->Pick(theMouseCoords, theViewportDimensions, inPickEverything);
+ if (theInnerPickResult.m_HitObject) {
+ thePickResult = theInnerPickResult;
+ thePickResult.m_OffscreenRenderer = theSubRenderer;
+ foundValidResult = true;
+ thePickResult.m_WasPickConsumed = true;
+ } else if (GraphObjectTypes::IsNodeType(thePickResult.m_HitObject->m_Type)) {
+ const SNode *theNode =
+ static_cast<const SNode *>(thePickResult.m_HitObject);
+ if (theNode->m_Flags.IsGloballyPickable() == true) {
+ foundValidResult = true;
+ thePickResult.m_WasPickConsumed = true;
+ }
+ }
+ } else {
+ // If the sub renderer doesn't consume the pick then we return the picked object
+ // itself. So no matter what, if we get to here the pick was consumed.
+ thePickResult.m_WasPickConsumed = true;
+ bool wasPickConsumed =
+ theSubRenderer->Pick(theMouseCoords, theViewportDimensions, this);
+ if (wasPickConsumed) {
+ thePickResult.m_HitObject = NULL;
+ foundValidResult = true;
+ }
+ }
+ } else {
+ foundValidResult = true;
+ thePickResult.m_WasPickConsumed = true;
+ }
+ }
+ return thePickResult;
+ }
+
+ Qt3DSRenderPickResult Qt3DSRendererImpl::Pick(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inMouseCoords, bool inPickSiblings,
+ bool inPickEverything, const SRenderInstanceId id)
+ {
+ m_LastPickResults.clear();
+
+ SLayer *theLayer = &inLayer;
+ // Stepping through how the original runtime did picking it picked layers in order
+ // stopping at the first hit. So objects on the top layer had first crack at the pick
+ // vector itself.
+ do {
+ if (theLayer->m_Flags.IsActive()) {
+ TInstanceRenderMap::iterator theIter
+ = m_InstanceRenderMap.find(combineLayerAndId(theLayer, id));
+ if (theIter != m_InstanceRenderMap.end()) {
+ m_LastPickResults.clear();
+ GetLayerHitObjectList(*theIter->second, inViewportDimensions, inMouseCoords,
+ inPickEverything, m_LastPickResults,
+ GetPerFrameAllocator());
+ SPickResultProcessResult retval(ProcessPickResultList(inPickEverything));
+ if (retval.m_WasPickConsumed)
+ return retval;
+ } else {
+ // QT3DS_ASSERT( false );
+ }
+ }
+
+ if (inPickSiblings)
+ theLayer = GetNextLayer(*theLayer);
+ else
+ theLayer = NULL;
+ } while (theLayer != NULL);
+
+ return Qt3DSRenderPickResult();
+ }
+
+ static inline Option<QT3DSVec2> IntersectRayWithNode(const SNode &inNode,
+ SRenderableObject &inRenderableObject,
+ const SRay &inPickRay)
+ {
+ if (inRenderableObject.m_RenderableFlags.IsText()) {
+ STextRenderable &theRenderable = static_cast<STextRenderable &>(inRenderableObject);
+ if (&theRenderable.m_Text == &inNode) {
+ return inPickRay.GetRelativeXY(inRenderableObject.m_GlobalTransform,
+ inRenderableObject.m_Bounds);
+ }
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ } else if (inRenderableObject.m_RenderableFlags.isDistanceField()) {
+ SDistanceFieldRenderable &theRenderable = static_cast<SDistanceFieldRenderable &>(
+ inRenderableObject);
+ if (&theRenderable.m_text == &inNode) {
+ return inPickRay.GetRelativeXY(inRenderableObject.m_GlobalTransform,
+ inRenderableObject.m_Bounds);
+ }
+#endif
+ } else if (inRenderableObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) {
+ SSubsetRenderable &theRenderable = static_cast<SSubsetRenderable &>(inRenderableObject);
+ if (&theRenderable.m_ModelContext.m_Model == &inNode)
+ return inPickRay.GetRelativeXY(inRenderableObject.m_GlobalTransform,
+ inRenderableObject.m_Bounds);
+ } else if (inRenderableObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ SCustomMaterialRenderable &theRenderable =
+ static_cast<SCustomMaterialRenderable &>(inRenderableObject);
+ if (&theRenderable.m_ModelContext.m_Model == &inNode)
+ return inPickRay.GetRelativeXY(inRenderableObject.m_GlobalTransform,
+ inRenderableObject.m_Bounds);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ return Empty();
+ }
+
+ static inline Qt3DSRenderPickSubResult ConstructSubResult(SImage &inImage)
+ {
+ STextureDetails theDetails = inImage.m_TextureData.m_Texture->GetTextureDetails();
+ return Qt3DSRenderPickSubResult(*inImage.m_LastFrameOffscreenRenderer,
+ inImage.m_TextureTransform, inImage.m_HorizontalTilingMode,
+ inImage.m_VerticalTilingMode, theDetails.m_Width,
+ theDetails.m_Height);
+ }
+
+ Option<QT3DSVec2> Qt3DSRendererImpl::FacePosition(SNode &inNode, NVBounds3 inBounds,
+ const QT3DSMat44 &inGlobalTransform,
+ const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inMouseCoords,
+ NVDataRef<SGraphObject *> inMapperObjects,
+ SBasisPlanes::Enum inPlane)
+ {
+ SLayerRenderData *theLayerData = GetOrCreateLayerRenderDataForNode(inNode);
+ if (theLayerData == NULL)
+ return Empty();
+ // This function assumes the layer was rendered to the scene itself. There is another
+ // function
+ // for completely offscreen layers that don't get rendered to the scene.
+ bool wasRenderToTarget(theLayerData->m_Layer.m_Flags.IsLayerRenderToTarget());
+ if (wasRenderToTarget == false || theLayerData->m_Camera == NULL
+ || theLayerData->m_LayerPrepResult.hasValue() == false
+ || theLayerData->m_LastFrameOffscreenRenderer.mPtr != NULL)
+ return Empty();
+
+ QT3DSVec2 theMouseCoords(inMouseCoords);
+ QT3DSVec2 theViewportDimensions(inViewportDimensions);
+
+ for (QT3DSU32 idx = 0, end = inMapperObjects.size(); idx < end; ++idx) {
+ SGraphObject &currentObject = *inMapperObjects[idx];
+ if (currentObject.m_Type == GraphObjectTypes::Layer) {
+ // The layer knows its viewport so it can take the information directly.
+ // This is extremely counter intuitive but a good sign.
+ } else if (currentObject.m_Type == GraphObjectTypes::Image) {
+ SImage &theImage = static_cast<SImage &>(currentObject);
+ SModel *theParentModel = NULL;
+ if (theImage.m_Parent
+ && theImage.m_Parent->m_Type == GraphObjectTypes::DefaultMaterial) {
+ SDefaultMaterial *theMaterial =
+ static_cast<SDefaultMaterial *>(theImage.m_Parent);
+ if (theMaterial) {
+ theParentModel = theMaterial->m_Parent;
+ }
+ }
+ if (theParentModel == NULL) {
+ QT3DS_ASSERT(false);
+ return Empty();
+ }
+ NVBounds3 theModelBounds = theParentModel->GetBounds(
+ GetQt3DSContext().GetBufferManager(), GetQt3DSContext().GetPathManager(), false);
+
+ if (theModelBounds.isEmpty()) {
+ QT3DS_ASSERT(false);
+ return Empty();
+ }
+ Option<QT3DSVec2> relativeHit =
+ FacePosition(*theParentModel, theModelBounds, theParentModel->m_GlobalTransform,
+ theViewportDimensions, theMouseCoords, NVDataRef<SGraphObject *>(),
+ SBasisPlanes::XY);
+ if (relativeHit.isEmpty()) {
+ return Empty();
+ }
+ Qt3DSRenderPickSubResult theResult = ConstructSubResult(theImage);
+ QT3DSVec2 hitInUVSpace = (*relativeHit) + QT3DSVec2(.5f, .5f);
+ eastl::pair<QT3DSVec2, QT3DSVec2> mouseAndViewport =
+ GetMouseCoordsAndViewportFromSubObject(hitInUVSpace, theResult);
+ theMouseCoords = mouseAndViewport.first;
+ theViewportDimensions = mouseAndViewport.second;
+ }
+ }
+
+ Option<SRay> theHitRay = theLayerData->m_LayerPrepResult->GetPickRay(
+ theMouseCoords, theViewportDimensions, false);
+ if (theHitRay.hasValue() == false)
+ return Empty();
+
+ // Scale the mouse coords to change them into the camera's numerical space.
+ SRay thePickRay = *theHitRay;
+ Option<QT3DSVec2> newValue = thePickRay.GetRelative(inGlobalTransform, inBounds, inPlane);
+ return newValue;
+ }
+
+ Qt3DSRenderPickResult
+ Qt3DSRendererImpl::PickOffscreenLayer(SLayer &/*inLayer*/, const QT3DSVec2 & /*inViewportDimensions*/
+ ,
+ const QT3DSVec2 & /*inMouseCoords*/
+ ,
+ bool /*inPickEverything*/)
+ {
+ return Qt3DSRenderPickResult();
+ }
+
+ QT3DSVec3 Qt3DSRendererImpl::UnprojectToPosition(SNode &inNode, QT3DSVec3 &inPosition,
+ const QT3DSVec2 &inMouseVec) const
+ {
+ // Translate mouse into layer's coordinates
+ SLayerRenderData *theData =
+ const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ return QT3DSVec3(0, 0, 0);
+ } // QT3DS_ASSERT( false ); return QT3DSVec3(0,0,0); }
+
+ QSize theWindow = m_qt3dsContext.GetWindowDimensions();
+ QT3DSVec2 theDims((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height());
+
+ SLayerRenderPreparationResult &thePrepResult(*theData->m_LayerPrepResult);
+ SRay theRay = thePrepResult.GetPickRay(inMouseVec, theDims, true);
+
+ return theData->m_Camera->UnprojectToPosition(inPosition, theRay);
+ }
+
+ QT3DSVec3 Qt3DSRendererImpl::UnprojectWithDepth(SNode &inNode, QT3DSVec3 &,
+ const QT3DSVec3 &inMouseVec) const
+ {
+ // Translate mouse into layer's coordinates
+ SLayerRenderData *theData =
+ const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ return QT3DSVec3(0, 0, 0);
+ } // QT3DS_ASSERT( false ); return QT3DSVec3(0,0,0); }
+
+ // Flip the y into gl coordinates from window coordinates.
+ QT3DSVec2 theMouse(inMouseVec.x, inMouseVec.y);
+ NVReal theDepth = inMouseVec.z;
+
+ SLayerRenderPreparationResult &thePrepResult(*theData->m_LayerPrepResult);
+ QSize theWindow = m_qt3dsContext.GetWindowDimensions();
+ SRay theRay = thePrepResult.GetPickRay(
+ theMouse, QT3DSVec2((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height()), true);
+ QT3DSVec3 theTargetPosition = theRay.m_Origin + theRay.m_Direction * theDepth;
+ if (inNode.m_Parent != NULL && inNode.m_Parent->m_Type != GraphObjectTypes::Layer)
+ theTargetPosition =
+ inNode.m_Parent->m_GlobalTransform.getInverse().transform(theTargetPosition);
+ // Our default global space is right handed, so if you are left handed z means something
+ // opposite.
+ if (inNode.m_Flags.IsLeftHanded())
+ theTargetPosition.z *= -1;
+ return theTargetPosition;
+ }
+
+ QT3DSVec3 Qt3DSRendererImpl::ProjectPosition(SNode &inNode, const QT3DSVec3 &inPosition) const
+ {
+ // Translate mouse into layer's coordinates
+ SLayerRenderData *theData =
+ const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inNode);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ return QT3DSVec3(0, 0, 0);
+ }
+
+ QT3DSMat44 viewProj;
+ theData->m_Camera->CalculateViewProjectionMatrix(viewProj);
+ QT3DSVec4 projPos = viewProj.transform(QT3DSVec4(inPosition, 1.0f));
+ projPos.x /= projPos.w;
+ projPos.y /= projPos.w;
+
+ NVRenderRectF theViewport = theData->m_LayerPrepResult->GetLayerToPresentationViewport();
+ QT3DSVec2 theDims((QT3DSF32)theViewport.m_Width, (QT3DSF32)theViewport.m_Height);
+ projPos.x += 1.0;
+ projPos.y += 1.0;
+ projPos.x *= 0.5;
+ projPos.y *= 0.5;
+ QT3DSVec3 cameraToObject = theData->m_Camera->GetGlobalPos() - inPosition;
+ projPos.z = sqrtf(cameraToObject.dot(cameraToObject));
+ QT3DSVec3 mouseVec = QT3DSVec3(projPos.x, projPos.y, projPos.z);
+ mouseVec.x *= theDims.x;
+ mouseVec.y *= theDims.y;
+
+ mouseVec.x += theViewport.m_X;
+ mouseVec.y += theViewport.m_Y;
+
+ // Flip the y into window coordinates so it matches the mouse.
+ QSize theWindow = m_qt3dsContext.GetWindowDimensions();
+ mouseVec.y = theWindow.height() - mouseVec.y;
+
+ return mouseVec;
+ }
+
+ Option<SLayerPickSetup> Qt3DSRendererImpl::GetLayerPickSetup(SLayer &inLayer,
+ const QT3DSVec2 &inMouseCoords,
+ const QSize &inPickDims)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ QT3DS_ASSERT(false);
+ return Empty();
+ }
+ QSize theWindow = m_qt3dsContext.GetWindowDimensions();
+ QT3DSVec2 theDims((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height());
+ // The mouse is relative to the layer
+ Option<QT3DSVec2> theLocalMouse = GetLayerMouseCoords(*theData, inMouseCoords, theDims, false);
+ if (theLocalMouse.hasValue() == false) {
+ return Empty();
+ }
+
+ SLayerRenderPreparationResult &thePrepResult(*theData->m_LayerPrepResult);
+ if (thePrepResult.GetCamera() == NULL) {
+ return Empty();
+ }
+ // Perform gluPickMatrix and pre-multiply it into the view projection
+ QT3DSMat44 theTransScale(QT3DSMat44::createIdentity());
+ SCamera &theCamera(*thePrepResult.GetCamera());
+
+ NVRenderRectF layerToPresentation = thePrepResult.GetLayerToPresentationViewport();
+ // Offsetting is already taken care of in the camera's projection.
+ // All we need to do is to scale and translate the image.
+ layerToPresentation.m_X = 0;
+ layerToPresentation.m_Y = 0;
+ QT3DSVec2 theMouse(*theLocalMouse);
+ // The viewport will need to center at this location
+ QT3DSVec2 viewportDims((QT3DSF32)inPickDims.width(), (QT3DSF32)inPickDims.height());
+ QT3DSVec2 bottomLeft =
+ QT3DSVec2(theMouse.x - viewportDims.x / 2.0f, theMouse.y - viewportDims.y / 2.0f);
+ // For some reason, and I haven't figured out why yet, the offsets need to be backwards for
+ // this to work.
+ // bottomLeft.x = layerToPresentation.m_Width - bottomLeft.x;
+ // bottomLeft.y = layerToPresentation.m_Height - bottomLeft.y;
+ // Virtual rect is relative to the layer.
+ NVRenderRectF thePickRect(bottomLeft.x, bottomLeft.y, viewportDims.x, viewportDims.y);
+ QT3DSMat44 projectionPremult(QT3DSMat44::createIdentity());
+ projectionPremult = render::NVRenderContext::ApplyVirtualViewportToProjectionMatrix(
+ projectionPremult, layerToPresentation, thePickRect);
+ projectionPremult = projectionPremult.getInverse();
+
+ QT3DSMat44 globalInverse = theCamera.m_GlobalTransform.getInverse();
+ QT3DSMat44 theVP = theCamera.m_Projection * globalInverse;
+ // For now we won't setup the scissor, so we may be off by inPickDims at most because
+ // GetLayerMouseCoords will return
+ // false if the mouse is too far off the layer.
+ return SLayerPickSetup(projectionPremult, theVP,
+ NVRenderRect(0, 0, (QT3DSU32)layerToPresentation.m_Width,
+ (QT3DSU32)layerToPresentation.m_Height));
+ }
+
+ Option<NVRenderRectF> Qt3DSRendererImpl::GetLayerRect(SLayer &inLayer)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ QT3DS_ASSERT(false);
+ return Empty();
+ }
+ SLayerRenderPreparationResult &thePrepResult(*theData->m_LayerPrepResult);
+ return thePrepResult.GetLayerToPresentationViewport();
+ }
+
+ // This doesn't have to be cheap.
+ void Qt3DSRendererImpl::RunLayerRender(SLayer &inLayer, const QT3DSMat44 &inViewProjection)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ theData->PrepareAndRender(inViewProjection);
+ }
+
+ void Qt3DSRendererImpl::AddRenderWidget(IRenderWidget &inWidget)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inWidget.GetNode());
+ if (theData)
+ theData->AddRenderWidget(inWidget);
+ }
+
+ void Qt3DSRendererImpl::RenderLayerRect(SLayer &inLayer, const QT3DSVec3 &inColor)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer);
+ if (theData)
+ theData->m_BoundingRectColor = inColor;
+ }
+
+ SScaleAndPosition Qt3DSRendererImpl::GetWorldToPixelScaleFactor(const SCamera &inCamera,
+ const QT3DSVec3 &inWorldPoint,
+ SLayerRenderData &inRenderData)
+ {
+ if (inCamera.m_Flags.IsOrthographic() == true) {
+ // There are situations where the camera can scale.
+ return SScaleAndPosition(
+ inWorldPoint,
+ inCamera.GetOrthographicScaleFactor(
+ inRenderData.m_LayerPrepResult->GetLayerToPresentationViewport(),
+ inRenderData.m_LayerPrepResult->GetPresentationDesignDimensions()));
+ } else {
+ QT3DSVec3 theCameraPos(0, 0, 0);
+ QT3DSVec3 theCameraDir(0, 0, -1);
+ SRay theRay(theCameraPos, inWorldPoint - theCameraPos);
+ NVPlane thePlane(theCameraDir, -600);
+ QT3DSVec3 theItemPosition(inWorldPoint);
+ Option<QT3DSVec3> theIntersection = theRay.Intersect(thePlane);
+ if (theIntersection.hasValue())
+ theItemPosition = *theIntersection;
+ // The special number comes in from physically measuring how off we are on the screen.
+ QT3DSF32 theScaleFactor = (1.0f / inCamera.m_Projection.column1[1]);
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inCamera);
+ QT3DSU32 theHeight = theData->m_LayerPrepResult->GetTextureDimensions().height();
+ QT3DSF32 theScaleMultiplier = 600.0f / ((QT3DSF32)theHeight / 2.0f);
+ theScaleFactor *= theScaleMultiplier;
+
+ return SScaleAndPosition(theItemPosition, theScaleFactor);
+ }
+ }
+
+ SScaleAndPosition Qt3DSRendererImpl::GetWorldToPixelScaleFactor(SLayer &inLayer,
+ const QT3DSVec3 &inWorldPoint)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inLayer);
+ if (theData == NULL || theData->m_Camera == NULL) {
+ QT3DS_ASSERT(false);
+ return SScaleAndPosition();
+ }
+ return GetWorldToPixelScaleFactor(*theData->m_Camera, inWorldPoint, *theData);
+ }
+
+ void Qt3DSRendererImpl::ReleaseLayerRenderResources(SLayer &inLayer, const SRenderInstanceId id)
+ {
+ TInstanceRenderMap::iterator theIter
+ = m_InstanceRenderMap.find(combineLayerAndId(&inLayer, id));
+ if (theIter != m_InstanceRenderMap.end()) {
+ TLayerRenderList::iterator theLastFrm = eastl::find(
+ m_LastFrameLayers.begin(), m_LastFrameLayers.end(), theIter->second.mPtr);
+ if (theLastFrm != m_LastFrameLayers.end()) {
+ theIter->second->ResetForFrame();
+ m_LastFrameLayers.erase(theLastFrm);
+ }
+ m_InstanceRenderMap.erase(theIter);
+ }
+ }
+
+ void Qt3DSRendererImpl::RenderQuad(const QT3DSVec2 inDimensions, const QT3DSMat44 &inMVP,
+ NVRenderTexture2D &inQuadTexture)
+ {
+ m_Context->SetCullingEnabled(false);
+ SLayerSceneShader *theShader = GetSceneLayerShader();
+ NVRenderContext &theContext(*m_Context);
+ theContext.SetActiveShader(&theShader->m_Shader);
+ theShader->m_MVP.Set(inMVP);
+ theShader->m_Dimensions.Set(inDimensions);
+ theShader->m_Sampler.Set(&inQuadTexture);
+
+ GenerateXYQuad();
+ theContext.SetInputAssembler(m_QuadInputAssembler);
+ theContext.Draw(NVRenderDrawMode::Triangles, m_QuadIndexBuffer->GetNumIndices(), 0);
+ }
+
+ void Qt3DSRendererImpl::RenderQuad()
+ {
+ m_Context->SetCullingEnabled(false);
+ GenerateXYQuad();
+ m_Context->SetInputAssembler(m_QuadInputAssembler);
+ m_Context->Draw(NVRenderDrawMode::Triangles, m_QuadIndexBuffer->GetNumIndices(), 0);
+ }
+
+ void Qt3DSRendererImpl::RenderPointsIndirect()
+ {
+ m_Context->SetCullingEnabled(false);
+ GenerateXYZPoint();
+ m_Context->SetInputAssembler(m_PointInputAssembler);
+ m_Context->DrawIndirect(NVRenderDrawMode::Points, 0);
+ }
+
+ void Qt3DSRendererImpl::LayerNeedsFrameClear(SLayerRenderData &inLayer)
+ {
+ m_LastFrameLayers.push_back(&inLayer);
+ }
+
+ void Qt3DSRendererImpl::BeginLayerDepthPassRender(SLayerRenderData &inLayer)
+ {
+ m_CurrentLayer = &inLayer;
+ }
+
+ void Qt3DSRendererImpl::EndLayerDepthPassRender() { m_CurrentLayer = NULL; }
+
+ void Qt3DSRendererImpl::BeginLayerRender(SLayerRenderData &inLayer)
+ {
+ m_CurrentLayer = &inLayer;
+ // Remove all of the shaders from the layer shader set
+ // so that we can only apply the camera and lighting properties to
+ // shaders that are in the layer.
+ m_LayerShaders.clear();
+ }
+ void Qt3DSRendererImpl::EndLayerRender() { m_CurrentLayer = NULL; }
+
+// Allocate an object that lasts only this frame.
+#define RENDER_FRAME_NEW(type) \
+ new (m_PerFrameAllocator.m_FastAllocator.allocate(sizeof(type), __FILE__, __LINE__)) type
+
+ void Qt3DSRendererImpl::PrepareImageForIbl(SImage &inImage)
+ {
+ if (inImage.m_TextureData.m_Texture && inImage.m_TextureData.m_Texture->GetNumMipmaps() < 1)
+ inImage.m_TextureData.m_Texture->GenerateMipmaps();
+ }
+
+ bool NodeContainsBoneRoot(SNode &childNode, QT3DSI32 rootID)
+ {
+ for (SNode *childChild = childNode.m_FirstChild; childChild != NULL;
+ childChild = childChild->m_NextSibling) {
+ if (childChild->m_SkeletonId == rootID)
+ return true;
+ }
+
+ return false;
+ }
+
+ void FillBoneIdNodeMap(SNode &childNode, nvhash_map<long, SNode *> &ioMap)
+ {
+ if (childNode.m_SkeletonId >= 0)
+ ioMap[childNode.m_SkeletonId] = &childNode;
+ for (SNode *childChild = childNode.m_FirstChild; childChild != NULL;
+ childChild = childChild->m_NextSibling)
+ FillBoneIdNodeMap(*childChild, ioMap);
+ }
+
+ bool Qt3DSRendererImpl::PrepareTextureAtlasForRender()
+ {
+ ITextTextureAtlas *theTextureAtlas = m_qt3dsContext.GetTextureAtlas();
+ if (theTextureAtlas == NULL)
+ return false;
+
+ // this is a one time creation
+ if (!theTextureAtlas->IsInitialized()) {
+ NVRenderContext &theContext(*m_Context);
+ NVScopedRefCounted<NVRenderVertexBuffer> mVertexBuffer;
+ NVScopedRefCounted<NVRenderInputAssembler> mInputAssembler;
+ NVScopedRefCounted<NVRenderAttribLayout> mAttribLayout;
+ // temporay FB
+ using qt3ds::render::NVRenderContextScopedProperty;
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __fbo(
+ *m_Context, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+
+ ITextRenderer &theTextRenderer(*m_qt3dsContext.GetOnscreenTextRenderer());
+ TTextTextureAtlasDetailsAndTexture theResult = theTextureAtlas->PrepareTextureAtlas();
+ if (!theResult.first.m_EntryCount) {
+ QT3DS_ASSERT(theResult.first.m_EntryCount);
+ return false;
+ }
+
+ // generate the index buffer we need
+ GenerateXYQuad();
+
+ qt3ds::render::NVRenderVertexBufferEntry theEntries[] = {
+ qt3ds::render::NVRenderVertexBufferEntry("attr_pos",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3),
+ qt3ds::render::NVRenderVertexBufferEntry(
+ "attr_uv", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 12),
+ };
+
+ // create our attribute layout
+ mAttribLayout = m_Context->CreateAttributeLayout(toConstDataRef(theEntries, 2));
+
+ NVRenderFrameBuffer *theAtlasFB(
+ m_qt3dsContext.GetResourceManager().AllocateFrameBuffer());
+ theAtlasFB->Attach(NVRenderFrameBufferAttachments::Color0, *theResult.second);
+ m_qt3dsContext.GetRenderContext().SetRenderTarget(theAtlasFB);
+
+ // this texture contains our single entries
+ NVRenderTexture2D *theTexture = nullptr;
+ if (m_Context->GetRenderContextType() == NVRenderContextValues::GLES2) {
+ theTexture = m_qt3dsContext.GetResourceManager()
+ .AllocateTexture2D(32, 32, NVRenderTextureFormats::RGBA8);
+ } else {
+ theTexture = m_qt3dsContext.GetResourceManager()
+ .AllocateTexture2D(32, 32, NVRenderTextureFormats::Alpha8);
+ }
+ m_Context->SetClearColor(QT3DSVec4(0, 0, 0, 0));
+ m_Context->Clear(NVRenderClearValues::Color);
+ m_Context->SetDepthTestEnabled(false);
+ m_Context->SetScissorTestEnabled(false);
+ m_Context->SetCullingEnabled(false);
+ m_Context->SetBlendingEnabled(false);
+ m_Context->SetViewport(
+ NVRenderRect(0, 0, theResult.first.m_TextWidth, theResult.first.m_TextHeight));
+
+ SCamera theCamera;
+ theCamera.m_ClipNear = -1.0;
+ theCamera.m_ClipFar = 1.0;
+ theCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ theCamera.m_Flags.SetOrthographic(true);
+ QT3DSVec2 theTextureDims((QT3DSF32)theResult.first.m_TextWidth,
+ (QT3DSF32)theResult.first.m_TextHeight);
+ theCamera.CalculateGlobalVariables(
+ NVRenderRect(0, 0, theResult.first.m_TextWidth, theResult.first.m_TextHeight),
+ theTextureDims);
+ // We want a 2D lower left projection
+ QT3DSF32 *writePtr(theCamera.m_Projection.front());
+ writePtr[12] = -1;
+ writePtr[13] = -1;
+
+ // generate render stuff
+ // We dynamicall update the vertex buffer
+ QT3DSF32 tempBuf[20];
+ QT3DSF32 *bufPtr = tempBuf;
+ QT3DSU32 bufSize = 20 * sizeof(QT3DSF32); // 4 vertices 3 pos 2 tex
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)bufPtr, bufSize);
+ mVertexBuffer = theContext.CreateVertexBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Dynamic, 20 * sizeof(QT3DSF32),
+ 3 * sizeof(QT3DSF32) + 2 * sizeof(QT3DSF32), vertData);
+ QT3DSU32 strides = mVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ mInputAssembler = theContext.CreateInputAssembler(
+ mAttribLayout, toConstDataRef(&mVertexBuffer.mPtr, 1), m_QuadIndexBuffer.mPtr,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+
+ NVRenderShaderProgram *theShader = GetTextAtlasEntryShader();
+ STextShader theTextShader(*theShader);
+
+ if (theShader) {
+ theContext.SetActiveShader(theShader);
+ theTextShader.m_MVP.Set(theCamera.m_Projection);
+
+ // we are going through all entries and render to the FBO
+ for (QT3DSU32 i = 0; i < theResult.first.m_EntryCount; i++) {
+ STextTextureAtlasEntryDetails theDetails =
+ theTextRenderer.RenderAtlasEntry(i, *theTexture);
+ // update vbo
+ // we need to mirror coordinates
+ QT3DSF32 x1 = (QT3DSF32)theDetails.m_X;
+ QT3DSF32 x2 = (QT3DSF32)theDetails.m_X + theDetails.m_TextWidth;
+ QT3DSF32 y1 = (QT3DSF32)theDetails.m_Y;
+ QT3DSF32 y2 = (QT3DSF32)theDetails.m_Y + theDetails.m_TextHeight;
+
+ QT3DSF32 box[4][5] = {
+ { x1, y1, 0, 0, 1 },
+ { x1, y2, 0, 0, 0 },
+ { x2, y2, 0, 1, 0 },
+ { x2, y1, 0, 1, 1 },
+ };
+
+ NVDataRef<QT3DSU8> vertData((QT3DSU8 *)box, bufSize);
+ mVertexBuffer->UpdateBuffer(vertData, false);
+
+ theTextShader.m_Sampler.Set(theTexture);
+
+ theContext.SetInputAssembler(mInputAssembler);
+ theContext.Draw(NVRenderDrawMode::Triangles, m_QuadIndexBuffer->GetNumIndices(),
+ 0);
+ }
+ }
+
+ m_qt3dsContext.GetResourceManager().Release(*theTexture);
+ m_qt3dsContext.GetResourceManager().Release(*theAtlasFB);
+
+ return true;
+ }
+
+ return theTextureAtlas->IsInitialized();
+ }
+
+ Option<QT3DSVec2> Qt3DSRendererImpl::GetLayerMouseCoords(SLayerRenderData &inLayerRenderData,
+ const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inViewportDimensions,
+ bool forceImageIntersect) const
+ {
+ if (inLayerRenderData.m_LayerPrepResult.hasValue())
+ return inLayerRenderData.m_LayerPrepResult->GetLayerMouseCoords(
+ inMouseCoords, inViewportDimensions, forceImageIntersect);
+ return Empty();
+ }
+
+ void Qt3DSRendererImpl::GetLayerHitObjectList(SLayerRenderData &inLayerRenderData,
+ const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inPresCoords, bool inPickEverything,
+ TPickResultArray &outIntersectionResult,
+ NVAllocatorCallback &inTempAllocator)
+ {
+ // This function assumes the layer was rendered to the scene itself. There is another
+ // function
+ // for completely offscreen layers that don't get rendered to the scene.
+ bool wasRenderToTarget(inLayerRenderData.m_Layer.m_Flags.IsLayerRenderToTarget());
+ if (wasRenderToTarget && inLayerRenderData.m_Camera != NULL) {
+ Option<SRay> theHitRay;
+ if (inLayerRenderData.m_LayerPrepResult.hasValue()) {
+ theHitRay = inLayerRenderData.m_LayerPrepResult->GetPickRay(
+ inPresCoords, inViewportDimensions, false, m_Context->isSceneCameraView());
+ }
+ if (inLayerRenderData.m_LastFrameOffscreenRenderer.mPtr == NULL) {
+ if (theHitRay.hasValue()) {
+ // Scale the mouse coords to change them into the camera's numerical space.
+ SRay thePickRay = *theHitRay;
+ for (QT3DSU32 idx = inLayerRenderData.m_OpaqueObjects.size(), end = 0; idx > end;
+ --idx) {
+ SRenderableObject *theRenderableObject =
+ inLayerRenderData.m_OpaqueObjects[idx - 1];
+ if (inPickEverything
+ || theRenderableObject->m_RenderableFlags.GetPickable())
+ IntersectRayWithSubsetRenderable(thePickRay, *theRenderableObject,
+ outIntersectionResult,
+ inTempAllocator);
+ }
+ for (QT3DSU32 idx = inLayerRenderData.m_TransparentObjects.size(), end = 0;
+ idx > end; --idx) {
+ SRenderableObject *theRenderableObject =
+ inLayerRenderData.m_TransparentObjects[idx - 1];
+ if (inPickEverything
+ || theRenderableObject->m_RenderableFlags.GetPickable())
+ IntersectRayWithSubsetRenderable(thePickRay, *theRenderableObject,
+ outIntersectionResult,
+ inTempAllocator);
+ }
+ }
+ } else {
+ IGraphObjectPickQuery *theQuery =
+ inLayerRenderData.m_LastFrameOffscreenRenderer->GetGraphObjectPickQuery(this);
+ if (theQuery) {
+ Qt3DSRenderPickResult theResult =
+ theQuery->Pick(inPresCoords, inViewportDimensions, inPickEverything);
+ if (theResult.m_HitObject) {
+ theResult.m_OffscreenRenderer =
+ inLayerRenderData.m_LastFrameOffscreenRenderer;
+ outIntersectionResult.push_back(theResult);
+ }
+ } else
+ inLayerRenderData.m_LastFrameOffscreenRenderer->Pick(inPresCoords,
+ inViewportDimensions,
+ this);
+ }
+ }
+ }
+
+ static inline Qt3DSRenderPickSubResult ConstructSubResult(SRenderableImage &inImage)
+ {
+ return ConstructSubResult(inImage.m_Image);
+ }
+
+ void Qt3DSRendererImpl::IntersectRayWithSubsetRenderable(
+ const SRay &inRay, SRenderableObject &inRenderableObject,
+ TPickResultArray &outIntersectionResultList, NVAllocatorCallback &inTempAllocator)
+ {
+ Option<SRayIntersectionResult> theIntersectionResultOpt(inRay.IntersectWithAABB(
+ inRenderableObject.m_GlobalTransform, inRenderableObject.m_Bounds));
+ if (theIntersectionResultOpt.hasValue() == false)
+ return;
+ SRayIntersectionResult &theResult(*theIntersectionResultOpt);
+
+ // Leave the coordinates relative for right now.
+ const SGraphObject *thePickObject = NULL;
+ if (inRenderableObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ thePickObject =
+ &static_cast<SSubsetRenderable *>(&inRenderableObject)->m_ModelContext.m_Model;
+ else if (inRenderableObject.m_RenderableFlags.IsText())
+ thePickObject = &static_cast<STextRenderable *>(&inRenderableObject)->m_Text;
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ else if (inRenderableObject.m_RenderableFlags.isDistanceField())
+ thePickObject = &static_cast<SDistanceFieldRenderable *>(&inRenderableObject)->m_text;
+#endif
+ else if (inRenderableObject.m_RenderableFlags.IsCustomMaterialMeshSubset())
+ thePickObject = &static_cast<SCustomMaterialRenderable *>(&inRenderableObject)
+ ->m_ModelContext.m_Model;
+ else if (inRenderableObject.m_RenderableFlags.IsPath())
+ thePickObject = &static_cast<SPathRenderable *>(&inRenderableObject)->m_Path;
+
+ if (thePickObject != NULL) {
+ outIntersectionResultList.push_back(Qt3DSRenderPickResult(
+ *thePickObject, theResult.m_RayLengthSquared, theResult.m_RelXY));
+
+ // For subsets, we know we can find images on them which may have been the result
+ // of rendering a sub-presentation.
+ if (inRenderableObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) {
+ Qt3DSRenderPickSubResult *theLastResult = NULL;
+ for (SRenderableImage *theImage =
+ static_cast<SSubsetRenderable *>(&inRenderableObject)->m_FirstImage;
+ theImage != NULL; theImage = theImage->m_NextImage) {
+ if (theImage->m_Image.m_LastFrameOffscreenRenderer != NULL
+ && theImage->m_Image.m_TextureData.m_Texture != NULL) {
+ Qt3DSRenderPickSubResult *theSubResult =
+ (Qt3DSRenderPickSubResult *)inTempAllocator.allocate(
+ sizeof(Qt3DSRenderPickSubResult), "Qt3DSRenderPickSubResult",
+ __FILE__, __LINE__);
+
+ new (theSubResult) Qt3DSRenderPickSubResult(ConstructSubResult(*theImage));
+ if (theLastResult == NULL)
+ outIntersectionResultList.back().m_FirstSubObject = theSubResult;
+ else
+ theLastResult->m_NextSibling = theSubResult;
+ theLastResult = theSubResult;
+ }
+ }
+ }
+ }
+ }
+
+#ifndef EA_PLATFORM_WINDOWS
+#define _snprintf snprintf
+#endif
+
+ NVRenderShaderProgram *Qt3DSRendererImpl::CompileShader(CRegisteredString inName,
+ const char8_t *inVert,
+ const char8_t *inFrag)
+ {
+ GetProgramGenerator().BeginProgram();
+ GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex)->Append(inVert);
+ GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment)->Append(inFrag);
+ return GetProgramGenerator().CompileGeneratedShader(inName);
+ }
+
+ const QT3DSF32 MINATTENUATION = 0;
+ const QT3DSF32 MAXATTENUATION = 1000;
+
+ QT3DSF32 ClampFloat(QT3DSF32 value, QT3DSF32 min, QT3DSF32 max)
+ {
+ return value < min ? min : ((value > max) ? max : value);
+ }
+
+ QT3DSF32 TranslateConstantAttenuation(QT3DSF32 attenuation) { return attenuation * .01f; }
+
+ QT3DSF32 TranslateLinearAttenuation(QT3DSF32 attenuation)
+ {
+ attenuation = ClampFloat(attenuation, MINATTENUATION, MAXATTENUATION);
+ return attenuation * 0.0001f;
+ }
+
+ QT3DSF32 TranslateQuadraticAttenuation(QT3DSF32 attenuation)
+ {
+ attenuation = ClampFloat(attenuation, MINATTENUATION, MAXATTENUATION);
+ return attenuation * 0.0000001f;
+ }
+
+ SShaderGeneratorGeneratedShader *Qt3DSRendererImpl::GetShader(SSubsetRenderable &inRenderable,
+ TShaderFeatureSet inFeatureSet)
+ {
+ if (m_CurrentLayer == NULL) {
+ QT3DS_ASSERT(false);
+ return NULL;
+ }
+ TShaderMap::iterator theFind = m_Shaders.find(inRenderable.m_ShaderDescription);
+ SShaderGeneratorGeneratedShader *retval = NULL;
+ if (theFind == m_Shaders.end()) {
+ // Generate the shader.
+ NVRenderShaderProgram *theShader(GenerateShader(inRenderable, inFeatureSet));
+ if (theShader) {
+ SShaderGeneratorGeneratedShader *theGeneratedShader =
+ (SShaderGeneratorGeneratedShader *)m_Context->GetAllocator().allocate(
+ sizeof(SShaderGeneratorGeneratedShader), "SShaderGeneratorGeneratedShader",
+ __FILE__, __LINE__);
+ new (theGeneratedShader) SShaderGeneratorGeneratedShader(
+ m_StringTable->RegisterStr(m_GeneratedShaderString.c_str()), *theShader);
+ m_Shaders.insert(make_pair(inRenderable.m_ShaderDescription, theGeneratedShader));
+ retval = theGeneratedShader;
+ }
+ // We still insert something because we don't to attempt to generate the same bad shader
+ // twice.
+ else
+ m_Shaders.insert(make_pair(inRenderable.m_ShaderDescription,
+ (SShaderGeneratorGeneratedShader *)NULL));
+ } else
+ retval = theFind->second;
+
+ if (retval != NULL) {
+ if (!m_LayerShaders.contains(*retval)) {
+ m_LayerShaders.insert(*retval);
+ }
+ if (m_CurrentLayer && m_CurrentLayer->m_Camera) {
+ SCamera &theCamera(*m_CurrentLayer->m_Camera);
+ if (m_CurrentLayer->m_CameraDirection.hasValue() == false)
+ m_CurrentLayer->m_CameraDirection = theCamera.GetScalingCorrectDirection();
+ }
+ }
+ return retval;
+ }
+ static QT3DSVec3 g_fullScreenRectFace[] = {
+ QT3DSVec3(-1, -1, 0), QT3DSVec3(-1, 1, 0), QT3DSVec3(1, 1, 0), QT3DSVec3(1, -1, 0),
+ };
+
+ static QT3DSVec2 g_fullScreenRectUVs[] = { QT3DSVec2(0, 0), QT3DSVec2(0, 1), QT3DSVec2(1, 1),
+ QT3DSVec2(1, 0) };
+
+ void Qt3DSRendererImpl::GenerateXYQuad()
+ {
+ if (m_QuadInputAssembler)
+ return;
+
+ qt3ds::render::NVRenderVertexBufferEntry theEntries[] = {
+ qt3ds::render::NVRenderVertexBufferEntry("attr_pos",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3),
+ qt3ds::render::NVRenderVertexBufferEntry("attr_uv",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 12),
+ };
+
+ QT3DSF32 tempBuf[20];
+ QT3DSF32 *bufPtr = tempBuf;
+ QT3DSVec3 *facePtr(g_fullScreenRectFace);
+ QT3DSVec2 *uvPtr(g_fullScreenRectUVs);
+ for (int j = 0; j < 4; j++, ++facePtr, ++uvPtr, bufPtr += 5) {
+ bufPtr[0] = facePtr->x;
+ bufPtr[1] = facePtr->y;
+ bufPtr[2] = facePtr->z;
+ bufPtr[3] = uvPtr->x;
+ bufPtr[4] = uvPtr->y;
+ }
+ m_QuadVertexBuffer = m_Context->CreateVertexBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Static, 20 * sizeof(QT3DSF32),
+ 3 * sizeof(QT3DSF32) + 2 * sizeof(QT3DSF32), toU8DataRef(tempBuf, 20));
+
+ QT3DSU8 indexData[] = {
+ 0, 1, 2, 0, 2, 3,
+ };
+ m_QuadIndexBuffer = m_Context->CreateIndexBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Static, qt3ds::render::NVRenderComponentTypes::QT3DSU8,
+ sizeof(indexData), toU8DataRef(indexData, sizeof(indexData)));
+
+ // create our attribute layout
+ m_QuadAttribLayout = m_Context->CreateAttributeLayout(toConstDataRef(theEntries, 2));
+
+ // create input assembler object
+ QT3DSU32 strides = m_QuadVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ m_QuadInputAssembler = m_Context->CreateInputAssembler(
+ m_QuadAttribLayout, toConstDataRef(&m_QuadVertexBuffer.mPtr, 1), m_QuadIndexBuffer,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ }
+
+ void Qt3DSRendererImpl::GenerateXYZPoint()
+ {
+ if (m_PointInputAssembler)
+ return;
+
+ qt3ds::render::NVRenderVertexBufferEntry theEntries[] = {
+ qt3ds::render::NVRenderVertexBufferEntry("attr_pos",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3),
+ qt3ds::render::NVRenderVertexBufferEntry("attr_uv",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 12),
+ };
+
+ QT3DSF32 tempBuf[5];
+ tempBuf[0] = tempBuf[1] = tempBuf[2] = 0.0;
+ tempBuf[3] = tempBuf[4] = 0.0;
+
+ m_PointVertexBuffer = m_Context->CreateVertexBuffer(
+ qt3ds::render::NVRenderBufferUsageType::Static, 5 * sizeof(QT3DSF32),
+ 3 * sizeof(QT3DSF32) + 2 * sizeof(QT3DSF32), toU8DataRef(tempBuf, 5));
+
+ // create our attribute layout
+ m_PointAttribLayout = m_Context->CreateAttributeLayout(toConstDataRef(theEntries, 2));
+
+ // create input assembler object
+ QT3DSU32 strides = m_PointVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ m_PointInputAssembler = m_Context->CreateInputAssembler(
+ m_PointAttribLayout, toConstDataRef(&m_PointVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ }
+
+ eastl::pair<NVRenderVertexBuffer *, NVRenderIndexBuffer *> Qt3DSRendererImpl::GetXYQuad()
+ {
+ if (!m_QuadInputAssembler)
+ GenerateXYQuad();
+
+ return eastl::make_pair(m_QuadVertexBuffer.mPtr, m_QuadIndexBuffer.mPtr);
+ }
+
+ SLayerGlobalRenderProperties Qt3DSRendererImpl::GetLayerGlobalRenderProperties()
+ {
+ SLayerRenderData &theData = *m_CurrentLayer;
+ SLayer &theLayer = theData.m_Layer;
+ if (theData.m_CameraDirection.hasValue() == false)
+ theData.m_CameraDirection = theData.m_Camera->GetScalingCorrectDirection();
+
+ return SLayerGlobalRenderProperties(
+ theLayer, *theData.m_Camera, *theData.m_CameraDirection, theData.m_Lights,
+ theData.m_LightDirections, theData.m_ShadowMapManager.mPtr, theData.m_LayerDepthTexture,
+ theData.m_LayerSsaoTexture, theLayer.m_LightProbe, theLayer.m_LightProbe2,
+ theLayer.m_ProbeHorizon, theLayer.m_ProbeBright, theLayer.m_Probe2Window,
+ theLayer.m_Probe2Pos, theLayer.m_Probe2Fade, theLayer.m_ProbeFov);
+ }
+
+ void Qt3DSRendererImpl::GenerateXYQuadStrip()
+ {
+ if (m_QuadStripInputAssembler)
+ return;
+
+ qt3ds::render::NVRenderVertexBufferEntry theEntries[] = {
+ qt3ds::render::NVRenderVertexBufferEntry("attr_pos",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3),
+ qt3ds::render::NVRenderVertexBufferEntry("attr_uv",
+ qt3ds::render::NVRenderComponentTypes::QT3DSF32, 2, 12),
+ };
+
+ // this buffer is filled dynmically
+ m_QuadStripVertexBuffer =
+ m_Context->CreateVertexBuffer(qt3ds::render::NVRenderBufferUsageType::Dynamic, 0,
+ 3 * sizeof(QT3DSF32) + 2 * sizeof(QT3DSF32) // stride
+ ,
+ NVDataRef<QT3DSU8>());
+
+ // create our attribute layout
+ m_QuadStripAttribLayout = m_Context->CreateAttributeLayout(toConstDataRef(theEntries, 2));
+
+ // create input assembler object
+ QT3DSU32 strides = m_QuadStripVertexBuffer->GetStride();
+ QT3DSU32 offsets = 0;
+ m_QuadStripInputAssembler = m_Context->CreateInputAssembler(
+ m_QuadStripAttribLayout, toConstDataRef(&m_QuadStripVertexBuffer.mPtr, 1), NULL,
+ toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1));
+ }
+
+ void Qt3DSRendererImpl::UpdateCbAoShadow(const SLayer *pLayer, const SCamera *pCamera,
+ CResourceTexture2D &inDepthTexture)
+ {
+ if (m_Context->GetConstantBufferSupport()) {
+ CRegisteredString theName = m_Context->GetStringTable().RegisterStr("cbAoShadow");
+ NVRenderConstantBuffer *pCB = m_Context->GetConstantBuffer(theName);
+
+ if (!pCB) {
+ // the size is determined automatically later on
+ pCB = m_Context->CreateConstantBuffer(
+ theName, qt3ds::render::NVRenderBufferUsageType::Static, 0, NVDataRef<QT3DSU8>());
+ if (!pCB) {
+ QT3DS_ASSERT(false);
+ return;
+ }
+ m_ConstantBuffers.insert(eastl::make_pair(theName, pCB));
+
+ // Add paramters. Note should match the appearance in the shader program
+ pCB->AddParam(m_Context->GetStringTable().RegisterStr("ao_properties"),
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4, 1);
+ pCB->AddParam(m_Context->GetStringTable().RegisterStr("ao_properties2"),
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4, 1);
+ pCB->AddParam(m_Context->GetStringTable().RegisterStr("shadow_properties"),
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4, 1);
+ pCB->AddParam(m_Context->GetStringTable().RegisterStr("aoScreenConst"),
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4, 1);
+ pCB->AddParam(m_Context->GetStringTable().RegisterStr("UvToEyeConst"),
+ qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4, 1);
+ }
+
+ // update values
+ QT3DSVec4 aoProps(pLayer->m_AoStrength * 0.01f, pLayer->m_AoDistance * 0.4f,
+ pLayer->m_AoSoftness * 0.02f, pLayer->m_AoBias);
+ pCB->UpdateParam("ao_properties", NVDataRef<QT3DSU8>((QT3DSU8 *)&aoProps, 1));
+ QT3DSVec4 aoProps2((QT3DSF32)pLayer->m_AoSamplerate, (pLayer->m_AoDither) ? 1.0f : 0.0f, 0.0f,
+ 0.0f);
+ pCB->UpdateParam("ao_properties2", NVDataRef<QT3DSU8>((QT3DSU8 *)&aoProps2, 1));
+ QT3DSVec4 shadowProps(pLayer->m_ShadowStrength * 0.01f, pLayer->m_ShadowDist,
+ pLayer->m_ShadowSoftness * 0.01f, pLayer->m_ShadowBias);
+ pCB->UpdateParam("shadow_properties", NVDataRef<QT3DSU8>((QT3DSU8 *)&shadowProps, 1));
+
+ QT3DSF32 R2 = pLayer->m_AoDistance * pLayer->m_AoDistance * 0.16f;
+ QT3DSF32 rw = 100, rh = 100;
+
+ if (inDepthTexture && inDepthTexture.GetTexture()) {
+ rw = (QT3DSF32)inDepthTexture.GetTexture()->GetTextureDetails().m_Width;
+ rh = (QT3DSF32)inDepthTexture.GetTexture()->GetTextureDetails().m_Height;
+ }
+ QT3DSF32 fov = (pCamera) ? pCamera->verticalFov(rw / rh) : 1.0f;
+ QT3DSF32 tanHalfFovY = tanf(0.5f * fov * (rh / rw));
+ QT3DSF32 invFocalLenX = tanHalfFovY * (rw / rh);
+
+ QT3DSVec4 aoScreenConst(1.0f / R2, rh / (2.0f * tanHalfFovY), 1.0f / rw, 1.0f / rh);
+ pCB->UpdateParam("aoScreenConst", NVDataRef<QT3DSU8>((QT3DSU8 *)&aoScreenConst, 1));
+ QT3DSVec4 UvToEyeConst(2.0f * invFocalLenX, -2.0f * tanHalfFovY, -invFocalLenX,
+ tanHalfFovY);
+ pCB->UpdateParam("UvToEyeConst", NVDataRef<QT3DSU8>((QT3DSU8 *)&UvToEyeConst, 1));
+
+ // update buffer to hardware
+ pCB->Update();
+ }
+ }
+
+ // widget context implementation
+
+ NVRenderVertexBuffer &Qt3DSRendererImpl::GetOrCreateVertexBuffer(CRegisteredString &inStr,
+ QT3DSU32 stride,
+ NVConstDataRef<QT3DSU8> bufferData)
+ {
+ NVRenderVertexBuffer *retval = GetVertexBuffer(inStr);
+ if (retval) {
+ // we update the buffer
+ retval->UpdateBuffer(bufferData, false);
+ return *retval;
+ }
+ retval = m_Context->CreateVertexBuffer(qt3ds::render::NVRenderBufferUsageType::Dynamic,
+ bufferData.size(), stride, bufferData);
+ m_WidgetVertexBuffers.insert(eastl::make_pair(inStr, retval));
+ return *retval;
+ }
+ NVRenderIndexBuffer &
+ Qt3DSRendererImpl::GetOrCreateIndexBuffer(CRegisteredString &inStr,
+ qt3ds::render::NVRenderComponentTypes::Enum componentType,
+ size_t size, NVConstDataRef<QT3DSU8> bufferData)
+ {
+ NVRenderIndexBuffer *retval = GetIndexBuffer(inStr);
+ if (retval) {
+ // we update the buffer
+ retval->UpdateBuffer(bufferData, false);
+ return *retval;
+ }
+
+ retval = m_Context->CreateIndexBuffer(qt3ds::render::NVRenderBufferUsageType::Dynamic,
+ componentType, size, bufferData);
+ m_WidgetIndexBuffers.insert(eastl::make_pair(inStr, retval));
+ return *retval;
+ }
+
+ NVRenderAttribLayout &Qt3DSRendererImpl::CreateAttributeLayout(
+ NVConstDataRef<qt3ds::render::NVRenderVertexBufferEntry> attribs)
+ {
+ // create our attribute layout
+ NVRenderAttribLayout *theAttribLAyout = m_Context->CreateAttributeLayout(attribs);
+ return *theAttribLAyout;
+ }
+
+ NVRenderInputAssembler &Qt3DSRendererImpl::GetOrCreateInputAssembler(
+ CRegisteredString &inStr, NVRenderAttribLayout *attribLayout,
+ NVConstDataRef<NVRenderVertexBuffer *> buffers, const NVRenderIndexBuffer *indexBuffer,
+ NVConstDataRef<QT3DSU32> strides, NVConstDataRef<QT3DSU32> offsets)
+ {
+ NVRenderInputAssembler *retval = GetInputAssembler(inStr);
+ if (retval)
+ return *retval;
+
+ retval =
+ m_Context->CreateInputAssembler(attribLayout, buffers, indexBuffer, strides, offsets);
+ m_WidgetInputAssembler.insert(eastl::make_pair(inStr, retval));
+ return *retval;
+ }
+
+ NVRenderVertexBuffer *Qt3DSRendererImpl::GetVertexBuffer(CRegisteredString &inStr)
+ {
+ TStrVertBufMap::iterator theIter = m_WidgetVertexBuffers.find(inStr);
+ if (theIter != m_WidgetVertexBuffers.end())
+ return theIter->second;
+ return NULL;
+ }
+
+ NVRenderIndexBuffer *Qt3DSRendererImpl::GetIndexBuffer(CRegisteredString &inStr)
+ {
+ TStrIndexBufMap::iterator theIter = m_WidgetIndexBuffers.find(inStr);
+ if (theIter != m_WidgetIndexBuffers.end())
+ return theIter->second;
+ return NULL;
+ }
+
+ NVRenderInputAssembler *Qt3DSRendererImpl::GetInputAssembler(CRegisteredString &inStr)
+ {
+ TStrIAMap::iterator theIter = m_WidgetInputAssembler.find(inStr);
+ if (theIter != m_WidgetInputAssembler.end())
+ return theIter->second;
+ return NULL;
+ }
+
+ NVRenderShaderProgram *Qt3DSRendererImpl::GetShader(CRegisteredString inStr)
+ {
+ TStrShaderMap::iterator theIter = m_WidgetShaders.find(inStr);
+ if (theIter != m_WidgetShaders.end())
+ return theIter->second;
+ return NULL;
+ }
+
+ NVRenderShaderProgram *Qt3DSRendererImpl::CompileAndStoreShader(CRegisteredString inStr)
+ {
+ NVRenderShaderProgram *newProgram = GetProgramGenerator().CompileGeneratedShader(inStr);
+ if (newProgram)
+ m_WidgetShaders.insert(eastl::make_pair(inStr, newProgram));
+ return newProgram;
+ }
+
+ IShaderProgramGenerator &Qt3DSRendererImpl::GetProgramGenerator()
+ {
+ return m_qt3dsContext.GetShaderProgramGenerator();
+ }
+
+ STextDimensions Qt3DSRendererImpl::MeasureText(const STextRenderInfo &inText)
+ {
+ if (m_qt3dsContext.GetTextRenderer() != NULL)
+ return m_qt3dsContext.GetTextRenderer()->MeasureText(inText, 0);
+ return STextDimensions();
+ }
+
+ void Qt3DSRendererImpl::RenderText(const STextRenderInfo &inText, const QT3DSVec3 &inTextColor,
+ const QT3DSVec3 &inBackgroundColor, const QT3DSMat44 &inMVP)
+ {
+ if (m_qt3dsContext.GetTextRenderer() != NULL) {
+ ITextRenderer &theTextRenderer(*m_qt3dsContext.GetTextRenderer());
+ NVRenderTexture2D *theTexture = m_qt3dsContext.GetResourceManager().AllocateTexture2D(
+ 32, 32, NVRenderTextureFormats::RGBA8);
+ STextTextureDetails theTextTextureDetails =
+ theTextRenderer.RenderText(inText, *theTexture);
+ STextRenderHelper theTextHelper(GetTextWidgetShader());
+ if (theTextHelper.m_Shader != NULL) {
+ m_qt3dsContext.GetRenderContext().SetBlendingEnabled(false);
+ STextScaleAndOffset theScaleAndOffset(*theTexture, theTextTextureDetails, inText);
+ theTextHelper.m_Shader->Render(*theTexture, theScaleAndOffset,
+ QT3DSVec4(inTextColor, 1.0f), inMVP, QT3DSVec2(0, 0),
+ GetContext(), theTextHelper.m_QuadInputAssembler,
+ theTextHelper.m_QuadInputAssembler.GetIndexCount(),
+ theTextTextureDetails, inBackgroundColor);
+ }
+ m_qt3dsContext.GetResourceManager().Release(*theTexture);
+ }
+ }
+
+ void Qt3DSRendererImpl::RenderText2D(QT3DSF32 x, QT3DSF32 y,
+ qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor,
+ const char *text)
+ {
+ if (m_qt3dsContext.GetOnscreenTextRenderer() != NULL) {
+ GenerateXYQuadStrip();
+
+ if (PrepareTextureAtlasForRender()) {
+ TTextRenderAtlasDetailsAndTexture theRenderTextDetails;
+ ITextTextureAtlas *theTextureAtlas = m_qt3dsContext.GetTextureAtlas();
+ QSize theWindow = m_qt3dsContext.GetWindowDimensions();
+
+ const wchar_t *wText = m_StringTable->GetWideStr(text);
+ STextRenderInfo theInfo;
+ theInfo.m_Text = m_StringTable->RegisterStr(wText);
+ theInfo.m_FontSize = 20;
+ // text scale 2% of screen we don't scale Y though because it becomes unreadable
+ theInfo.m_ScaleX = (theWindow.width() / 100.0f) * 1.5f / (theInfo.m_FontSize);
+ theInfo.m_ScaleY = 1.0f;
+
+ theRenderTextDetails = theTextureAtlas->RenderText(theInfo);
+
+ if (theRenderTextDetails.first.m_Vertices.size()) {
+ STextRenderHelper theTextHelper(GetOnscreenTextShader());
+ if (theTextHelper.m_Shader != NULL) {
+ // setup 2D projection
+ SCamera theCamera;
+ theCamera.m_ClipNear = -1.0;
+ theCamera.m_ClipFar = 1.0;
+
+ theCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ theCamera.m_Flags.SetOrthographic(true);
+ QT3DSVec2 theWindowDim((QT3DSF32)theWindow.width(), (QT3DSF32)theWindow.height());
+ theCamera.CalculateGlobalVariables(
+ NVRenderRect(0, 0, theWindow.width(), theWindow.height()),
+ theWindowDim);
+ // We want a 2D lower left projection
+ QT3DSF32 *writePtr(theCamera.m_Projection.front());
+ writePtr[12] = -1;
+ writePtr[13] = -1;
+
+ // upload vertices
+ m_QuadStripVertexBuffer->UpdateBuffer(theRenderTextDetails.first.m_Vertices,
+ false);
+
+ theTextHelper.m_Shader->Render2D(
+ *theRenderTextDetails.second, QT3DSVec4(inColor, 1.0f),
+ theCamera.m_Projection, GetContext(),
+ theTextHelper.m_QuadInputAssembler,
+ theRenderTextDetails.first.m_VertexCount, QT3DSVec2(x, y));
+ }
+ // we release the memory here
+ QT3DS_FREE(m_Context->GetAllocator(),
+ theRenderTextDetails.first.m_Vertices.begin());
+ }
+ }
+ }
+ }
+
+ void Qt3DSRendererImpl::RenderGpuProfilerStats(QT3DSF32 x, QT3DSF32 y,
+ qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor)
+ {
+ if (!IsLayerGpuProfilingEnabled())
+ return;
+
+ char messageLine[1024];
+ TInstanceRenderMap::const_iterator theIter;
+
+ QT3DSF32 startY = y;
+
+ for (theIter = m_InstanceRenderMap.begin(); theIter != m_InstanceRenderMap.end(); theIter++) {
+ QT3DSF32 startX = x;
+ const SLayerRenderData *theLayerRenderData = theIter->second;
+ const SLayer *theLayer = &theLayerRenderData->m_Layer;
+
+ if (theLayer->m_Flags.IsActive() && theLayerRenderData->m_LayerProfilerGpu.mPtr) {
+ const IRenderProfiler::TStrIDVec &idList =
+ theLayerRenderData->m_LayerProfilerGpu->GetTimerIDs();
+ if (!idList.empty()) {
+ startY -= 22;
+ startX += 20;
+ RenderText2D(startX, startY, inColor, theLayer->m_Id);
+ IRenderProfiler::TStrIDVec::const_iterator theIdIter = idList.begin();
+ for (theIdIter = idList.begin(); theIdIter != idList.end(); theIdIter++) {
+ startY -= 22;
+ sprintf(messageLine, "%s: %.3f ms", theIdIter->c_str(),
+ theLayerRenderData->m_LayerProfilerGpu->GetElapsedTime(*theIdIter));
+ RenderText2D(startX + 20, startY, inColor, messageLine);
+ }
+ }
+ }
+ }
+ }
+
+ // Given a node and a point in the node's local space (most likely its pivot point), we return
+ // a normal matrix so you can get the axis out, a transformation from node to camera
+ // a new position and a floating point scale factor so you can render in 1/2 perspective mode
+ // or orthographic mode if you would like to.
+ SWidgetRenderInformation
+ Qt3DSRendererImpl::GetWidgetRenderInformation(SNode &inNode, const QT3DSVec3 &inPos,
+ RenderWidgetModes::Enum inWidgetMode)
+ {
+ SLayerRenderData *theData = GetOrCreateLayerRenderDataForNode(inNode);
+ SCamera *theCamera = theData->m_Camera;
+ if (theCamera == NULL || theData->m_LayerPrepResult.hasValue() == false) {
+ QT3DS_ASSERT(false);
+ return SWidgetRenderInformation();
+ }
+ QT3DSMat44 theGlobalTransform(QT3DSMat44::createIdentity());
+ if (inNode.m_Parent != NULL && inNode.m_Parent->m_Type != GraphObjectTypes::Layer
+ && !inNode.m_Flags.IsIgnoreParentTransform())
+ theGlobalTransform = inNode.m_Parent->m_GlobalTransform;
+ QT3DSMat44 theCameraInverse(theCamera->m_GlobalTransform.getInverse());
+ QT3DSMat44 theNodeParentToCamera;
+ if (inWidgetMode == RenderWidgetModes::Local)
+ theNodeParentToCamera = theCameraInverse * theGlobalTransform;
+ else
+ theNodeParentToCamera = theCameraInverse;
+
+ QT3DSMat33 theNormalMat(theNodeParentToCamera.column0.getXYZ(),
+ theNodeParentToCamera.column1.getXYZ(),
+ theNodeParentToCamera.column2.getXYZ());
+ theNormalMat = theNormalMat.getInverse().getTranspose();
+ theNormalMat.column0.normalize();
+ theNormalMat.column1.normalize();
+ theNormalMat.column2.normalize();
+
+ QT3DSMat44 theTranslation(QT3DSMat44::createIdentity());
+ theTranslation.column3.x = inNode.m_Position.x;
+ theTranslation.column3.y = inNode.m_Position.y;
+ theTranslation.column3.z = inNode.m_Position.z;
+ theTranslation.column3.z *= -1.0f;
+
+ theGlobalTransform = theGlobalTransform * theTranslation;
+
+ QT3DSMat44 theNodeToParentPlusTranslation = theCameraInverse * theGlobalTransform;
+ QT3DSVec3 thePos = theNodeToParentPlusTranslation.transform(inPos);
+ SScaleAndPosition theScaleAndPos = GetWorldToPixelScaleFactor(*theCamera, thePos, *theData);
+ QT3DSMat33 theLookAtMatrix(QT3DSMat33::createIdentity());
+ if (theCamera->m_Flags.IsOrthographic() == false) {
+ QT3DSVec3 theNodeToCamera = theScaleAndPos.m_Position;
+ theNodeToCamera.normalize();
+ QT3DSVec3 theOriginalAxis = QT3DSVec3(0, 0, -1);
+ QT3DSVec3 theRotAxis = theOriginalAxis.cross(theNodeToCamera);
+ QT3DSF32 theAxisLen = theRotAxis.normalize();
+ if (theAxisLen > .05f) {
+ QT3DSF32 theRotAmount = acos(theOriginalAxis.dot(theNodeToCamera));
+ QT3DSQuat theQuat(theRotAmount, theRotAxis);
+ theLookAtMatrix = QT3DSMat33(theQuat);
+ }
+ }
+ QT3DSVec3 thePosInWorldSpace = theGlobalTransform.transform(inPos);
+ QT3DSVec3 theCameraPosInWorldSpace = theCamera->GetGlobalPos();
+ QT3DSVec3 theCameraOffset = thePosInWorldSpace - theCameraPosInWorldSpace;
+ QT3DSVec3 theDir = theCameraOffset;
+ theDir.normalize();
+ // Things should be 600 units from the camera, as that is how all of our math is setup.
+ theCameraOffset = 600.0f * theDir;
+ return SWidgetRenderInformation(
+ theNormalMat, theNodeParentToCamera, theCamera->m_Projection, theCamera->m_Projection,
+ theLookAtMatrix, theCameraInverse, theCameraOffset, theScaleAndPos.m_Position,
+ theScaleAndPos.m_Scale, *theCamera);
+ }
+
+ Option<QT3DSVec2> Qt3DSRendererImpl::GetLayerMouseCoords(SLayer &inLayer,
+ const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inViewportDimensions,
+ bool forceImageIntersect) const
+ {
+ SLayerRenderData *theData =
+ const_cast<Qt3DSRendererImpl &>(*this).GetOrCreateLayerRenderDataForNode(inLayer);
+ return GetLayerMouseCoords(*theData, inMouseCoords, inViewportDimensions,
+ forceImageIntersect);
+ }
+
+ bool IQt3DSRenderer::IsGlEsContext(qt3ds::render::NVRenderContextType inContextType)
+ {
+ qt3ds::render::NVRenderContextType esContextTypes(NVRenderContextValues::GLES2
+ | NVRenderContextValues::GLES3
+ | NVRenderContextValues::GLES3PLUS);
+
+ if ((inContextType & esContextTypes))
+ return true;
+
+ return false;
+ }
+
+ bool IQt3DSRenderer::IsGlEs3Context(qt3ds::render::NVRenderContextType inContextType)
+ {
+ if (inContextType == NVRenderContextValues::GLES3
+ || inContextType == NVRenderContextValues::GLES3PLUS)
+ return true;
+
+ return false;
+ }
+
+ bool IQt3DSRenderer::IsGl2Context(qt3ds::render::NVRenderContextType inContextType)
+ {
+ if (inContextType == NVRenderContextValues::GL2)
+ return true;
+
+ return false;
+ }
+
+ IQt3DSRenderer &IQt3DSRenderer::CreateRenderer(IQt3DSRenderContext &inContext)
+ {
+ return *QT3DS_NEW(inContext.GetAllocator(), Qt3DSRendererImpl)(inContext);
+ }
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h
new file mode 100644
index 0000000..906afd6
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImpl.h
@@ -0,0 +1,549 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_RENDER_SHADER_GENERATOR_IMPL_H
+#define QT3DS_RENDER_SHADER_GENERATOR_IMPL_H
+#include "Qt3DSRender.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRenderableObjects.h"
+#include "Qt3DSRendererImplShaders.h"
+#include "Qt3DSRendererImplLayerRenderData.h"
+#include "foundation/Qt3DSFlags.h"
+#include "Qt3DSRenderMesh.h"
+#include "Qt3DSRenderModel.h"
+#include "foundation/Qt3DSBounds3.h"
+#include "render/Qt3DSRenderContext.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "Qt3DSRenderDefaultMaterial.h"
+#include "foundation/StringTable.h"
+#include "foundation/Qt3DSInvasiveSet.h"
+#include "EASTL/string.h"
+#include "foundation/Qt3DSDataRef.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSRenderRay.h"
+#include "Qt3DSRenderText.h"
+#include "Qt3DSOffscreenRenderManager.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSOffscreenRenderManager.h"
+#include "Qt3DSRendererImplLayerRenderHelper.h"
+#include "Qt3DSRenderWidgets.h"
+#include "Qt3DSRenderShaderCodeGenerator.h"
+#include "Qt3DSRenderClippingFrustum.h"
+#include "foundation/Qt3DSUnionCast.h"
+#include "foundation/FastAllocator.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "Qt3DSRenderShaderKeys.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderProfiler.h"
+#include "Qt3DSRenderDefaultMaterialShaderGenerator.h"
+
+namespace qt3ds {
+namespace render {
+
+ inline bool FloatLessThan(QT3DSF32 lhs, QT3DSF32 rhs)
+ {
+ QT3DSF32 diff = lhs - rhs;
+ if (fabs(diff) < .001)
+ return false;
+ return diff < 0.0f ? true : false;
+ }
+ inline bool ISRenderObjectPtrLessThan(const SRenderableObject *lhs,
+ const SRenderableObject *rhs)
+ {
+ return FloatLessThan(lhs->m_CameraDistanceSq, rhs->m_CameraDistanceSq);
+ }
+ inline bool ISRenderObjectPtrGreatThan(const SRenderableObject *lhs,
+ const SRenderableObject *rhs)
+ {
+ return FloatLessThan(rhs->m_CameraDistanceSq, lhs->m_CameraDistanceSq);
+ }
+ inline bool NonZero(float inValue) { return fabs(inValue) > .001f; }
+ inline bool NonZero(QT3DSU32 inValue) { return inValue != 0; }
+ inline bool IsZero(float inValue) { return fabs(inValue) < .001f; }
+ inline bool IsNotOne(float inValue) { return fabs(1.0f - inValue) > .001f; }
+
+ inline bool IsRectEdgeInBounds(QT3DSI32 inNewRectOffset, QT3DSI32 inNewRectWidth,
+ QT3DSI32 inCurrentRectOffset, QT3DSI32 inCurrentRectWidth)
+ {
+ QT3DSI32 newEnd = inNewRectOffset + inNewRectWidth;
+ QT3DSI32 currentEnd = inCurrentRectOffset + inCurrentRectWidth;
+ return inNewRectOffset >= inCurrentRectOffset && newEnd <= currentEnd;
+ }
+
+ struct STextRenderHelper
+ {
+ STextShader *m_Shader;
+ NVRenderInputAssembler &m_QuadInputAssembler;
+ STextRenderHelper(STextShader *inShader, NVRenderInputAssembler &inQuadInputAssembler)
+ : m_Shader(inShader)
+ , m_QuadInputAssembler(inQuadInputAssembler)
+ {
+ }
+ };
+
+ struct SPickResultProcessResult : public Qt3DSRenderPickResult
+ {
+ SPickResultProcessResult(const Qt3DSRenderPickResult &inSrc)
+ : Qt3DSRenderPickResult(inSrc)
+ , m_WasPickConsumed(false)
+ {
+ }
+ SPickResultProcessResult()
+ : m_WasPickConsumed(false)
+ {
+ }
+ bool m_WasPickConsumed;
+ };
+
+ struct STextShaderPtr
+ {
+ NVAllocatorCallback &m_Allocator;
+ bool m_HasGeneratedShader;
+ STextShader *m_Shader;
+ STextShaderPtr(NVAllocatorCallback &alloc)
+ : m_Allocator(alloc)
+ , m_HasGeneratedShader(false)
+ , m_Shader(NULL)
+ {
+ }
+ bool HasGeneratedShader() { return m_HasGeneratedShader; }
+ void Set(STextShader *inShader)
+ {
+ m_Shader = inShader;
+ m_HasGeneratedShader = true;
+ }
+ ~STextShaderPtr()
+ {
+ if (m_Shader)
+ NVDelete(m_Allocator, m_Shader);
+ }
+ operator STextShader *() { return m_Shader; }
+ };
+
+ class QT3DS_AUTOTEST_EXPORT Qt3DSRendererImpl : public IQt3DSRenderer, public IRenderWidgetContext
+ {
+ typedef nvhash_map<SShaderDefaultMaterialKey, SShaderGeneratorGeneratedShader *> TShaderMap;
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderConstantBuffer>>
+ TStrConstanBufMap;
+ typedef nvhash_map<SRenderInstanceId, NVScopedRefCounted<SLayerRenderData>,
+ eastl::hash<SRenderInstanceId>> TInstanceRenderMap;
+ typedef nvvector<SLayerRenderData *> TLayerRenderList;
+ typedef nvvector<Qt3DSRenderPickResult> TPickResultArray;
+
+ // Items to implement the widget context.
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderVertexBuffer>>
+ TStrVertBufMap;
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderIndexBuffer>>
+ TStrIndexBufMap;
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderShaderProgram>>
+ TStrShaderMap;
+ typedef nvhash_map<CRegisteredString, NVScopedRefCounted<NVRenderInputAssembler>> TStrIAMap;
+
+ typedef nvhash_map<long, SNode *> TBoneIdNodeMap;
+
+ IQt3DSRenderContext &m_qt3dsContext;
+ NVScopedRefCounted<NVRenderContext> m_Context;
+ NVScopedRefCounted<IBufferManager> m_BufferManager;
+ NVScopedRefCounted<IOffscreenRenderManager> m_OffscreenRenderManager;
+ NVScopedRefCounted<IStringTable> m_StringTable;
+ InvasiveSet<SShaderGeneratorGeneratedShader, SGGSGet, SGGSSet> m_LayerShaders;
+ // For rendering bounding boxes.
+ NVScopedRefCounted<NVRenderVertexBuffer> m_BoxVertexBuffer;
+ NVScopedRefCounted<NVRenderIndexBuffer> m_BoxIndexBuffer;
+ NVScopedRefCounted<NVRenderShaderProgram> m_BoxShader;
+ NVScopedRefCounted<NVRenderShaderProgram> m_ScreenRectShader;
+
+ NVScopedRefCounted<NVRenderVertexBuffer> m_AxisVertexBuffer;
+ NVScopedRefCounted<NVRenderShaderProgram> m_AxisShader;
+
+ // X,Y quad, broken down into 2 triangles and normalized over
+ //-1,1.
+ NVScopedRefCounted<NVRenderVertexBuffer> m_QuadVertexBuffer;
+ NVScopedRefCounted<NVRenderIndexBuffer> m_QuadIndexBuffer;
+ NVScopedRefCounted<NVRenderIndexBuffer> m_RectIndexBuffer;
+ NVScopedRefCounted<NVRenderInputAssembler> m_QuadInputAssembler;
+ NVScopedRefCounted<NVRenderInputAssembler> m_RectInputAssembler;
+ NVScopedRefCounted<NVRenderAttribLayout> m_QuadAttribLayout;
+ NVScopedRefCounted<NVRenderAttribLayout> m_RectAttribLayout;
+
+ // X,Y triangle strip quads in screen coord dynamiclly setup
+ NVScopedRefCounted<NVRenderVertexBuffer> m_QuadStripVertexBuffer;
+ NVScopedRefCounted<NVRenderInputAssembler> m_QuadStripInputAssembler;
+ NVScopedRefCounted<NVRenderAttribLayout> m_QuadStripAttribLayout;
+
+ // X,Y,Z point which is used for instanced based rendering of points
+ NVScopedRefCounted<NVRenderVertexBuffer> m_PointVertexBuffer;
+ NVScopedRefCounted<NVRenderInputAssembler> m_PointInputAssembler;
+ NVScopedRefCounted<NVRenderAttribLayout> m_PointAttribLayout;
+
+ Option<NVScopedRefCounted<SLayerSceneShader>> m_SceneLayerShader;
+ Option<NVScopedRefCounted<SLayerProgAABlendShader>> m_LayerProgAAShader;
+
+ TShaderMap m_Shaders;
+ TStrConstanBufMap m_ConstantBuffers; ///< store the the shader constant buffers
+ // Option is true if we have attempted to generate the shader.
+ // This does not mean we were successul, however.
+ Option<NVScopedRefCounted<SDefaultMaterialRenderableDepthShader>>
+ m_DefaultMaterialDepthPrepassShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthPrepassShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthPrepassShaderDisplaced;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthTessLinearPrepassShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>>
+ m_DepthTessLinearPrepassShaderDisplaced;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthTessPhongPrepassShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_DepthTessNPatchPrepassShader;
+ Option<NVScopedRefCounted<STextDepthShader>> m_TextDepthPrepassShader;
+ Option<NVScopedRefCounted<SDefaultAoPassShader>> m_DefaultAoPassShader;
+ Option<NVScopedRefCounted<SDefaultAoPassShader>> m_FakeDepthShader;
+ Option<NVScopedRefCounted<SDefaultAoPassShader>> m_FakeCubemapDepthShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_ParaboloidDepthShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_ParaboloidDepthTessLinearShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_ParaboloidDepthTessPhongShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_ParaboloidDepthTessNPatchShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_CubemapDepthShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_CubemapDepthTessLinearShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_CubemapDepthTessPhongShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_CubemapDepthTessNPatchShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> m_OrthographicDepthShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>>
+ m_OrthographicDepthTessLinearShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>>
+ m_OrthographicDepthTessPhongShader;
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>>
+ m_OrthographicDepthTessNPatchShader;
+ Option<NVScopedRefCounted<SShadowmapPreblurShader>> m_CubeShadowBlurXShader;
+ Option<NVScopedRefCounted<SShadowmapPreblurShader>> m_CubeShadowBlurYShader;
+ Option<NVScopedRefCounted<SShadowmapPreblurShader>> m_OrthoShadowBlurXShader;
+ Option<NVScopedRefCounted<SShadowmapPreblurShader>> m_OrthoShadowBlurYShader;
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ Option<NVScopedRefCounted<SAdvancedModeBlendShader>> m_AdvancedModeOverlayBlendShader;
+ Option<NVScopedRefCounted<SAdvancedModeBlendShader>> m_AdvancedModeColorBurnBlendShader;
+ Option<NVScopedRefCounted<SAdvancedModeBlendShader>> m_AdvancedModeColorDodgeBlendShader;
+#endif
+ // Text shaders may be generated on demand.
+ STextShaderPtr m_TextShader;
+ STextShaderPtr m_TextPathShader;
+ STextShaderPtr m_TextWidgetShader;
+ STextShaderPtr m_TextOnscreenShader;
+
+ // Overlay used to render all widgets.
+ NVRenderRect m_BeginFrameViewport;
+ NVScopedRefCounted<NVRenderTexture2D> m_WidgetTexture;
+ NVScopedRefCounted<NVRenderFrameBuffer> m_WidgetFBO;
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ // Advanced blend mode SW fallback
+ CResourceTexture2D m_LayerBlendTexture;
+ NVScopedRefCounted<NVRenderFrameBuffer> m_BlendFB;
+#endif
+ // Allocator for temporary data that is cleared after every layer.
+ TInstanceRenderMap m_InstanceRenderMap;
+ TLayerRenderList m_LastFrameLayers;
+ volatile QT3DSI32 mRefCount;
+
+ // Set from the first layer.
+ TPickResultArray m_LastPickResults;
+
+ // Temporary information stored only when rendering a particular layer.
+ SLayerRenderData *m_CurrentLayer;
+ QT3DSMat44 m_ViewProjection;
+ eastl::string m_GeneratedShaderString;
+
+ TStrVertBufMap m_WidgetVertexBuffers;
+ TStrIndexBufMap m_WidgetIndexBuffers;
+ TStrShaderMap m_WidgetShaders;
+ TStrIAMap m_WidgetInputAssembler;
+
+ TBoneIdNodeMap m_BoneIdNodeMap;
+
+ bool m_PickRenderPlugins;
+ bool m_LayerCachingEnabled;
+ bool m_LayerGPuProfilingEnabled;
+ SShaderDefaultMaterialKeyProperties m_DefaultMaterialShaderKeyProperties;
+
+ public:
+ Qt3DSRendererImpl(IQt3DSRenderContext &ctx);
+ virtual ~Qt3DSRendererImpl();
+ SShaderDefaultMaterialKeyProperties &DefaultMaterialShaderKeyProperties()
+ {
+ return m_DefaultMaterialShaderKeyProperties;
+ }
+
+ // NVRefCounted
+ void addRef() override;
+ void release() override;
+
+ void EnableLayerCaching(bool inEnabled) override { m_LayerCachingEnabled = inEnabled; }
+ bool IsLayerCachingEnabled() const override { return m_LayerCachingEnabled; }
+
+ void EnableLayerGpuProfiling(bool inEnabled) override;
+ bool IsLayerGpuProfilingEnabled() const override { return m_LayerGPuProfilingEnabled; }
+
+ // Calls prepare layer for render
+ // and then do render layer.
+ bool PrepareLayerForRender(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions,
+ bool inRenderSiblings, const SRenderInstanceId id) override;
+ void RenderLayer(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions,
+ bool clear, QT3DSVec4 clearColor, bool inRenderSiblings,
+ const SRenderInstanceId id) override;
+ void ChildrenUpdated(SNode &inParent) override;
+ QT3DSF32 GetTextScale(const SText &inText) override;
+
+ SCamera *GetCameraForNode(const SNode &inNode) const override;
+ Option<SCuboidRect> GetCameraBounds(const SGraphObject &inObject) override;
+ virtual SLayer *GetLayerForNode(const SNode &inNode) const;
+ SLayerRenderData *GetOrCreateLayerRenderDataForNode(const SNode &inNode,
+ const SRenderInstanceId id = nullptr);
+
+ IRenderWidgetContext &GetRenderWidgetContext()
+ {
+ return *this;
+ }
+
+ void BeginFrame() override;
+ void EndFrame() override;
+
+ void PickRenderPlugins(bool inPick) override { m_PickRenderPlugins = inPick; }
+ Qt3DSRenderPickResult Pick(SLayer &inLayer, const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inMouseCoords, bool inPickSiblings,
+ bool inPickEverything,
+ const SRenderInstanceId id) override;
+
+ virtual Option<QT3DSVec2>
+ FacePosition(SNode &inNode, NVBounds3 inBounds, const QT3DSMat44 &inGlobalTransform,
+ const QT3DSVec2 &inViewportDimensions, const QT3DSVec2 &inMouseCoords,
+ NVDataRef<SGraphObject *> inMapperObjects, SBasisPlanes::Enum inPlane) override;
+
+ virtual Qt3DSRenderPickResult PickOffscreenLayer(SLayer &inLayer,
+ const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inMouseCoords,
+ bool inPickEverything);
+
+ QT3DSVec3 UnprojectToPosition(SNode &inNode, QT3DSVec3 &inPosition,
+ const QT3DSVec2 &inMouseVec) const override;
+ QT3DSVec3 UnprojectWithDepth(SNode &inNode, QT3DSVec3 &inPosition,
+ const QT3DSVec3 &inMouseVec) const override;
+ QT3DSVec3 ProjectPosition(SNode &inNode, const QT3DSVec3 &inPosition) const override;
+
+ Option<SLayerPickSetup> GetLayerPickSetup(SLayer &inLayer,
+ const QT3DSVec2 &inMouseCoords,
+ const QSize &inPickDims) override;
+
+ Option<NVRenderRectF> GetLayerRect(SLayer &inLayer) override;
+
+ void RunLayerRender(SLayer &inLayer, const QT3DSMat44 &inViewProjection) override;
+
+ // Note that this allocator is completely reset on BeginFrame.
+ NVAllocatorCallback &GetPerFrameAllocator() override
+ {
+ return m_qt3dsContext.GetPerFrameAllocator();
+ }
+ void RenderLayerRect(SLayer &inLayer, const QT3DSVec3 &inColor) override;
+ void AddRenderWidget(IRenderWidget &inWidget) override;
+
+ SScaleAndPosition GetWorldToPixelScaleFactor(SLayer &inLayer,
+ const QT3DSVec3 &inWorldPoint) override;
+ SScaleAndPosition GetWorldToPixelScaleFactor(const SCamera &inCamera,
+ const QT3DSVec3 &inWorldPoint,
+ SLayerRenderData &inRenderData);
+
+ void ReleaseLayerRenderResources(SLayer &inLayer, const SRenderInstanceId id) override;
+
+ void RenderQuad(const QT3DSVec2 inDimensions, const QT3DSMat44 &inMVP,
+ NVRenderTexture2D &inQuadTexture) override;
+ void RenderQuad() override;
+
+ void RenderPointsIndirect() override;
+
+ // render a screen aligned 2D text
+ void RenderText2D(QT3DSF32 x, QT3DSF32 y, qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor,
+ const char *text) override;
+ bool PrepareTextureAtlasForRender();
+
+ // render Gpu profiler values
+ void RenderGpuProfilerStats(QT3DSF32 x, QT3DSF32 y,
+ qt3ds::foundation::Option<qt3ds::QT3DSVec3> inColor) override;
+
+ // Callback during the layer render process.
+ void LayerNeedsFrameClear(SLayerRenderData &inLayer);
+ void BeginLayerDepthPassRender(SLayerRenderData &inLayer);
+ void EndLayerDepthPassRender();
+ void BeginLayerRender(SLayerRenderData &inLayer);
+ void EndLayerRender();
+ void PrepareImageForIbl(SImage &inImage);
+
+ NVRenderShaderProgram *CompileShader(CRegisteredString inName, const char8_t *inVert,
+ const char8_t *inFrame);
+
+ NVRenderShaderProgram *GenerateShader(SSubsetRenderable &inRenderable,
+ TShaderFeatureSet inFeatureSet);
+ SShaderGeneratorGeneratedShader *GetShader(SSubsetRenderable &inRenderable,
+ TShaderFeatureSet inFeatureSet);
+
+ SDefaultAoPassShader *GetDefaultAoPassShader(TShaderFeatureSet inFeatureSet);
+ SDefaultAoPassShader *GetFakeDepthShader(TShaderFeatureSet inFeatureSet);
+ SDefaultAoPassShader *GetFakeCubeDepthShader(TShaderFeatureSet inFeatureSet);
+ SDefaultMaterialRenderableDepthShader *GetRenderableDepthShader();
+
+ SRenderableDepthPrepassShader *GetParaboloidDepthShader(TessModeValues::Enum inTessMode);
+ SRenderableDepthPrepassShader *GetParaboloidDepthNoTessShader();
+ SRenderableDepthPrepassShader *GetParaboloidDepthTessLinearShader();
+ SRenderableDepthPrepassShader *GetParaboloidDepthTessPhongShader();
+ SRenderableDepthPrepassShader *GetParaboloidDepthTessNPatchShader();
+ SRenderableDepthPrepassShader *GetCubeShadowDepthShader(TessModeValues::Enum inTessMode);
+ SRenderableDepthPrepassShader *GetCubeDepthNoTessShader();
+ SRenderableDepthPrepassShader *GetCubeDepthTessLinearShader();
+ SRenderableDepthPrepassShader *GetCubeDepthTessPhongShader();
+ SRenderableDepthPrepassShader *GetCubeDepthTessNPatchShader();
+ SRenderableDepthPrepassShader *GetOrthographicDepthShader(TessModeValues::Enum inTessMode);
+ SRenderableDepthPrepassShader *GetOrthographicDepthNoTessShader();
+ SRenderableDepthPrepassShader *GetOrthographicDepthTessLinearShader();
+ SRenderableDepthPrepassShader *GetOrthographicDepthTessPhongShader();
+ SRenderableDepthPrepassShader *GetOrthographicDepthTessNPatchShader();
+
+ SRenderableDepthPrepassShader *GetDepthPrepassShader(bool inDisplaced);
+ SRenderableDepthPrepassShader *GetDepthTessPrepassShader(TessModeValues::Enum inTessMode,
+ bool inDisplaced);
+ SRenderableDepthPrepassShader *GetDepthTessLinearPrepassShader(bool inDisplaced);
+ SRenderableDepthPrepassShader *GetDepthTessPhongPrepassShader();
+ SRenderableDepthPrepassShader *GetDepthTessNPatchPrepassShader();
+ STextDepthShader *GetTextDepthShader();
+ STextRenderHelper GetShader(STextRenderable &inRenderable, bool inUsePathRendering);
+ STextRenderHelper GetTextShader(bool inUsePathRendering);
+ STextRenderHelper GetTextWidgetShader();
+ STextRenderHelper GetOnscreenTextShader();
+ SLayerSceneShader *GetSceneLayerShader();
+ NVRenderShaderProgram *GetTextAtlasEntryShader();
+ void GenerateXYQuad();
+ void GenerateXYQuadStrip();
+ void GenerateXYZPoint();
+ eastl::pair<NVRenderVertexBuffer *, NVRenderIndexBuffer *> GetXYQuad();
+ SLayerProgAABlendShader *GetLayerProgAABlendShader();
+ SShadowmapPreblurShader *GetCubeShadowBlurXShader();
+ SShadowmapPreblurShader *GetCubeShadowBlurYShader();
+ SShadowmapPreblurShader *GetOrthoShadowBlurXShader();
+ SShadowmapPreblurShader *GetOrthoShadowBlurYShader();
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ SAdvancedModeBlendShader *GetAdvancedBlendModeShader(AdvancedBlendModes::Enum blendMode);
+ SAdvancedModeBlendShader *GetOverlayBlendModeShader();
+ SAdvancedModeBlendShader *GetColorBurnBlendModeShader();
+ SAdvancedModeBlendShader *GetColorDodgeBlendModeShader();
+#endif
+ SLayerRenderData *GetLayerRenderData() { return m_CurrentLayer; }
+ SLayerGlobalRenderProperties GetLayerGlobalRenderProperties();
+ void UpdateCbAoShadow(const SLayer *pLayer, const SCamera *pCamera,
+ CResourceTexture2D &inDepthTexture);
+
+ NVRenderContext &GetContext() { return *m_Context; }
+
+ IQt3DSRenderContext &GetQt3DSContext() { return m_qt3dsContext; }
+
+ void DrawScreenRect(NVRenderRectF inRect, const QT3DSVec3 &inColor);
+ // Binds an offscreen texture. Widgets are rendered last.
+ void SetupWidgetLayer();
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ NVScopedRefCounted<NVRenderTexture2D> GetLayerBlendTexture()
+ {
+ return m_LayerBlendTexture.GetTexture();
+ }
+
+ NVScopedRefCounted<NVRenderFrameBuffer> GetBlendFB()
+ {
+ return m_BlendFB;
+ }
+#endif
+ // widget context implementation
+ virtual NVRenderVertexBuffer &
+ GetOrCreateVertexBuffer(CRegisteredString &inStr, QT3DSU32 stride,
+ NVConstDataRef<QT3DSU8> bufferData = NVConstDataRef<QT3DSU8>()) override;
+ virtual NVRenderIndexBuffer &
+ GetOrCreateIndexBuffer(CRegisteredString &inStr,
+ qt3ds::render::NVRenderComponentTypes::Enum componentType, size_t size,
+ NVConstDataRef<QT3DSU8> bufferData = NVConstDataRef<QT3DSU8>()) override;
+ virtual NVRenderAttribLayout &
+ CreateAttributeLayout(NVConstDataRef<qt3ds::render::NVRenderVertexBufferEntry> attribs) override;
+ virtual NVRenderInputAssembler &
+ GetOrCreateInputAssembler(CRegisteredString &inStr, NVRenderAttribLayout *attribLayout,
+ NVConstDataRef<NVRenderVertexBuffer *> buffers,
+ const NVRenderIndexBuffer *indexBuffer,
+ NVConstDataRef<QT3DSU32> strides, NVConstDataRef<QT3DSU32> offsets) override;
+
+ NVRenderVertexBuffer *GetVertexBuffer(CRegisteredString &inStr) override;
+ NVRenderIndexBuffer *GetIndexBuffer(CRegisteredString &inStr) override;
+ NVRenderInputAssembler *GetInputAssembler(CRegisteredString &inStr) override;
+
+ NVRenderShaderProgram *GetShader(CRegisteredString inStr) override;
+ NVRenderShaderProgram *CompileAndStoreShader(CRegisteredString inStr) override;
+ IShaderProgramGenerator &GetProgramGenerator() override;
+
+ STextDimensions MeasureText(const STextRenderInfo &inText) override;
+ void RenderText(const STextRenderInfo &inText, const QT3DSVec3 &inTextColor,
+ const QT3DSVec3 &inBackgroundColor, const QT3DSMat44 &inMVP) override;
+
+ // Given a node and a point in the node's local space (most likely its pivot point), we
+ // return
+ // a normal matrix so you can get the axis out, a transformation from node to camera
+ // a new position and a floating point scale factor so you can render in 1/2 perspective
+ // mode
+ // or orthographic mode if you would like to.
+ virtual SWidgetRenderInformation
+ GetWidgetRenderInformation(SNode &inNode, const QT3DSVec3 &inPos,
+ RenderWidgetModes::Enum inWidgetMode) override;
+
+ Option<QT3DSVec2> GetLayerMouseCoords(SLayer &inLayer, const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inViewportDimensions,
+ bool forceImageIntersect = false) const override;
+
+ protected:
+ Option<QT3DSVec2> GetLayerMouseCoords(SLayerRenderData &inLayer, const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inViewportDimensions,
+ bool forceImageIntersect = false) const;
+ SPickResultProcessResult ProcessPickResultList(bool inPickEverything);
+ // If the mouse y coordinates need to be flipped we expect that to happen before entry into
+ // this function
+ void GetLayerHitObjectList(SLayerRenderData &inLayer, const QT3DSVec2 &inViewportDimensions,
+ const QT3DSVec2 &inMouseCoords, bool inPickEverything,
+ TPickResultArray &outIntersectionResult,
+ NVAllocatorCallback &inTempAllocator);
+ void IntersectRayWithSubsetRenderable(const SRay &inRay,
+ SRenderableObject &inRenderableObject,
+ TPickResultArray &outIntersectionResultList,
+ NVAllocatorCallback &inTempAllocator);
+ };
+}
+}
+
+#endif
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
new file mode 100644
index 0000000..362a602
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp
@@ -0,0 +1,2220 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSRender.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSRenderEffect.h"
+#include "EASTL/sort.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderScene.h"
+#include "Qt3DSRenderPresentation.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderResourceManager.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "render/Qt3DSRenderRenderBuffer.h"
+#include "Qt3DSOffscreenRenderKey.h"
+#include "Qt3DSRenderPlugin.h"
+#include "Qt3DSRenderPluginGraphObject.h"
+#include "Qt3DSRenderResourceBufferObjects.h"
+#include "foundation/Qt3DSPerfTimer.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "Qt3DSRenderMaterialHelpers.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderTextTextureCache.h"
+#include "Qt3DSRenderTextTextureAtlas.h"
+#include "Qt3DSRenderRenderList.h"
+#include "Qt3DSRendererUtil.h"
+
+#ifdef WIN32
+#pragma warning(disable : 4355)
+#endif
+
+#define QT3DS_CACHED_POST_EFFECT
+const float QT3DS_DEGREES_TO_RADIANS = 0.0174532925199f;
+
+namespace qt3ds {
+namespace render {
+ using eastl::reverse;
+ using eastl::stable_sort;
+ using qt3ds::render::NVRenderContextScopedProperty;
+ using qt3ds::QT3DSVec2;
+
+ SLayerRenderData::SLayerRenderData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer)
+ : SLayerRenderPreparationData(inLayer, inRenderer)
+ , m_LayerTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_TemporalAATexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerPrepassDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerWidgetTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerSsaoTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisampleTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisamplePrepassDepthTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerMultisampleWidgetTexture(inRenderer.GetQt3DSContext().GetResourceManager())
+ , m_LayerCachedTexture(NULL)
+ , m_AdvancedBlendDrawTexture(NULL)
+ , m_AdvancedBlendBlendTexture(NULL)
+ , m_AdvancedModeDrawFB(NULL)
+ , m_AdvancedModeBlendFB(NULL)
+ , m_ProgressiveAAPassIndex(0)
+ , m_TemporalAAPassIndex(0)
+ , m_NonDirtyTemporalAAPassIndex(0)
+ , m_TextScale(1.0f)
+ , mRefCount(0)
+ , m_DepthBufferFormat(NVRenderTextureFormats::Unknown)
+ {
+ }
+
+ SLayerRenderData::~SLayerRenderData()
+ {
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture)
+ theResourceManager.Release(*m_LayerCachedTexture);
+ if (m_AdvancedModeDrawFB) {
+ m_AdvancedModeDrawFB->release();
+ m_AdvancedModeDrawFB = NULL;
+ }
+ if (m_AdvancedModeBlendFB) {
+ m_AdvancedModeBlendFB->release();
+ m_AdvancedModeBlendFB = NULL;
+ }
+ if (m_AdvancedBlendBlendTexture)
+ m_AdvancedBlendBlendTexture = NULL;
+ if (m_AdvancedBlendDrawTexture)
+ m_AdvancedBlendDrawTexture = NULL;
+ }
+ void SLayerRenderData::PrepareForRender(const QSize &inViewportDimensions)
+ {
+ SLayerRenderPreparationData::PrepareForRender(inViewportDimensions);
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // at that time all values shoud be updated
+ m_Renderer.UpdateCbAoShadow(&m_Layer, m_Camera, m_LayerDepthTexture);
+
+ // Generate all necessary lighting keys
+
+ if (thePrepResult.m_Flags.WasLayerDataDirty()) {
+ m_ProgressiveAAPassIndex = 0;
+ }
+
+ // Get rid of the layer texture if we aren't rendering to texture this frame.
+ if (m_LayerTexture && !thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) {
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+
+ m_LayerTexture.ReleaseTexture();
+ m_LayerDepthTexture.ReleaseTexture();
+ m_LayerWidgetTexture.ReleaseTexture();
+ m_LayerSsaoTexture.ReleaseTexture();
+ m_LayerMultisampleTexture.ReleaseTexture();
+ m_LayerMultisamplePrepassDepthTexture.ReleaseTexture();
+ m_LayerMultisampleWidgetTexture.ReleaseTexture();
+ }
+
+ if (NeedsWidgetTexture() == false)
+ m_LayerWidgetTexture.ReleaseTexture();
+
+ if (m_LayerDepthTexture && !thePrepResult.m_Flags.RequiresDepthTexture())
+ m_LayerDepthTexture.ReleaseTexture();
+
+ if (m_LayerSsaoTexture && !thePrepResult.m_Flags.RequiresSsaoPass())
+ m_LayerSsaoTexture.ReleaseTexture();
+
+ m_Renderer.LayerNeedsFrameClear(*this);
+
+ // Clean up the texture cache if layer dimensions changed
+ if (inViewportDimensions.width() != m_previousDimensions.width()
+ || inViewportDimensions.height() != m_previousDimensions.height()) {
+ m_LayerTexture.ReleaseTexture();
+ m_LayerDepthTexture.ReleaseTexture();
+ m_LayerSsaoTexture.ReleaseTexture();
+ m_LayerWidgetTexture.ReleaseTexture();
+ m_LayerPrepassDepthTexture.ReleaseTexture();
+ m_TemporalAATexture.ReleaseTexture();
+ m_LayerMultisampleTexture.ReleaseTexture();
+ m_LayerMultisamplePrepassDepthTexture.ReleaseTexture();
+ m_LayerMultisampleWidgetTexture.ReleaseTexture();
+
+ m_previousDimensions.setWidth(inViewportDimensions.width());
+ m_previousDimensions.setHeight(inViewportDimensions.height());
+
+ theResourceManager.DestroyFreeSizedResources();
+
+ // Effect system uses different resource manager, so clean that up too
+ m_Renderer.GetQt3DSContext().GetEffectSystem().GetResourceManager()
+ .DestroyFreeSizedResources();
+ }
+ }
+
+ NVRenderTextureFormats::Enum SLayerRenderData::GetDepthBufferFormat()
+ {
+ if (m_DepthBufferFormat == NVRenderTextureFormats::Unknown) {
+ QT3DSU32 theExistingDepthBits = m_Renderer.GetContext().GetDepthBits();
+ QT3DSU32 theExistingStencilBits = m_Renderer.GetContext().GetStencilBits();
+ switch (theExistingDepthBits) {
+ case 32:
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth32;
+ break;
+ case 24:
+ // check if we have stencil bits
+ if (theExistingStencilBits > 0)
+ m_DepthBufferFormat =
+ NVRenderTextureFormats::Depth24Stencil8; // currently no stencil usage
+ // should be Depth24Stencil8 in
+ // this case
+ else
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth24;
+ break;
+ case 16:
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth16;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ m_DepthBufferFormat = NVRenderTextureFormats::Depth16;
+ break;
+ }
+ }
+ return m_DepthBufferFormat;
+ }
+
+ NVRenderFrameBufferAttachments::Enum
+ SLayerRenderData::GetFramebufferDepthAttachmentFormat(NVRenderTextureFormats::Enum depthFormat)
+ {
+ NVRenderFrameBufferAttachments::Enum fmt = NVRenderFrameBufferAttachments::Depth;
+
+ switch (depthFormat) {
+ case NVRenderTextureFormats::Depth16:
+ case NVRenderTextureFormats::Depth24:
+ case NVRenderTextureFormats::Depth32:
+ fmt = NVRenderFrameBufferAttachments::Depth;
+ break;
+ case NVRenderTextureFormats::Depth24Stencil8:
+ fmt = NVRenderFrameBufferAttachments::DepthStencil;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+
+ return fmt;
+ }
+
+ void SLayerRenderData::RenderAoPass()
+ {
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SDefaultAoPassShader *shader = m_Renderer.GetDefaultAoPassShader(GetShaderFeatureSet());
+ if (shader == NULL)
+ return;
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ // Setup constants
+ shader->m_CameraDirection.Set(m_CameraDirection);
+ shader->m_ViewMatrix.Set(m_Camera->m_GlobalTransform);
+
+ shader->m_DepthTexture.Set(m_LayerDepthTexture);
+ shader->m_DepthSamplerSize.Set(QT3DSVec2(m_LayerDepthTexture->GetTextureDetails().m_Width,
+ m_LayerDepthTexture->GetTextureDetails().m_Height));
+
+ // Important uniforms for AO calculations
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ shader->m_CameraProperties.Set(theCameraProps);
+ shader->m_AoShadowParams.Set();
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ void SLayerRenderData::RenderFakeDepthMapPass(NVRenderTexture2D *theDepthTex,
+ NVRenderTextureCube *theDepthCube)
+ {
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SDefaultAoPassShader *shader = theDepthTex
+ ? m_Renderer.GetFakeDepthShader(GetShaderFeatureSet())
+ : m_Renderer.GetFakeCubeDepthShader(GetShaderFeatureSet());
+ if (shader == NULL)
+ return;
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ // Setup constants
+ shader->m_CameraDirection.Set(m_CameraDirection);
+ shader->m_ViewMatrix.Set(m_Camera->m_GlobalTransform);
+
+ shader->m_DepthTexture.Set(theDepthTex);
+ shader->m_CubeTexture.Set(theDepthCube);
+ shader->m_DepthSamplerSize.Set(QT3DSVec2(theDepthTex->GetTextureDetails().m_Width,
+ theDepthTex->GetTextureDetails().m_Height));
+
+ // Important uniforms for AO calculations
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ shader->m_CameraProperties.Set(theCameraProps);
+ shader->m_AoShadowParams.Set();
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+ }
+
+ namespace {
+
+ void computeFrustumBounds(const SCamera &inCamera, const NVRenderRectF &inViewPort,
+ QT3DSVec3 &ctrBound, QT3DSVec3 camVerts[8])
+ {
+ QT3DSVec3 camEdges[4];
+
+ const QT3DSF32 *dataPtr(inCamera.m_GlobalTransform.front());
+ QT3DSVec3 camX(dataPtr[0], dataPtr[1], dataPtr[2]);
+ QT3DSVec3 camY(dataPtr[4], dataPtr[5], dataPtr[6]);
+ QT3DSVec3 camZ(dataPtr[8], dataPtr[9], dataPtr[10]);
+
+ float tanFOV = tanf(inCamera.verticalFov(inViewPort) * 0.5f);
+ float asTanFOV = tanFOV * inViewPort.m_Width / inViewPort.m_Height;
+ camEdges[0] = -asTanFOV * camX + tanFOV * camY + camZ;
+ camEdges[1] = asTanFOV * camX + tanFOV * camY + camZ;
+ camEdges[2] = asTanFOV * camX - tanFOV * camY + camZ;
+ camEdges[3] = -asTanFOV * camX - tanFOV * camY + camZ;
+
+ for (int i = 0; i < 4; ++i) {
+ camEdges[i].x = -camEdges[i].x;
+ camEdges[i].y = -camEdges[i].y;
+ }
+
+ camVerts[0] = inCamera.m_Position + camEdges[0] * inCamera.m_ClipNear;
+ camVerts[1] = inCamera.m_Position + camEdges[0] * inCamera.m_ClipFar;
+ camVerts[2] = inCamera.m_Position + camEdges[1] * inCamera.m_ClipNear;
+ camVerts[3] = inCamera.m_Position + camEdges[1] * inCamera.m_ClipFar;
+ camVerts[4] = inCamera.m_Position + camEdges[2] * inCamera.m_ClipNear;
+ camVerts[5] = inCamera.m_Position + camEdges[2] * inCamera.m_ClipFar;
+ camVerts[6] = inCamera.m_Position + camEdges[3] * inCamera.m_ClipNear;
+ camVerts[7] = inCamera.m_Position + camEdges[3] * inCamera.m_ClipFar;
+
+ ctrBound = camVerts[0];
+ for (int i = 1; i < 8; ++i) {
+ ctrBound += camVerts[i];
+ }
+ ctrBound *= 0.125f;
+ }
+
+ void SetupCameraForShadowMap(const QT3DSVec2 &inCameraVec, NVRenderContext & /*inContext*/,
+ const NVRenderRectF &inViewport, const SCamera &inCamera,
+ const SLight *inLight, SCamera &theCamera)
+ {
+ // setup light matrix
+ QT3DSU32 mapRes = 1 << inLight->m_ShadowMapRes;
+ NVRenderRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
+ theCamera.m_ClipNear = 1.0f;
+ theCamera.m_ClipFar = inLight->m_ShadowMapFar;
+ // Setup camera projection
+ QT3DSVec3 inLightPos = inLight->GetGlobalPos();
+ QT3DSVec3 inLightDir = inLight->GetDirection();
+
+ if (inLight->m_Flags.IsLeftHanded())
+ inLightPos.z = -inLightPos.z;
+
+ inLightPos -= inLightDir * inCamera.m_ClipNear;
+ theCamera.m_FOV = inLight->m_ShadowMapFov * QT3DS_DEGREES_TO_RADIANS;
+
+ if (inLight->m_LightType == RenderLightTypes::Directional) {
+ QT3DSVec3 frustBounds[8], boundCtr;
+ computeFrustumBounds(inCamera, inViewport, boundCtr, frustBounds);
+
+ QT3DSVec3 forward = inLightDir;
+ forward.normalize();
+ QT3DSVec3 right = forward.cross(QT3DSVec3(0, 1, 0));
+ right.normalize();
+ QT3DSVec3 up = right.cross(forward);
+ up.normalize();
+
+ // Calculate bounding box of the scene camera frustum
+ float minDistanceZ = std::numeric_limits<float>::max();
+ float maxDistanceZ = -std::numeric_limits<float>::max();
+ float minDistanceY = std::numeric_limits<float>::max();
+ float maxDistanceY = -std::numeric_limits<float>::max();
+ float minDistanceX = std::numeric_limits<float>::max();
+ float maxDistanceX = -std::numeric_limits<float>::max();
+ for (int i = 0; i < 8; ++i) {
+ float distanceZ = frustBounds[i].dot(forward);
+ if (distanceZ < minDistanceZ)
+ minDistanceZ = distanceZ;
+ if (distanceZ > maxDistanceZ)
+ maxDistanceZ = distanceZ;
+ float distanceY = frustBounds[i].dot(up);
+ if (distanceY < minDistanceY)
+ minDistanceY = distanceY;
+ if (distanceY > maxDistanceY)
+ maxDistanceY = distanceY;
+ float distanceX = frustBounds[i].dot(right);
+ if (distanceX < minDistanceX)
+ minDistanceX = distanceX;
+ if (distanceX > maxDistanceX)
+ maxDistanceX = distanceX;
+ }
+
+ // Apply bounding box parameters to shadow map camera projection matrix
+ // so that the whole scene is fit inside the shadow map
+ inLightPos = boundCtr;
+ theViewport.m_Height = abs(maxDistanceY - minDistanceY);
+ theViewport.m_Width = abs(maxDistanceX - minDistanceX);
+ theCamera.m_ClipNear = -abs(maxDistanceZ - minDistanceZ);
+ theCamera.m_ClipFar = abs(maxDistanceZ - minDistanceZ);
+ }
+
+ theCamera.m_Flags.SetLeftHanded(false);
+
+ theCamera.m_Flags.ClearOrSet(inLight->m_LightType == RenderLightTypes::Directional,
+ NodeFlagValues::Orthographic);
+ theCamera.m_Parent = NULL;
+ theCamera.m_Pivot = inLight->m_Pivot;
+
+ if (inLight->m_LightType != RenderLightTypes::Point) {
+ theCamera.LookAt(inLightPos, QT3DSVec3(0, 1.0, 0), inLightPos + inLightDir);
+ } else {
+ theCamera.LookAt(inLightPos, QT3DSVec3(0, 1.0, 0), QT3DSVec3(0, 0, 0));
+ }
+
+ theCamera.CalculateGlobalVariables(theViewport,
+ QT3DSVec2(theViewport.m_Width, theViewport.m_Height));
+ }
+ }
+
+ void SetupCubeShadowCameras(const SLight *inLight, SCamera inCameras[6])
+ {
+ // setup light matrix
+ QT3DSU32 mapRes = 1 << inLight->m_ShadowMapRes;
+ NVRenderRectF theViewport(0.0f, 0.0f, (float)mapRes, (float)mapRes);
+ QT3DSVec3 rotOfs[6];
+
+ QT3DS_ASSERT(inLight != NULL);
+ QT3DS_ASSERT(inLight->m_LightType != RenderLightTypes::Directional);
+
+ QT3DSVec3 inLightPos = inLight->GetGlobalPos();
+ if (inLight->m_Flags.IsLeftHanded())
+ inLightPos.z = -inLightPos.z;
+
+ rotOfs[0] = QT3DSVec3(0.f, -NVHalfPi, NVPi);
+ rotOfs[1] = QT3DSVec3(0.f, NVHalfPi, NVPi);
+ rotOfs[2] = QT3DSVec3(NVHalfPi, 0.f, 0.f);
+ rotOfs[3] = QT3DSVec3(-NVHalfPi, 0.f, 0.f);
+ rotOfs[4] = QT3DSVec3(0.f, NVPi, -NVPi);
+ rotOfs[5] = QT3DSVec3(0.f, 0.f, NVPi);
+
+ for (int i = 0; i < 6; ++i) {
+ inCameras[i].m_Flags.SetLeftHanded(false);
+
+ inCameras[i].m_Flags.ClearOrSet(false, NodeFlagValues::Orthographic);
+ inCameras[i].m_Parent = NULL;
+ inCameras[i].m_Pivot = inLight->m_Pivot;
+ inCameras[i].m_ClipNear = 1.0f;
+ inCameras[i].m_ClipFar = NVMax<QT3DSF32>(2.0f, inLight->m_ShadowMapFar);
+ inCameras[i].m_FOV = inLight->m_ShadowMapFov * QT3DS_DEGREES_TO_RADIANS;
+
+ inCameras[i].m_Position = inLightPos;
+ inCameras[i].m_Rotation = rotOfs[i];
+ inCameras[i].CalculateGlobalVariables(
+ theViewport, QT3DSVec2(theViewport.m_Width, theViewport.m_Height));
+ }
+
+ /*
+ if ( inLight->m_LightType == RenderLightTypes::Point ) return;
+
+ QT3DSVec3 viewDirs[6];
+ QT3DSVec3 viewUp[6];
+ QT3DSMat33 theDirMatrix( inLight->m_GlobalTransform.getUpper3x3() );
+
+ viewDirs[0] = theDirMatrix.transform( QT3DSVec3( 1.f, 0.f, 0.f ) );
+ viewDirs[2] = theDirMatrix.transform( QT3DSVec3( 0.f, -1.f, 0.f ) );
+ viewDirs[4] = theDirMatrix.transform( QT3DSVec3( 0.f, 0.f, 1.f ) );
+ viewDirs[0].normalize(); viewDirs[2].normalize(); viewDirs[4].normalize();
+ viewDirs[1] = -viewDirs[0];
+ viewDirs[3] = -viewDirs[2];
+ viewDirs[5] = -viewDirs[4];
+
+ viewUp[0] = viewDirs[2];
+ viewUp[1] = viewDirs[2];
+ viewUp[2] = viewDirs[5];
+ viewUp[3] = viewDirs[4];
+ viewUp[4] = viewDirs[2];
+ viewUp[5] = viewDirs[2];
+
+ for (int i = 0; i < 6; ++i)
+ {
+ inCameras[i].LookAt( inLightPos, viewUp[i], inLightPos + viewDirs[i] );
+ inCameras[i].CalculateGlobalVariables( theViewport, QT3DSVec2( theViewport.m_Width,
+ theViewport.m_Height ) );
+ }
+ */
+ }
+
+ inline void RenderRenderableShadowMapPass(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet,
+ QT3DSU32 lightIndex, const SCamera &inCamera)
+ {
+ if (!inObject.m_RenderableFlags.IsShadowCaster())
+ return;
+
+ SShadowMapEntry *pEntry = inData.m_ShadowMapManager->GetShadowMapEntry(lightIndex);
+
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ static_cast<SSubsetRenderableBase &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).RenderShadowMapPass(
+ inCameraProps, inData.m_Lights[lightIndex], inCamera, pEntry);
+ }
+ }
+
+ void SLayerRenderData::RenderShadowCubeBlurPass(CResourceFrameBuffer *theFB,
+ NVRenderTextureCube *target0,
+ NVRenderTextureCube *target1, QT3DSF32 filterSz,
+ QT3DSF32 clipFar)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+
+ SShadowmapPreblurShader *shaderX = m_Renderer.GetCubeShadowBlurXShader();
+ SShadowmapPreblurShader *shaderY = m_Renderer.GetCubeShadowBlurYShader();
+
+ if (shaderX == NULL)
+ return;
+ if (shaderY == NULL)
+ return;
+ // if ( theShader == NULL ) return;
+
+ // Enable drawing to 6 color attachment buffers for cubemap passes
+ qt3ds::QT3DSI32 buffers[6] = { 0, 1, 2, 3, 4, 5 };
+ qt3ds::foundation::NVConstDataRef<qt3ds::QT3DSI32> bufferList(buffers, 6);
+ theContext.SetDrawBuffers(bufferList);
+
+ // Attach framebuffer targets
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, *target1,
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, *target1,
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, *target1,
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, *target1,
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, *target1,
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, *target1,
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ // theContext.SetColorWritesEnabled(true);
+ theContext.SetActiveShader(&(shaderX->m_Shader));
+
+ shaderX->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderX->m_DepthCube.Set(target0);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetActiveShader(&(shaderY->m_Shader));
+
+ // Lather, Rinse, and Repeat for the Y-blur pass
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, *target0,
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, *target0,
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, *target0,
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, *target0,
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, *target0,
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, *target0,
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ shaderY->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderY->m_DepthCube.Set(target1);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetDepthWriteEnabled(true);
+ theContext.SetDepthTestEnabled(true);
+ // theContext.SetColorWritesEnabled(false);
+
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color1, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegX);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color2, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color3, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegY);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color4, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubePosZ);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color5, NVRenderTextureOrRenderBuffer(),
+ NVRenderTextureCubeFaces::CubeNegZ);
+
+ theContext.SetDrawBuffers(qt3ds::foundation::toConstDataRef((qt3ds::QT3DSI32)0));
+ }
+
+ void SLayerRenderData::RenderShadowMapBlurPass(CResourceFrameBuffer *theFB,
+ NVRenderTexture2D *target0,
+ NVRenderTexture2D *target1, QT3DSF32 filterSz,
+ QT3DSF32 clipFar)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+
+ SShadowmapPreblurShader *shaderX = m_Renderer.GetOrthoShadowBlurXShader();
+ SShadowmapPreblurShader *shaderY = m_Renderer.GetOrthoShadowBlurYShader();
+
+ if (shaderX == NULL)
+ return;
+ if (shaderY == NULL)
+ return;
+
+ // Attach framebuffer target
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *target1);
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil, *target1 );
+
+ // Set initial state
+ theContext.SetBlendingEnabled(false);
+ theContext.SetDepthWriteEnabled(false);
+ theContext.SetDepthTestEnabled(false);
+ theContext.SetColorWritesEnabled(true);
+ theContext.SetActiveShader(&(shaderX->m_Shader));
+
+ shaderX->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderX->m_DepthMap.Set(target0);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *target0);
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil, *target0 );
+ theContext.SetActiveShader(&(shaderY->m_Shader));
+
+ shaderY->m_CameraProperties.Set(QT3DSVec2(filterSz, clipFar));
+ shaderY->m_DepthMap.Set(target1);
+
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+
+ theContext.SetDepthWriteEnabled(true);
+ theContext.SetDepthTestEnabled(true);
+ theContext.SetColorWritesEnabled(false);
+
+ //(*theFB)->Attach( NVRenderFrameBufferAttachments::DepthStencil,
+ //NVRenderTextureOrRenderBuffer() );
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer());
+ }
+
+ void SLayerRenderData::RenderShadowMapPass(CResourceFrameBuffer *theFB)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::RenderShadowMapPass");
+
+ if (m_Camera == NULL || !GetShadowMapManager())
+ return;
+
+ // Check if we have anything to render
+ if (m_OpaqueObjects.size() == 0 || m_Lights.size() == 0)
+ return;
+
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+
+ // we may change the viewport
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theRenderContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+
+ // disable color writes
+ // theRenderContext.SetColorWritesEnabled( false );
+ theRenderContext.SetColorWritesEnabled(true);
+ theRenderContext.SetDepthWriteEnabled(true);
+ theRenderContext.SetCullingEnabled(false);
+ theRenderContext.SetClearColor(QT3DSVec4(1.0f));
+
+ // we render the shadow map with a slight offset to prevent shadow acne and cull the front
+ // faces
+ NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rsdefaultstate =
+ theRenderContext.CreateRasterizerState(0.0, 0.0, qt3ds::render::NVRenderFaces::Back);
+ NVScopedRefCounted<qt3ds::render::NVRenderRasterizerState> rsstate =
+ theRenderContext.CreateRasterizerState(1.5, 2.0, qt3ds::render::NVRenderFaces::Front);
+ theRenderContext.SetRasterizerState(rsstate);
+
+ qt3ds::render::NVRenderClearFlags clearFlags(qt3ds::render::NVRenderClearValues::Depth
+ | qt3ds::render::NVRenderClearValues::Stencil
+ | qt3ds::render::NVRenderClearValues::Color);
+
+ for (QT3DSU32 i = 0; i < m_Lights.size(); i++) {
+ // don't render shadows when not casting
+ if (m_Lights[i]->m_CastShadow == false)
+ continue;
+ SShadowMapEntry *pEntry = m_ShadowMapManager->GetShadowMapEntry(i);
+ if (pEntry && pEntry->m_DepthMap && pEntry->m_DepthCopy && pEntry->m_DepthRender) {
+ SCamera theCamera;
+
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ SetupCameraForShadowMap(theCameraProps, m_Renderer.GetContext(),
+ __viewport.m_InitialValue, *m_Camera,
+ m_Lights[i], theCamera);
+ // we need this matrix for the final rendering
+ theCamera.CalculateViewProjectionMatrix(pEntry->m_LightVP);
+ pEntry->m_LightView = theCamera.m_GlobalTransform.getInverse();
+
+ STextureDetails theDetails(pEntry->m_DepthMap->GetTextureDetails());
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)theDetails.m_Width, (QT3DSU32)theDetails.m_Height));
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, *pEntry->m_DepthMap);
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ *pEntry->m_DepthRender);
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableShadowMapPass, false, true, true, i, theCamera);
+ RenderShadowMapBlurPass(theFB, pEntry->m_DepthMap, pEntry->m_DepthCopy,
+ m_Lights[i]->m_ShadowFilter, m_Lights[i]->m_ShadowMapFar);
+ } else if (pEntry && pEntry->m_DepthCube && pEntry->m_CubeCopy
+ && pEntry->m_DepthRender) {
+ SCamera theCameras[6];
+
+ SetupCubeShadowCameras(m_Lights[i], theCameras);
+
+ // pEntry->m_LightView = m_Lights[i]->m_LightType == RenderLightTypes::Point ?
+ // QT3DSMat44::createIdentity()
+ // : m_Lights[i]->m_GlobalTransform;
+ pEntry->m_LightView = QT3DSMat44::createIdentity();
+
+ STextureDetails theDetails(pEntry->m_DepthCube->GetTextureDetails());
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)theDetails.m_Width, (QT3DSU32)theDetails.m_Height));
+
+ // int passes = m_Lights[i]->m_LightType == RenderLightTypes::Point ? 6 : 5;
+ int passes = 6;
+ for (int k = 0; k < passes; ++k) {
+ // theCameras[k].CalculateViewProjectionMatrix( pEntry->m_LightCubeVP[k] );
+ pEntry->m_LightCubeView[k] = theCameras[k].m_GlobalTransform.getInverse();
+ theCameras[k].CalculateViewProjectionMatrix(pEntry->m_LightVP);
+
+ // Geometry shader multiplication really doesn't work unless you have a
+ // 6-layered 3D depth texture...
+ // Otherwise, you have no way to depth test while rendering...
+ // which more or less completely defeats the purpose of having a cubemap render
+ // target.
+ NVRenderTextureCubeFaces::Enum curFace =
+ (NVRenderTextureCubeFaces::Enum)(k + 1);
+ //(*theFB)->AttachFace( NVRenderFrameBufferAttachments::DepthStencil,
+ //*pEntry->m_DepthCube, curFace );
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::DepthStencil,
+ *pEntry->m_DepthRender);
+ (*theFB)->AttachFace(NVRenderFrameBufferAttachments::Color0,
+ *pEntry->m_DepthCube, curFace);
+ (*theFB)->IsComplete();
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableShadowMapPass, false, true, true, i,
+ theCameras[k]);
+ }
+
+ RenderShadowCubeBlurPass(theFB, pEntry->m_DepthCube, pEntry->m_CubeCopy,
+ m_Lights[i]->m_ShadowFilter, m_Lights[i]->m_ShadowMapFar);
+ }
+ }
+
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Depth, NVRenderTextureOrRenderBuffer());
+ (*theFB)->Attach(NVRenderFrameBufferAttachments::Color0, NVRenderTextureOrRenderBuffer());
+
+ // enable color writes
+ theRenderContext.SetColorWritesEnabled(true);
+ theRenderContext.SetCullingEnabled(true);
+ theRenderContext.SetClearColor(QT3DSVec4(0.0f));
+ // reset rasterizer state
+ theRenderContext.SetRasterizerState(rsdefaultstate);
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ inline void RenderRenderableDepthPass(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet, QT3DSU32,
+ const SCamera &inCamera)
+ {
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset()) {
+ static_cast<SSubsetRenderable &>(inObject).RenderDepthPass(inCameraProps);
+ } else if (inObject.m_RenderableFlags.IsText()) {
+ static_cast<STextRenderable &>(inObject).RenderDepthPass(inCameraProps);
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ } else if (inObject.m_RenderableFlags.isDistanceField()) {
+ static_cast<SDistanceFieldRenderable &>(inObject).RenderDepthPass(inCameraProps);
+#endif
+ } else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ static_cast<SCustomMaterialRenderable &>(inObject).RenderDepthPass(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera, NULL);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).RenderDepthPass(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera, NULL);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ void SLayerRenderData::RenderDepthPass(bool inEnableTransparentDepthWrite)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::RenderDepthPass");
+ if (m_Camera == NULL)
+ return;
+
+ // Avoid running this method if possible.
+ if ((inEnableTransparentDepthWrite == false
+ && (m_OpaqueObjects.size() == 0
+ || m_Layer.m_Flags.IsLayerEnableDepthPrepass() == false))
+ || m_Layer.m_Flags.IsLayerEnableDepthTest() == false)
+ return;
+
+ m_Renderer.BeginLayerDepthPassRender(*this);
+
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+
+ // disable color writes
+ theRenderContext.SetColorWritesEnabled(false);
+ theRenderContext.SetDepthWriteEnabled(true);
+
+ qt3ds::render::NVRenderClearFlags clearFlags(qt3ds::render::NVRenderClearValues::Stencil
+ | qt3ds::render::NVRenderClearValues::Depth);
+ theRenderContext.Clear(clearFlags);
+
+ RunRenderPass(RenderRenderableDepthPass, false, true, inEnableTransparentDepthWrite, 0,
+ *m_Camera);
+
+ // enable color writes
+ theRenderContext.SetColorWritesEnabled(true);
+
+ m_Renderer.EndLayerDepthPassRender();
+ }
+
+ inline void RenderRenderable(SLayerRenderData &inData, SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps, TShaderFeatureSet inFeatureSet, QT3DSU32,
+ const SCamera &inCamera)
+ {
+ if (inObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ static_cast<SSubsetRenderable &>(inObject).Render(inCameraProps, inFeatureSet);
+ else if (inObject.m_RenderableFlags.IsText())
+ static_cast<STextRenderable &>(inObject).Render(inCameraProps);
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ else if (inObject.m_RenderableFlags.isDistanceField())
+ static_cast<SDistanceFieldRenderable &>(inObject).Render(inCameraProps);
+#endif
+ else if (inObject.m_RenderableFlags.IsCustomMaterialMeshSubset()) {
+ // PKC : Need a better place to do this.
+ SCustomMaterialRenderable &theObject =
+ static_cast<SCustomMaterialRenderable &>(inObject);
+ if (!inData.m_Layer.m_LightProbe && theObject.m_Material.m_IblProbe)
+ inData.SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE",
+ theObject.m_Material.m_IblProbe->m_TextureData.m_Texture
+ != NULL);
+ else if (inData.m_Layer.m_LightProbe)
+ inData.SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE",
+ inData.m_Layer.m_LightProbe->m_TextureData.m_Texture
+ != NULL);
+
+ static_cast<SCustomMaterialRenderable &>(inObject).Render(
+ inCameraProps, inData, inData.m_Layer, inData.m_Lights, inCamera,
+ inData.m_LayerDepthTexture, inData.m_LayerSsaoTexture, inFeatureSet);
+ } else if (inObject.m_RenderableFlags.IsPath()) {
+ static_cast<SPathRenderable &>(inObject).Render(
+ inCameraProps, inData.m_Layer, inData.m_Lights, inCamera,
+ inData.m_LayerDepthTexture, inData.m_LayerSsaoTexture, inFeatureSet);
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ }
+
+ void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn,
+ bool inEnableBlending, bool inEnableDepthWrite,
+ bool inEnableTransparentDepthWrite, QT3DSU32 indexLight,
+ const SCamera &inCamera, CResourceFrameBuffer *theFB)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ theRenderContext.SetDepthFunction(qt3ds::render::NVRenderBoolOp::LessThanOrEqual);
+ theRenderContext.SetBlendingEnabled(false);
+ QT3DSVec2 theCameraProps = QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar);
+ NVDataRef<SRenderableObject *> theOpaqueObjects = GetOpaqueRenderableObjects();
+ bool usingDepthBuffer =
+ m_Layer.m_Flags.IsLayerEnableDepthTest() && theOpaqueObjects.size() > 0;
+
+ if (usingDepthBuffer) {
+ theRenderContext.SetDepthTestEnabled(true);
+ theRenderContext.SetDepthWriteEnabled(inEnableDepthWrite);
+ } else {
+ theRenderContext.SetDepthWriteEnabled(false);
+ theRenderContext.SetDepthTestEnabled(false);
+ }
+
+ for (QT3DSU32 idx = 0, end = theOpaqueObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theOpaqueObjects[idx]);
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(), indexLight,
+ inCamera);
+ }
+
+ // transparent objects
+ if (inEnableBlending || m_Layer.m_Flags.IsLayerEnableDepthTest() == false) {
+ theRenderContext.SetBlendingEnabled(true && inEnableBlending);
+ theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite);
+
+ NVDataRef<SRenderableObject *> theTransparentObjects = GetTransparentRenderableObjects();
+ // Assume all objects have transparency if the layer's depth test enabled flag is true.
+ if (m_Layer.m_Flags.IsLayerEnableDepthTest() == true) {
+ for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theTransparentObjects[idx]);
+ if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) {
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ // SW fallback for advanced blend modes.
+ // Renders transparent objects to a separate FBO and blends them in shader
+ // with the opaque items and background.
+ DefaultMaterialBlendMode::Enum blendMode
+ = DefaultMaterialBlendMode::Enum::Normal;
+ if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode();
+ bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay ||
+ blendMode == DefaultMaterialBlendMode::ColorBurn ||
+ blendMode == DefaultMaterialBlendMode::ColorDodge) &&
+ !theRenderContext.IsAdvancedBlendHwSupported() &&
+ !theRenderContext.IsAdvancedBlendHwSupportedKHR() &&
+ m_LayerPrepassDepthTexture;
+ if (useBlendFallback)
+ SetupDrawFB(true);
+#endif
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections,
+ m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(),
+ indexLight, inCamera);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ // SW fallback for advanced blend modes.
+ // Continue blending after transparent objects have been rendered to a FBO
+ if (useBlendFallback) {
+ BlendAdvancedToFB(blendMode, true, theFB);
+ // restore blending status
+ theRenderContext.SetBlendingEnabled(inEnableBlending);
+ // restore depth test status
+ theRenderContext.SetDepthTestEnabled(usingDepthBuffer);
+ theRenderContext.SetDepthWriteEnabled(inEnableTransparentDepthWrite);
+ }
+#endif
+ }
+ }
+ }
+ // If the layer doesn't have depth enabled then we have to render via an alternate route
+ // where the transparent objects vector could have both opaque and transparent objects.
+ else {
+ for (QT3DSU32 idx = 0, end = theTransparentObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theObject(*theTransparentObjects[idx]);
+ if (!(theObject.m_RenderableFlags.IsCompletelyTransparent())) {
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ DefaultMaterialBlendMode::Enum blendMode
+ = DefaultMaterialBlendMode::Enum::Normal;
+ if (theObject.m_RenderableFlags.IsDefaultMaterialMeshSubset())
+ blendMode = static_cast<SSubsetRenderable &>(theObject).getBlendingMode();
+ bool useBlendFallback = (blendMode == DefaultMaterialBlendMode::Overlay ||
+ blendMode == DefaultMaterialBlendMode::ColorBurn ||
+ blendMode == DefaultMaterialBlendMode::ColorDodge) &&
+ !theRenderContext.IsAdvancedBlendHwSupported() &&
+ !theRenderContext.IsAdvancedBlendHwSupportedKHR();
+
+ if (theObject.m_RenderableFlags.HasTransparency()) {
+ theRenderContext.SetBlendingEnabled(true && inEnableBlending);
+ // If we have SW fallback for blend mode, render to a FBO and blend back.
+ // Slow as this must be done per-object (transparent and opaque items
+ // are mixed, not batched)
+ if (useBlendFallback)
+ SetupDrawFB(false);
+ }
+#endif
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections,
+ m_SourceLightDirections,
+ theObject.m_ScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+ inRenderFn(*this, theObject, theCameraProps, GetShaderFeatureSet(),
+ indexLight, inCamera);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ if (useBlendFallback) {
+ BlendAdvancedToFB(blendMode, false, theFB);
+ // restore blending status
+ theRenderContext.SetBlendingEnabled(inEnableBlending);
+
+ }
+#endif
+ }
+ }
+ }
+ }
+ }
+
+ void SLayerRenderData::Render(CResourceFrameBuffer *theFB)
+ {
+ SStackPerfTimer ___timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::Render");
+ if (m_Camera == NULL)
+ return;
+
+ m_Renderer.BeginLayerRender(*this);
+ RunRenderPass(RenderRenderable, true, !m_Layer.m_Flags.IsLayerEnableDepthPrepass(), false,
+ 0, *m_Camera, theFB);
+ m_Renderer.EndLayerRender();
+ }
+
+ void SLayerRenderData::CreateGpuProfiler()
+ {
+ if (m_Renderer.GetContext().IsTimerQuerySupported()) {
+ m_LayerProfilerGpu = IRenderProfiler::CreateGpuProfiler(
+ m_Renderer.GetContext().GetFoundation(), m_Renderer.GetQt3DSContext(),
+ m_Renderer.GetContext());
+ }
+ }
+
+ void SLayerRenderData::StartProfiling(CRegisteredString &nameID, bool sync)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->StartTimer(nameID, false, sync);
+ }
+ }
+
+ void SLayerRenderData::EndProfiling(CRegisteredString &nameID)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->EndTimer(nameID);
+ }
+ }
+
+ void SLayerRenderData::StartProfiling(const char *nameID, bool sync)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ CRegisteredString theStr(
+ m_Renderer.GetQt3DSContext().GetStringTable().RegisterStr(nameID));
+ m_LayerProfilerGpu->StartTimer(theStr, false, sync);
+ }
+ }
+
+ void SLayerRenderData::EndProfiling(const char *nameID)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ CRegisteredString theStr(
+ m_Renderer.GetQt3DSContext().GetStringTable().RegisterStr(nameID));
+ m_LayerProfilerGpu->EndTimer(theStr);
+ }
+ }
+
+ void SLayerRenderData::AddVertexCount(QT3DSU32 count)
+ {
+ if (m_LayerProfilerGpu.mPtr) {
+ m_LayerProfilerGpu->AddVertexCount(count);
+ }
+ }
+
+ // Assumes the viewport is setup appropriately to render the widget.
+ void SLayerRenderData::RenderRenderWidgets()
+ {
+ if (m_Camera) {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ for (QT3DSU32 idx = 0, end = m_IRenderWidgets.size(); idx < end; ++idx) {
+ IRenderWidget &theWidget = *m_IRenderWidgets[idx];
+ theWidget.Render(m_Renderer, theContext);
+ }
+ }
+ }
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ void SLayerRenderData::BlendAdvancedEquationSwFallback(NVRenderTexture2D *drawTexture,
+ NVRenderTexture2D *layerTexture,
+ AdvancedBlendModes::Enum blendMode)
+ {
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SAdvancedModeBlendShader *shader = m_Renderer.GetAdvancedBlendModeShader(blendMode);
+ if (shader == NULL)
+ return;
+
+ theContext.SetActiveShader(&(shader->m_Shader));
+
+ shader->m_baseLayer.Set(layerTexture);
+ shader->m_blendLayer.Set(drawTexture);
+ // Draw a fullscreen quad
+ m_Renderer.RenderQuad();
+ }
+
+ void SLayerRenderData::SetupDrawFB(bool depthEnabled)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ // create drawing FBO and texture, if not existing
+ if (!m_AdvancedModeDrawFB)
+ m_AdvancedModeDrawFB = theRenderContext.CreateFrameBuffer();
+ if (!m_AdvancedBlendDrawTexture) {
+ m_AdvancedBlendDrawTexture = theRenderContext.CreateTexture2D();
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ m_AdvancedBlendDrawTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theViewport.m_Width,
+ theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ m_AdvancedModeDrawFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ *m_AdvancedBlendDrawTexture);
+ // Use existing depth prepass information when rendering transparent objects to a FBO
+ if (depthEnabled)
+ m_AdvancedModeDrawFB->Attach(NVRenderFrameBufferAttachments::Depth,
+ *m_LayerPrepassDepthTexture);
+ }
+ theRenderContext.SetRenderTarget(m_AdvancedModeDrawFB);
+ // make sure that depth testing is on in order to render just the
+ // depth-passed objects (=transparent objects) and leave background intact
+ if (depthEnabled)
+ theRenderContext.SetDepthTestEnabled(true);
+ theRenderContext.SetBlendingEnabled(false);
+ // clear color commonly is the layer background, make sure that it is all-zero here
+ QT3DSVec4 originalClrColor = theRenderContext.GetClearColor();
+ theRenderContext.SetClearColor(QT3DSVec4(0.0));
+ theRenderContext.Clear(NVRenderClearValues::Color);
+ theRenderContext.SetClearColor(originalClrColor);
+
+ }
+ void SLayerRenderData::BlendAdvancedToFB(DefaultMaterialBlendMode::Enum blendMode,
+ bool depthEnabled, CResourceFrameBuffer *theFB)
+ {
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ AdvancedBlendModes::Enum advancedMode;
+
+ switch (blendMode) {
+ case DefaultMaterialBlendMode::Overlay:
+ advancedMode = AdvancedBlendModes::Overlay;
+ break;
+ case DefaultMaterialBlendMode::ColorBurn:
+ advancedMode = AdvancedBlendModes::ColorBurn;
+ break;
+ case DefaultMaterialBlendMode::ColorDodge:
+ advancedMode = AdvancedBlendModes::ColorDodge;
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ // create blending FBO and texture if not existing
+ if (!m_AdvancedModeBlendFB)
+ m_AdvancedModeBlendFB = theRenderContext.CreateFrameBuffer();
+ if (!m_AdvancedBlendBlendTexture) {
+ m_AdvancedBlendBlendTexture = theRenderContext.CreateTexture2D();
+ m_AdvancedBlendBlendTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theViewport.m_Width,
+ theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ m_AdvancedModeBlendFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ *m_AdvancedBlendBlendTexture);
+ }
+ theRenderContext.SetRenderTarget(m_AdvancedModeBlendFB);
+
+ // Blend transparent objects with SW fallback shaders.
+ // Disable depth testing as transparent objects have already been
+ // depth-checked; here we want to run shader for all layer pixels
+ if (depthEnabled)
+ {
+ theRenderContext.SetDepthTestEnabled(false);
+ theRenderContext.SetDepthWriteEnabled(false);
+ }
+ BlendAdvancedEquationSwFallback(m_AdvancedBlendDrawTexture, m_LayerTexture, advancedMode);
+ theRenderContext.SetRenderTarget(*theFB);
+ // setup read target
+ theRenderContext.SetReadTarget(m_AdvancedModeBlendFB);
+ theRenderContext.SetReadBuffer(NVReadFaces::Color0);
+ theRenderContext.BlitFramebuffer(0, 0, theViewport.m_Width, theViewport.m_Height,
+ 0, 0, theViewport.m_Width, theViewport.m_Height,
+ NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+ }
+#endif
+
+ void SLayerRenderData::RenderToViewport()
+ {
+ if (m_LayerPrepResult->IsLayerVisible()) {
+ if (GetOffscreenRenderer()) {
+ if (m_Layer.m_Background == LayerBackground::Color) {
+ m_LastFrameOffscreenRenderer->RenderWithClear(
+ CreateOffscreenRenderEnvironment(), m_Renderer.GetContext(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor(),
+ SScene::AlwaysClear, m_Layer.m_ClearColor, &m_Layer);
+ } else {
+ m_LastFrameOffscreenRenderer->Render(
+ CreateOffscreenRenderEnvironment(), m_Renderer.GetContext(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor(),
+ SScene::ClearIsOptional, &m_Layer);
+ }
+ } else {
+ RenderDepthPass(false);
+ Render();
+ RenderRenderWidgets();
+ }
+ }
+ }
+ // These are meant to be pixel offsets, so you need to divide them by the width/height
+ // of the layer respectively.
+ const QT3DSVec2 s_VertexOffsets[SLayerRenderPreparationData::MAX_AA_LEVELS] = {
+ QT3DSVec2(-0.170840f, -0.553840f), // 1x
+ QT3DSVec2(0.162960f, -0.319340f), // 2x
+ QT3DSVec2(0.360260f, -0.245840f), // 3x
+ QT3DSVec2(-0.561340f, -0.149540f), // 4x
+ QT3DSVec2(0.249460f, 0.453460f), // 5x
+ QT3DSVec2(-0.336340f, 0.378260f), // 6x
+ QT3DSVec2(0.340000f, 0.166260f), // 7x
+ QT3DSVec2(0.235760f, 0.527760f), // 8x
+ };
+
+ // Blend factors are in the form of (frame blend factor, accumulator blend factor)
+ const QT3DSVec2 s_BlendFactors[SLayerRenderPreparationData::MAX_AA_LEVELS] = {
+ QT3DSVec2(0.500000f, 0.500000f), // 1x
+ QT3DSVec2(0.333333f, 0.666667f), // 2x
+ QT3DSVec2(0.250000f, 0.750000f), // 3x
+ QT3DSVec2(0.200000f, 0.800000f), // 4x
+ QT3DSVec2(0.166667f, 0.833333f), // 5x
+ QT3DSVec2(0.142857f, 0.857143f), // 6x
+ QT3DSVec2(0.125000f, 0.875000f), // 7x
+ QT3DSVec2(0.111111f, 0.888889f), // 8x
+ };
+
+ const QT3DSVec2 s_TemporalVertexOffsets[SLayerRenderPreparationData::MAX_TEMPORAL_AA_LEVELS] = {
+ QT3DSVec2(.3f, .3f), QT3DSVec2(-.3f, -.3f)
+ };
+
+ static inline void OffsetProjectionMatrix(QT3DSMat44 &inProjectionMatrix, QT3DSVec2 inVertexOffsets)
+ {
+ inProjectionMatrix.column3.x =
+ inProjectionMatrix.column3.x + inProjectionMatrix.column3.w * inVertexOffsets.x;
+ inProjectionMatrix.column3.y =
+ inProjectionMatrix.column3.y + inProjectionMatrix.column3.w * inVertexOffsets.y;
+ }
+
+ CRegisteredString depthPassStr;
+
+ // Render this layer's data to a texture. Required if we have any effects,
+ // prog AA, or if forced.
+ void SLayerRenderData::RenderToTexture()
+ {
+ QT3DS_ASSERT(m_LayerPrepResult->m_Flags.ShouldRenderToTexture());
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderContext &theRenderContext(m_Renderer.GetContext());
+ QSize theLayerTextureDimensions = thePrepResult.GetTextureDimensions();
+ QSize theLayerOriginalTextureDimensions = theLayerTextureDimensions;
+ NVRenderTextureFormats::Enum DepthTextureFormat = NVRenderTextureFormats::Depth24Stencil8;
+ NVRenderTextureFormats::Enum ColorTextureFormat = NVRenderTextureFormats::RGBA8;
+ if (thePrepResult.m_LastEffect
+ && theRenderContext.GetRenderContextType() != NVRenderContextValues::GLES2) {
+ if (m_Layer.m_Background != LayerBackground::Transparent)
+ ColorTextureFormat = NVRenderTextureFormats::R11G11B10;
+ else
+ ColorTextureFormat = NVRenderTextureFormats::RGBA16F;
+ }
+ NVRenderTextureFormats::Enum ColorSSAOTextureFormat = NVRenderTextureFormats::RGBA8;
+
+ bool needsRender = false;
+ QT3DSU32 sampleCount = 1;
+ // check multsample mode and MSAA texture support
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::NoAA
+ && theRenderContext.AreMultisampleTexturesSupported())
+ sampleCount = (QT3DSU32)m_Layer.m_MultisampleAAMode;
+
+ bool isMultisamplePass = false;
+ if (theRenderContext.GetRenderContextType() != NVRenderContextValues::GLES2)
+ isMultisamplePass =
+ (sampleCount > 1) || (m_Layer.m_MultisampleAAMode == AAModeValues::SSAA);
+
+ qt3ds::render::NVRenderTextureTargetType::Enum thFboAttachTarget =
+ qt3ds::render::NVRenderTextureTargetType::Texture2D;
+
+ // If the user has disabled all layer caching this has the side effect of disabling the
+ // progressive AA algorithm.
+ if (thePrepResult.m_Flags.WasLayerDataDirty()
+ || thePrepResult.m_Flags.WasDirty()
+ || m_Renderer.IsLayerCachingEnabled() == false
+ || thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ needsRender = true;
+ }
+
+ CResourceTexture2D *renderColorTexture = &m_LayerTexture;
+ CResourceTexture2D *renderPrepassDepthTexture = &m_LayerPrepassDepthTexture;
+ CResourceTexture2D *renderWidgetTexture = &m_LayerWidgetTexture;
+ NVRenderContextScopedProperty<bool> __multisampleEnabled(
+ theRenderContext, &NVRenderContext::IsMultisampleEnabled,
+ &NVRenderContext::SetMultisampleEnabled);
+ theRenderContext.SetMultisampleEnabled(false);
+ if (isMultisamplePass) {
+ renderColorTexture = &m_LayerMultisampleTexture;
+ renderPrepassDepthTexture = &m_LayerMultisamplePrepassDepthTexture;
+ renderWidgetTexture = &m_LayerMultisampleWidgetTexture;
+ // for SSAA we don't use MS textures
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::SSAA)
+ thFboAttachTarget = qt3ds::render::NVRenderTextureTargetType::Texture2D_MS;
+ }
+ QT3DSU32 maxTemporalPassIndex = m_Layer.m_TemporalAAEnabled ? 2 : 0;
+
+ // If all the dimensions match then we do not have to re-render the layer.
+ if (m_LayerTexture.TextureMatches(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(), ColorTextureFormat)
+ && (!thePrepResult.m_Flags.RequiresDepthTexture()
+ || m_LayerDepthTexture.TextureMatches(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ DepthTextureFormat))
+ && m_ProgressiveAAPassIndex >= thePrepResult.m_MaxAAPassIndex
+ && m_NonDirtyTemporalAAPassIndex >= maxTemporalPassIndex && needsRender == false) {
+ return;
+ }
+
+ // adjust render size for SSAA
+ if (m_Layer.m_MultisampleAAMode == AAModeValues::SSAA) {
+ QT3DSU32 ow, oh;
+ CRendererUtil::GetSSAARenderSize(theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(),
+ ow, oh);
+ theLayerTextureDimensions = QSize(ow, oh);
+ }
+
+ // If our pass index == thePreResult.m_MaxAAPassIndex then
+ // we shouldn't get into here.
+
+ IResourceManager &theResourceManager = m_Renderer.GetQt3DSContext().GetResourceManager();
+ bool hadLayerTexture = true;
+
+ if (renderColorTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ ColorTextureFormat, sampleCount)) {
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ hadLayerTexture = false;
+ }
+
+ if (thePrepResult.m_Flags.RequiresDepthTexture()) {
+ // The depth texture doesn't need to be multisample, the prepass depth does.
+ if (m_LayerDepthTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ DepthTextureFormat)) {
+ // Depth textures are generally not bilinear filtered.
+ m_LayerDepthTexture->SetMinFilter(NVRenderTextureMinifyingOp::Nearest);
+ m_LayerDepthTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Nearest);
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ }
+ }
+
+ if (thePrepResult.m_Flags.RequiresSsaoPass()) {
+ if (m_LayerSsaoTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ ColorSSAOTextureFormat)) {
+ m_LayerSsaoTexture->SetMinFilter(NVRenderTextureMinifyingOp::Linear);
+ m_LayerSsaoTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Linear);
+ m_ProgressiveAAPassIndex = 0;
+ m_NonDirtyTemporalAAPassIndex = 0;
+ }
+ }
+
+ QT3DS_ASSERT(!thePrepResult.m_Flags.RequiresDepthTexture() || m_LayerDepthTexture);
+ QT3DS_ASSERT(!thePrepResult.m_Flags.RequiresSsaoPass() || m_LayerSsaoTexture);
+
+ CResourceTexture2D theLastLayerTexture(theResourceManager);
+ SLayerProgAABlendShader *theBlendShader = NULL;
+ QT3DSU32 aaFactorIndex = 0;
+ bool isProgressiveAABlendPass =
+ m_ProgressiveAAPassIndex && m_ProgressiveAAPassIndex < thePrepResult.m_MaxAAPassIndex;
+ bool isTemporalAABlendPass = m_Layer.m_TemporalAAEnabled && m_ProgressiveAAPassIndex == 0;
+
+ if (isProgressiveAABlendPass || isTemporalAABlendPass) {
+ theBlendShader = m_Renderer.GetLayerProgAABlendShader();
+ if (theBlendShader) {
+ m_LayerTexture.EnsureTexture(theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(),
+ ColorTextureFormat);
+ QT3DSVec2 theVertexOffsets;
+ if (isProgressiveAABlendPass) {
+ theLastLayerTexture.StealTexture(m_LayerTexture);
+ aaFactorIndex = (m_ProgressiveAAPassIndex - 1);
+ theVertexOffsets = s_VertexOffsets[aaFactorIndex];
+ } else {
+ if (m_TemporalAATexture.GetTexture())
+ theLastLayerTexture.StealTexture(m_TemporalAATexture);
+ else {
+ if (hadLayerTexture) {
+ theLastLayerTexture.StealTexture(m_LayerTexture);
+ }
+ }
+ theVertexOffsets = s_TemporalVertexOffsets[m_TemporalAAPassIndex];
+ ++m_TemporalAAPassIndex;
+ ++m_NonDirtyTemporalAAPassIndex;
+ m_TemporalAAPassIndex = m_TemporalAAPassIndex % MAX_TEMPORAL_AA_LEVELS;
+ }
+ if (theLastLayerTexture.GetTexture()) {
+ theVertexOffsets.x =
+ theVertexOffsets.x / (theLayerOriginalTextureDimensions.width() / 2.0f);
+ theVertexOffsets.y =
+ theVertexOffsets.y / (theLayerOriginalTextureDimensions.height() / 2.0f);
+ // Run through all models and update MVP.
+ // run through all texts and update MVP.
+ // run through all path and update MVP.
+
+ // TODO - optimize this exact matrix operation.
+ for (QT3DSU32 idx = 0, end = m_ModelContexts.size(); idx < end; ++idx) {
+ QT3DSMat44 &originalProjection(m_ModelContexts[idx]->m_ModelViewProjection);
+ OffsetProjectionMatrix(originalProjection, theVertexOffsets);
+ }
+ for (QT3DSU32 idx = 0, end = m_OpaqueObjects.size(); idx < end; ++idx) {
+ if (m_OpaqueObjects[idx]->m_RenderableFlags.IsPath()) {
+ SPathRenderable &theRenderable =
+ static_cast<SPathRenderable &>(*m_OpaqueObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+ }
+ }
+ for (QT3DSU32 idx = 0, end = m_TransparentObjects.size(); idx < end; ++idx) {
+ if (m_TransparentObjects[idx]->m_RenderableFlags.IsText()) {
+ STextRenderable &theRenderable =
+ static_cast<STextRenderable &>(*m_TransparentObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ } else if (m_TransparentObjects[idx]->m_RenderableFlags
+ .isDistanceField()) {
+ SDistanceFieldRenderable &theRenderable
+ = static_cast<SDistanceFieldRenderable &>(
+ *m_TransparentObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_mvp,
+ theVertexOffsets);
+#endif
+ } else if (m_TransparentObjects[idx]->m_RenderableFlags.IsPath()) {
+ SPathRenderable &theRenderable =
+ static_cast<SPathRenderable &>(*m_TransparentObjects[idx]);
+ OffsetProjectionMatrix(theRenderable.m_ModelViewProjection,
+ theVertexOffsets);
+ }
+ }
+ }
+ }
+ }
+ if (theLastLayerTexture.GetTexture() == NULL) {
+ isProgressiveAABlendPass = false;
+ isTemporalAABlendPass = false;
+ }
+ // Sometimes we will have stolen the render texture.
+ renderColorTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(), ColorTextureFormat,
+ sampleCount);
+
+ if (!isTemporalAABlendPass)
+ m_TemporalAATexture.ReleaseTexture();
+
+ // Allocating a frame buffer can cause it to be bound, so we need to save state before this
+ // happens.
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __framebuf(
+ theRenderContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ // Match the bit depth of the current render target to avoid popping when we switch from aa
+ // to non aa layers
+ // We have to all this here in because once we change the FB by allocating an FB we are
+ // screwed.
+ NVRenderTextureFormats::Enum theDepthFormat(GetDepthBufferFormat());
+ NVRenderFrameBufferAttachments::Enum theDepthAttachmentFormat(
+ GetFramebufferDepthAttachmentFormat(theDepthFormat));
+
+ // Definitely disable the scissor rect if it is running right now.
+ NVRenderContextScopedProperty<bool> __scissorEnabled(
+ theRenderContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled, false);
+ CResourceFrameBuffer theFB(theResourceManager);
+ // Allocates the frame buffer which has the side effect of setting the current render target
+ // to that frame buffer.
+ theFB.EnsureFrameBuffer();
+
+ bool hasDepthObjects = m_OpaqueObjects.size() > 0;
+ bool requiresDepthStencilBuffer =
+ hasDepthObjects || thePrepResult.m_Flags.RequiresStencilBuffer();
+ NVRenderRect theNewViewport(0, 0, theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height());
+ {
+ theRenderContext.SetRenderTarget(theFB);
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theRenderContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport,
+ theNewViewport);
+ QT3DSVec4 clearColor(0.0f);
+ if (m_Layer.m_Background == LayerBackground::Color)
+ clearColor = m_Layer.m_ClearColor;
+
+ NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
+ theRenderContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
+ clearColor);
+ if (requiresDepthStencilBuffer) {
+ if (renderPrepassDepthTexture->EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ theDepthFormat, sampleCount)) {
+ (*renderPrepassDepthTexture)->SetMinFilter(NVRenderTextureMinifyingOp::Nearest);
+ (*renderPrepassDepthTexture)
+ ->SetMagFilter(NVRenderTextureMagnifyingOp::Nearest);
+ }
+ }
+
+ if (thePrepResult.m_Flags.RequiresDepthTexture() && m_ProgressiveAAPassIndex == 0) {
+ // Setup FBO with single depth buffer target.
+ // Note this does not use multisample.
+ NVRenderFrameBufferAttachments::Enum theAttachment =
+ GetFramebufferDepthAttachmentFormat(DepthTextureFormat);
+ theFB->Attach(theAttachment, *m_LayerDepthTexture);
+
+ // In this case transparent objects also may write their depth.
+ RenderDepthPass(true);
+ theFB->Attach(theAttachment, NVRenderTextureOrRenderBuffer());
+ }
+
+ if (thePrepResult.m_Flags.RequiresSsaoPass() && m_ProgressiveAAPassIndex == 0
+ && m_Camera != nullptr) {
+ StartProfiling("AO pass", false);
+ // Setup FBO with single color buffer target
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerSsaoTexture);
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ RenderAoPass();
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer());
+ EndProfiling("AO pass");
+ }
+
+ if (thePrepResult.m_Flags.RequiresShadowMapPass() && m_ProgressiveAAPassIndex == 0) {
+ // shadow map path
+ RenderShadowMapPass(&theFB);
+ }
+
+ if (sampleCount > 1) {
+ theRenderContext.SetMultisampleEnabled(true);
+ }
+
+ qt3ds::render::NVRenderClearFlags clearFlags = qt3ds::render::NVRenderClearValues::Color;
+
+ // render depth prepass
+ if ((*renderPrepassDepthTexture)) {
+ theFB->Attach(theDepthAttachmentFormat, **renderPrepassDepthTexture,
+ thFboAttachTarget);
+
+ if (m_Layer.m_Flags.IsLayerEnableDepthPrepass()) {
+ StartProfiling("Depth pass", false);
+ RenderDepthPass(false);
+ EndProfiling("Depth pass");
+ } else {
+ clearFlags |= (qt3ds::render::NVRenderClearValues::Depth);
+ clearFlags |= (qt3ds::render::NVRenderClearValues::Stencil);
+ // enable depth write for the clear below
+ theRenderContext.SetDepthWriteEnabled(true);
+ }
+ }
+
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, **renderColorTexture,
+ thFboAttachTarget);
+ if (m_Layer.m_Background != LayerBackground::Unspecified)
+ theRenderContext.Clear(clearFlags);
+
+ // We don't clear the depth buffer because the layer render code we are about to call
+ // will do this.
+ StartProfiling("Render pass", false);
+ Render(&theFB);
+ // Debug measure to view the depth map to ensure we're rendering it correctly.
+ //if (m_Layer.m_TemporalAAEnabled) {
+ // RenderFakeDepthMapPass(m_ShadowMapManager->GetShadowMapEntry(0)->m_DepthMap,
+ // m_ShadowMapManager->GetShadowMapEntry(0)->m_DepthCube);
+ //}
+ EndProfiling("Render pass");
+
+ // Now before going further, we downsample and resolve the multisample information.
+ // This allows all algorithms running after
+ // this point to run unchanged.
+ if (isMultisamplePass) {
+ if (m_Layer.m_MultisampleAAMode != AAModeValues::SSAA) {
+ // Resolve the FBO to the layer texture
+ CRendererUtil::ResolveMutisampleFBOColorOnly(
+ theResourceManager, m_LayerTexture, theRenderContext,
+ theLayerTextureDimensions.width(), theLayerTextureDimensions.height(),
+ ColorTextureFormat, *theFB);
+
+ theRenderContext.SetMultisampleEnabled(false);
+ } else {
+ // Resolve the FBO to the layer texture
+ CRendererUtil::ResolveSSAAFBOColorOnly(
+ theResourceManager, m_LayerTexture,
+ theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(), theRenderContext,
+ theLayerTextureDimensions.width(), theLayerTextureDimensions.height(),
+ ColorTextureFormat, *theFB);
+ }
+ }
+
+ // CN - when I tried to get anti-aliased widgets I lost all transparency on the widget
+ // layer which made it overwrite the object you were
+ // manipulating. When I tried to use parallel nsight on it the entire studio
+ // application crashed on startup.
+ if (NeedsWidgetTexture()) {
+ m_LayerWidgetTexture.EnsureTexture(theLayerTextureDimensions.width(),
+ theLayerTextureDimensions.height(),
+ NVRenderTextureFormats::RGBA8);
+ theRenderContext.SetRenderTarget(theFB);
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *m_LayerWidgetTexture);
+ theFB->Attach(GetFramebufferDepthAttachmentFormat(DepthTextureFormat),
+ *m_LayerDepthTexture);
+ theRenderContext.SetClearColor(QT3DSVec4(0.0f));
+ theRenderContext.Clear(qt3ds::render::NVRenderClearValues::Color);
+ // We should already have the viewport and everything setup for this.
+ RenderRenderWidgets();
+ }
+
+ if (theLastLayerTexture.GetTexture() != NULL
+ && (isProgressiveAABlendPass || isTemporalAABlendPass)) {
+ theRenderContext.SetViewport(
+ NVRenderRect(0, 0, theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height()));
+ CResourceTexture2D targetTexture(
+ theResourceManager, theLayerOriginalTextureDimensions.width(),
+ theLayerOriginalTextureDimensions.height(), ColorTextureFormat);
+ theFB->Attach(theDepthAttachmentFormat,
+ NVRenderTextureOrRenderBuffer());
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0, *targetTexture);
+ QT3DSVec2 theBlendFactors;
+ if (isProgressiveAABlendPass)
+ theBlendFactors = s_BlendFactors[aaFactorIndex];
+ else
+ theBlendFactors = QT3DSVec2(.5f, .5f);
+
+ theRenderContext.SetDepthTestEnabled(false);
+ theRenderContext.SetBlendingEnabled(false);
+ theRenderContext.SetCullingEnabled(false);
+ theRenderContext.SetActiveShader(theBlendShader->m_Shader);
+ theBlendShader->m_AccumSampler.Set(theLastLayerTexture);
+ theBlendShader->m_LastFrame.Set(m_LayerTexture);
+ theBlendShader->m_BlendFactors.Set(theBlendFactors);
+ m_Renderer.RenderQuad();
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ qt3ds::render::NVRenderTextureOrRenderBuffer());
+ if (isTemporalAABlendPass)
+ m_TemporalAATexture.StealTexture(m_LayerTexture);
+ m_LayerTexture.StealTexture(targetTexture);
+ }
+
+ m_LayerTexture->SetMinFilter(NVRenderTextureMinifyingOp::Linear);
+ m_LayerTexture->SetMagFilter(NVRenderTextureMagnifyingOp::Linear);
+
+ // Don't remember why needs widget texture is false here.
+ // Should have commented why progAA plus widgets is a fail.
+ if (m_ProgressiveAAPassIndex < thePrepResult.m_MaxAAPassIndex
+ && NeedsWidgetTexture() == false)
+ ++m_ProgressiveAAPassIndex;
+
+// now we render all post effects
+#ifdef QT3DS_CACHED_POST_EFFECT
+ ApplyLayerPostEffects();
+#endif
+
+ if (m_LayerPrepassDepthTexture) {
+ // Detach any depth buffers.
+ theFB->Attach(theDepthAttachmentFormat, qt3ds::render::NVRenderTextureOrRenderBuffer(),
+ thFboAttachTarget);
+ }
+
+ theFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ qt3ds::render::NVRenderTextureOrRenderBuffer(), thFboAttachTarget);
+ // Let natural scoping rules destroy the other stuff.
+ }
+ }
+
+ void SLayerRenderData::ApplyLayerPostEffects()
+ {
+ if (m_Layer.m_FirstEffect == NULL) {
+ if (m_LayerCachedTexture) {
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+ return;
+ }
+
+ IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem());
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // we use the non MSAA buffer for the effect
+ NVRenderTexture2D *theLayerColorTexture = m_LayerTexture;
+ NVRenderTexture2D *theLayerDepthTexture = m_LayerDepthTexture;
+
+ NVRenderTexture2D *theCurrentTexture = theLayerColorTexture;
+ for (SEffect *theEffect = m_Layer.m_FirstEffect; theEffect;
+ theEffect = theEffect->m_NextEffect) {
+ if (theEffect->m_Flags.IsActive() && m_Camera) {
+ StartProfiling(theEffect->m_ClassName, false);
+
+ NVRenderTexture2D *theRenderedEffect = theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*theEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture));
+
+ EndProfiling(theEffect->m_ClassName);
+
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+
+ theCurrentTexture = theRenderedEffect;
+
+ if (!theRenderedEffect) {
+ QString errorMsg = QObject::tr("Failed to compile \"%1\" effect.\nConsider"
+ " removing it from the presentation.")
+ .arg(theEffect->m_ClassName.c_str());
+ QT3DS_ALWAYS_ASSERT_MESSAGE(errorMsg.toUtf8());
+ break;
+ }
+ }
+ }
+
+ if (m_LayerCachedTexture && m_LayerCachedTexture != m_LayerTexture) {
+ theResourceManager.Release(*m_LayerCachedTexture);
+ m_LayerCachedTexture = NULL;
+ }
+
+ if (theCurrentTexture != m_LayerTexture)
+ m_LayerCachedTexture = theCurrentTexture;
+ }
+
+ inline bool AnyCompletelyNonTransparentObjects(TRenderableObjectList &inObjects)
+ {
+ for (QT3DSU32 idx = 0, end = inObjects.size(); idx < end; ++idx) {
+ if (inObjects[idx]->m_RenderableFlags.IsCompletelyTransparent() == false)
+ return true;
+ }
+ return false;
+ }
+
+ void SLayerRenderData::RunnableRenderToViewport(qt3ds::render::NVRenderFrameBuffer *theFB)
+ {
+ // If we have an effect, an opaque object, or any transparent objects that aren't completely
+ // transparent
+ // or an offscreen renderer or a layer widget texture
+ // Then we can't possible affect the resulting render target.
+ bool needsToRender = m_Layer.m_FirstEffect != NULL || m_OpaqueObjects.empty() == false
+ || AnyCompletelyNonTransparentObjects(m_TransparentObjects) || GetOffscreenRenderer()
+ || m_LayerWidgetTexture || m_BoundingRectColor.hasValue()
+ || m_Layer.m_Background == LayerBackground::Color;
+
+ if (needsToRender == false)
+ return;
+
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ theContext.resetStates();
+
+ NVRenderContextScopedProperty<NVRenderFrameBuffer *> __fbo(
+ theContext, &NVRenderContext::GetRenderTarget, &NVRenderContext::SetRenderTarget);
+ qt3ds::render::NVRenderRect theCurrentViewport = theContext.GetViewport();
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+ NVRenderContextScopedProperty<bool> theScissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled);
+ NVRenderContextScopedProperty<qt3ds::render::NVRenderRect> theScissorRect(
+ theContext, &NVRenderContext::GetScissorRect, &NVRenderContext::SetScissorRect);
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderRectF theScreenRect(thePrepResult.GetLayerToPresentationViewport());
+
+ bool blendingEnabled = m_Layer.m_Background != LayerBackground::Unspecified;
+ if (!thePrepResult.m_Flags.ShouldRenderToTexture()) {
+ theContext.SetViewport(
+ m_LayerPrepResult->GetLayerToPresentationViewport().ToIntegerRect());
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetScissorRect(
+ m_LayerPrepResult->GetLayerToPresentationScissorRect().ToIntegerRect());
+ if (m_Layer.m_Background == LayerBackground::Color) {
+ NVRenderContextScopedProperty<QT3DSVec4> __clearColor(
+ theContext, &NVRenderContext::GetClearColor, &NVRenderContext::SetClearColor,
+ m_Layer.m_ClearColor);
+ theContext.Clear(NVRenderClearValues::Color);
+ }
+ RenderToViewport();
+ } else {
+// First, render the layer along with whatever progressive AA is appropriate.
+// The render graph should have taken care of the render to texture step.
+#ifdef QT3DS_CACHED_POST_EFFECT
+ NVRenderTexture2D *theLayerColorTexture =
+ (m_LayerCachedTexture) ? m_LayerCachedTexture : m_LayerTexture;
+#else
+ // Then render all but the last effect
+ IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem());
+ IResourceManager &theResourceManager(m_Renderer.GetQt3DSContext().GetResourceManager());
+ // we use the non MSAA buffer for the effect
+ NVRenderTexture2D *theLayerColorTexture = m_LayerTexture;
+ NVRenderTexture2D *theLayerDepthTexture = m_LayerDepthTexture;
+
+ NVRenderTexture2D *theCurrentTexture = theLayerColorTexture;
+ for (SEffect *theEffect = m_Layer.m_FirstEffect;
+ theEffect && theEffect != thePrepResult.m_LastEffect;
+ theEffect = theEffect->m_NextEffect) {
+ if (theEffect->m_Flags.IsActive() && m_Camera) {
+ StartProfiling(theEffect->m_ClassName, false);
+
+ NVRenderTexture2D *theRenderedEffect = theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*theEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture));
+
+ EndProfiling(theEffect->m_ClassName);
+
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+
+ theCurrentTexture = theRenderedEffect;
+ }
+ }
+#endif
+ // Now the last effect or straight to the scene if we have no last effect
+ // There are two cases we need to consider here. The first is when we shouldn't
+ // transform
+ // the result and thus we need to setup an MVP that just maps to the viewport width and
+ // height.
+ // The second is when we are expected to render to the scene using some global
+ // transform.
+ QT3DSMat44 theFinalMVP(QT3DSMat44::createIdentity());
+ SCamera theTempCamera;
+ NVRenderRect theLayerViewport(
+ thePrepResult.GetLayerToPresentationViewport().ToIntegerRect());
+ NVRenderRect theLayerClip(
+ thePrepResult.GetLayerToPresentationScissorRect().ToIntegerRect());
+
+ {
+ QT3DSMat33 ignored;
+ QT3DSMat44 theViewProjection;
+ // We could cache these variables
+ theTempCamera.m_Flags.SetOrthographic(true);
+ theTempCamera.MarkDirty(NodeTransformDirtyFlag::TransformIsDirty);
+ // Move the camera back far enough that we can see everything
+ QT3DSF32 theCameraSetback(10);
+ // Attempt to ensure the layer can never be clipped.
+ theTempCamera.m_Position.z = -theCameraSetback;
+ theTempCamera.m_ClipFar = 2.0f * theCameraSetback;
+ // Render the layer texture to the entire viewport.
+ SCameraGlobalCalculationResult theResult = theTempCamera.CalculateGlobalVariables(
+ theLayerViewport,
+ QT3DSVec2((QT3DSF32)theLayerViewport.m_Width, (QT3DSF32)theLayerViewport.m_Height));
+ theTempCamera.CalculateViewProjectionMatrix(theViewProjection);
+ SNode theTempNode;
+ theFinalMVP = theViewProjection;
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc;
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu;
+
+ switch (m_Layer.m_BlendType) {
+ case LayerBlendTypes::Screen:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::SrcAlpha, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Multiply:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::DstColor, NVRenderDstBlendFunc::Zero,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Add:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ case LayerBlendTypes::Subtract:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ReverseSubtract,
+ NVRenderBlendEquation::ReverseSubtract);
+ break;
+ case LayerBlendTypes::Overlay:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Overlay, NVRenderBlendEquation::Overlay);
+ break;
+ case LayerBlendTypes::ColorBurn:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ColorBurn, NVRenderBlendEquation::ColorBurn);
+ break;
+ case LayerBlendTypes::ColorDodge:
+ // SW fallback doesn't use blend equation
+ // note blend func is not used here anymore
+ if (theContext.IsAdvancedBlendHwSupported() ||
+ theContext.IsAdvancedBlendHwSupportedKHR())
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::ColorDodge, NVRenderBlendEquation::ColorDodge);
+ break;
+ default:
+ blendFunc = qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha);
+ blendEqu = qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add);
+ break;
+ }
+ theContext.SetBlendFunction(blendFunc);
+ theContext.SetBlendEquation(blendEqu);
+ theContext.SetBlendingEnabled(blendingEnabled);
+ theContext.SetDepthTestEnabled(false);
+ }
+
+ {
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetScissorRect(theLayerClip);
+
+ // Remember the camera we used so we can get a valid pick ray
+ m_SceneCamera = theTempCamera;
+ theContext.SetDepthTestEnabled(false);
+#ifndef QT3DS_CACHED_POST_EFFECT
+ if (thePrepResult.m_LastEffect && m_Camera) {
+ StartProfiling(thePrepResult.m_LastEffect->m_ClassName, false);
+ // inUseLayerMPV is true then we are rendering directly to the scene and thus we
+ // should enable blending
+ // for the final render pass. Else we should leave it.
+ theEffectSystem.RenderEffect(
+ SEffectRenderArgument(*thePrepResult.m_LastEffect, *theCurrentTexture,
+ QT3DSVec2(m_Camera->m_ClipNear, m_Camera->m_ClipFar),
+ theLayerDepthTexture, m_LayerPrepassDepthTexture),
+ theFinalMVP, blendingEnabled);
+ EndProfiling(thePrepResult.m_LastEffect->m_ClassName);
+ // If the texture came from rendering a chain of effects, then we don't need it
+ // after this.
+ if (theCurrentTexture != theLayerColorTexture)
+ theResourceManager.Release(*theCurrentTexture);
+ } else
+#endif
+ {
+ theContext.SetCullingEnabled(false);
+ theContext.SetBlendingEnabled(blendingEnabled);
+ theContext.SetDepthTestEnabled(false);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ NVScopedRefCounted<NVRenderTexture2D> screenTexture =
+ m_Renderer.GetLayerBlendTexture();
+ NVScopedRefCounted<NVRenderFrameBuffer> blendFB = m_Renderer.GetBlendFB();
+
+ // Layer blending for advanced blending modes if SW fallback is needed
+ // rendering to FBO and blending with separate shader
+ if (screenTexture) {
+ // Blending is enabled only if layer background has been chosen transparent
+ // Layers with advanced blending modes
+ if (blendingEnabled && (m_Layer.m_BlendType == LayerBlendTypes::Overlay ||
+ m_Layer.m_BlendType == LayerBlendTypes::ColorBurn ||
+ m_Layer.m_BlendType == LayerBlendTypes::ColorDodge)) {
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetBlendingEnabled(false);
+
+ // Get part matching to layer from screen texture and
+ // use that for blending
+ qt3ds::render::NVRenderTexture2D *blendBlitTexture;
+ blendBlitTexture = theContext.CreateTexture2D();
+ blendBlitTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ qt3ds::render::NVRenderFrameBuffer *blitFB;
+ blitFB = theContext.CreateFrameBuffer();
+ blitFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*blendBlitTexture));
+ blendFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*screenTexture));
+ theContext.SetRenderTarget(blitFB);
+ theContext.SetReadTarget(blendFB);
+ theContext.SetReadBuffer(NVReadFaces::Color0);
+ theContext.BlitFramebuffer(theLayerViewport.m_X, theLayerViewport.m_Y,
+ theLayerViewport.m_Width +
+ theLayerViewport.m_X,
+ theLayerViewport.m_Height +
+ theLayerViewport.m_Y,
+ 0, 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderClearValues::Color,
+ NVRenderTextureMagnifyingOp::Nearest);
+
+ qt3ds::render::NVRenderTexture2D *blendResultTexture;
+ blendResultTexture = theContext.CreateTexture2D();
+ blendResultTexture->SetTextureData(NVDataRef<QT3DSU8>(), 0,
+ theLayerViewport.m_Width,
+ theLayerViewport.m_Height,
+ NVRenderTextureFormats::RGBA8);
+ qt3ds::render::NVRenderFrameBuffer *resultFB;
+ resultFB = theContext.CreateFrameBuffer();
+ resultFB->Attach(NVRenderFrameBufferAttachments::Color0,
+ NVRenderTextureOrRenderBuffer(*blendResultTexture));
+ theContext.SetRenderTarget(resultFB);
+
+ AdvancedBlendModes::Enum advancedMode;
+ switch (m_Layer.m_BlendType) {
+ case LayerBlendTypes::Overlay:
+ advancedMode = AdvancedBlendModes::Overlay;
+ break;
+ case LayerBlendTypes::ColorBurn:
+ advancedMode = AdvancedBlendModes::ColorBurn;
+ break;
+ case LayerBlendTypes::ColorDodge:
+ advancedMode = AdvancedBlendModes::ColorDodge;
+ break;
+ default:
+ advancedMode = AdvancedBlendModes::None;
+ break;
+ }
+
+ theContext.SetViewport(NVRenderRect(0, 0, theLayerViewport.m_Width,
+ theLayerViewport.m_Height));
+ BlendAdvancedEquationSwFallback(theLayerColorTexture, blendBlitTexture,
+ advancedMode);
+ blitFB->release();
+ // save blending result to screen texture for use with other layers
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetRenderTarget(blendFB);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *blendResultTexture);
+ // render the blended result
+ theContext.SetRenderTarget(theFB);
+ theContext.SetScissorTestEnabled(true);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *blendResultTexture);
+ resultFB->release();
+ } else {
+ // Layers with normal blending modes
+ // save result for future use
+ theContext.SetViewport(theLayerViewport);
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetBlendingEnabled(true);
+ theContext.SetRenderTarget(blendFB);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ theContext.SetRenderTarget(theFB);
+ theContext.SetScissorTestEnabled(true);
+ theContext.SetViewport(theCurrentViewport);
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ }
+ } else {
+ // No advanced blending SW fallback needed
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+ }
+#else
+ m_Renderer.RenderQuad(QT3DSVec2((QT3DSF32)theLayerViewport.m_Width,
+ (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *theLayerColorTexture);
+#endif
+ }
+ if (m_LayerWidgetTexture) {
+ theContext.SetBlendingEnabled(false);
+ m_Renderer.SetupWidgetLayer();
+ SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult);
+ NVRenderRectF thePresRect(thePrepResult.GetPresentationViewport());
+ NVRenderRectF theLayerRect(thePrepResult.GetLayerToPresentationViewport());
+
+ // Ensure we remove any offsetting in the layer rect that was caused simply by
+ // the
+ // presentation rect offsetting but then use a new rect.
+ NVRenderRectF theWidgetLayerRect(theLayerRect.m_X - thePresRect.m_X,
+ theLayerRect.m_Y - thePresRect.m_Y,
+ theLayerRect.m_Width, theLayerRect.m_Height);
+ theContext.SetScissorTestEnabled(false);
+ theContext.SetViewport(theWidgetLayerRect.ToIntegerRect());
+ m_Renderer.RenderQuad(
+ QT3DSVec2((QT3DSF32)theLayerViewport.m_Width, (QT3DSF32)theLayerViewport.m_Height),
+ theFinalMVP, *m_LayerWidgetTexture);
+ }
+ }
+ } // End offscreen render code.
+
+ if (m_BoundingRectColor.hasValue()) {
+ NVRenderContextScopedProperty<NVRenderRect> __viewport(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport);
+ NVRenderContextScopedProperty<bool> theScissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled);
+ NVRenderContextScopedProperty<qt3ds::render::NVRenderRect> theScissorRect(
+ theContext, &NVRenderContext::GetScissorRect, &NVRenderContext::SetScissorRect);
+ m_Renderer.SetupWidgetLayer();
+ // Setup a simple viewport to render to the entire presentation viewport.
+ theContext.SetViewport(
+ NVRenderRect(0, 0, (QT3DSU32)thePrepResult.GetPresentationViewport().m_Width,
+ (QT3DSU32)thePrepResult.GetPresentationViewport().m_Height));
+
+ NVRenderRectF thePresRect(thePrepResult.GetPresentationViewport());
+
+ // Remove any offsetting from the presentation rect since the widget layer is a
+ // stand-alone fbo.
+ NVRenderRectF theWidgetScreenRect(theScreenRect.m_X - thePresRect.m_X,
+ theScreenRect.m_Y - thePresRect.m_Y,
+ theScreenRect.m_Width, theScreenRect.m_Height);
+ theContext.SetScissorTestEnabled(false);
+ m_Renderer.DrawScreenRect(theWidgetScreenRect, *m_BoundingRectColor);
+ }
+ theContext.SetBlendFunction(qt3ds::render::NVRenderBlendFunctionArgument(
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::OneMinusSrcAlpha));
+ theContext.SetBlendEquation(qt3ds::render::NVRenderBlendEquationArgument(
+ NVRenderBlendEquation::Add, NVRenderBlendEquation::Add));
+ }
+
+#define RENDER_FRAME_NEW(type) QT3DS_NEW(m_Renderer.GetPerFrameAllocator(), type)
+
+ void SLayerRenderData::AddLayerRenderStep()
+ {
+ SStackPerfTimer __perfTimer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::AddLayerRenderStep");
+ QT3DS_ASSERT(m_Camera);
+ if (!m_Camera)
+ return;
+
+ IRenderList &theGraph(m_Renderer.GetQt3DSContext().GetRenderList());
+
+ qt3ds::render::NVRenderRect theCurrentViewport = theGraph.GetViewport();
+ if (!m_LayerPrepResult.hasValue())
+ PrepareForRender(
+ QSize(theCurrentViewport.m_Width, theCurrentViewport.m_Height));
+ }
+
+ void SLayerRenderData::PrepareForRender()
+ {
+ // When we render to the scene itself (as opposed to an offscreen buffer somewhere)
+ // then we use the MVP of the layer somewhat.
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ PrepareForRender(
+ QSize((QT3DSU32)theViewport.m_Width, (QT3DSU32)theViewport.m_Height));
+ }
+
+ void SLayerRenderData::ResetForFrame()
+ {
+ SLayerRenderPreparationData::ResetForFrame();
+ m_BoundingRectColor.setEmpty();
+ }
+
+ void SLayerRenderData::PrepareAndRender(const QT3DSMat44 &inViewProjection)
+ {
+ TRenderableObjectList theTransparentObjects(m_TransparentObjects);
+ TRenderableObjectList theOpaqueObjects(m_OpaqueObjects);
+ theTransparentObjects.clear();
+ theOpaqueObjects.clear();
+ m_ModelContexts.clear();
+ SLayerRenderPreparationResultFlags theFlags;
+ PrepareRenderablesForRender(inViewProjection, Empty(), 1.0, theFlags);
+ RenderDepthPass(false);
+ Render();
+ }
+
+ struct SLayerRenderToTextureRunnable : public IRenderTask
+ {
+ SLayerRenderData &m_Data;
+ SLayerRenderToTextureRunnable(SLayerRenderData &d)
+ : m_Data(d)
+ {
+ }
+
+ void Run() override { m_Data.RenderToTexture(); }
+ };
+
+ static inline OffscreenRendererDepthValues::Enum
+ GetOffscreenRendererDepthValue(NVRenderTextureFormats::Enum inBufferFormat)
+ {
+ switch (inBufferFormat) {
+ case NVRenderTextureFormats::Depth32:
+ return OffscreenRendererDepthValues::Depth32;
+ case NVRenderTextureFormats::Depth24:
+ return OffscreenRendererDepthValues::Depth24;
+ case NVRenderTextureFormats::Depth24Stencil8:
+ return OffscreenRendererDepthValues::Depth24;
+ default:
+ QT3DS_ASSERT(false); // fallthrough intentional
+ case NVRenderTextureFormats::Depth16:
+ return OffscreenRendererDepthValues::Depth16;
+ }
+ }
+
+ SOffscreenRendererEnvironment SLayerRenderData::CreateOffscreenRenderEnvironment()
+ {
+ OffscreenRendererDepthValues::Enum theOffscreenDepth(
+ GetOffscreenRendererDepthValue(GetDepthBufferFormat()));
+ NVRenderRect theViewport = m_Renderer.GetQt3DSContext().GetRenderList().GetViewport();
+ return SOffscreenRendererEnvironment(theViewport.m_Width, theViewport.m_Height,
+ NVRenderTextureFormats::RGBA8, theOffscreenDepth,
+ false, AAModeValues::NoAA);
+ }
+
+ IRenderTask &SLayerRenderData::CreateRenderToTextureRunnable()
+ {
+ return *RENDER_FRAME_NEW(SLayerRenderToTextureRunnable)(*this);
+ }
+
+ void SLayerRenderData::addRef() { atomicIncrement(&mRefCount); }
+
+ void SLayerRenderData::release() { QT3DS_IMPLEMENT_REF_COUNT_RELEASE(m_Allocator); }
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h
new file mode 100644
index 0000000..4e237b0
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_RENDERER_IMPL_LAYER_RENDER_DATA_H
+#define QT3DS_RENDERER_IMPL_LAYER_RENDER_DATA_H
+#include "Qt3DSRender.h"
+#include "Qt3DSRendererImplLayerRenderPreparationData.h"
+#include "Qt3DSRenderResourceBufferObjects.h"
+
+namespace qt3ds {
+namespace render {
+
+struct AdvancedBlendModes
+{
+ enum Enum {
+ None = 0,
+ Overlay,
+ ColorBurn,
+ ColorDodge
+ };
+};
+ struct QT3DS_AUTOTEST_EXPORT SLayerRenderData : public SLayerRenderPreparationData
+ {
+
+ // Layers can be rendered offscreen for many reasons; effects, progressive aa,
+ // or just because a flag forces it. If they are rendered offscreen we can then
+ // cache the result so we don't render the layer again if it isn't dirty.
+ CResourceTexture2D m_LayerTexture;
+ CResourceTexture2D m_TemporalAATexture;
+ // Sometimes we need to render our depth buffer to a depth texture.
+ CResourceTexture2D m_LayerDepthTexture;
+ CResourceTexture2D m_LayerPrepassDepthTexture;
+ CResourceTexture2D m_LayerWidgetTexture;
+ CResourceTexture2D m_LayerSsaoTexture;
+ // if we render multisampled we need resolve buffers
+ CResourceTexture2D m_LayerMultisampleTexture;
+ CResourceTexture2D m_LayerMultisamplePrepassDepthTexture;
+ CResourceTexture2D m_LayerMultisampleWidgetTexture;
+ // the texture contains the render result inclusive post effects
+ NVRenderTexture2D *m_LayerCachedTexture;
+
+ NVRenderTexture2D *m_AdvancedBlendDrawTexture;
+ NVRenderTexture2D *m_AdvancedBlendBlendTexture;
+ qt3ds::render::NVRenderFrameBuffer *m_AdvancedModeDrawFB;
+ qt3ds::render::NVRenderFrameBuffer *m_AdvancedModeBlendFB;
+
+ // True if this layer was rendered offscreen.
+ // If this object has no value then this layer wasn't rendered at all.
+ SOffscreenRendererEnvironment m_LastOffscreenRenderEnvironment;
+
+ // GPU profiler per layer
+ NVScopedRefCounted<IRenderProfiler> m_LayerProfilerGpu;
+
+ SCamera m_SceneCamera;
+ QT3DSVec2 m_SceneDimensions;
+
+ // ProgressiveAA algorithm details.
+ QT3DSU32 m_ProgressiveAAPassIndex;
+ // Increments every frame regardless to provide appropriate jittering
+ QT3DSU32 m_TemporalAAPassIndex;
+ // Ensures we don't stop on an in-between frame; we will run two frames after the dirty flag
+ // is clear.
+ QT3DSU32 m_NonDirtyTemporalAAPassIndex;
+ QT3DSF32 m_TextScale;
+
+ volatile QT3DSI32 mRefCount;
+ Option<QT3DSVec3> m_BoundingRectColor;
+ NVRenderTextureFormats::Enum m_DepthBufferFormat;
+
+ QSize m_previousDimensions;
+
+ SLayerRenderData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer);
+
+ virtual ~SLayerRenderData();
+
+ void PrepareForRender();
+
+ // Internal Call
+ void PrepareForRender(const QSize &inViewportDimensions) override;
+
+ NVRenderTextureFormats::Enum GetDepthBufferFormat();
+ NVRenderFrameBufferAttachments::Enum
+ GetFramebufferDepthAttachmentFormat(NVRenderTextureFormats::Enum depthFormat);
+
+ // Render this layer assuming viewport and RT are setup. Just renders exactly this item
+ // no effects.
+ void RenderDepthPass(bool inEnableTransparentDepthWrite = false);
+ void RenderAoPass();
+ void RenderFakeDepthMapPass(NVRenderTexture2D *theDepthTex,
+ NVRenderTextureCube *theDepthCube);
+ void RenderShadowMapPass(CResourceFrameBuffer *theFB);
+ void RenderShadowCubeBlurPass(CResourceFrameBuffer *theFB, NVRenderTextureCube *target0,
+ NVRenderTextureCube *target1, QT3DSF32 filterSz, QT3DSF32 clipFar);
+ void RenderShadowMapBlurPass(CResourceFrameBuffer *theFB, NVRenderTexture2D *target0,
+ NVRenderTexture2D *target1, QT3DSF32 filterSz, QT3DSF32 clipFar);
+
+ void Render(CResourceFrameBuffer *theFB = NULL);
+ void ResetForFrame() override;
+
+ void CreateGpuProfiler();
+ void StartProfiling(CRegisteredString &nameID, bool sync);
+ void EndProfiling(CRegisteredString &nameID);
+ void StartProfiling(const char *nameID, bool sync);
+ void EndProfiling(const char *nameID);
+ void AddVertexCount(QT3DSU32 count);
+
+ void RenderToViewport();
+ // Render this layer's data to a texture. Required if we have any effects,
+ // prog AA, or if forced.
+ void RenderToTexture();
+
+ void ApplyLayerPostEffects();
+
+ void RunnableRenderToViewport(qt3ds::render::NVRenderFrameBuffer *theFB);
+
+ void AddLayerRenderStep();
+
+ void RenderRenderWidgets();
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ void BlendAdvancedEquationSwFallback(NVRenderTexture2D *drawTexture,
+ NVRenderTexture2D *m_LayerTexture,
+ AdvancedBlendModes::Enum blendMode);
+#endif
+ // test method to render this layer to a given view projection without running the entire
+ // layer setup system. This assumes the client has setup the viewport, scissor, and render
+ // target
+ // the way they want them.
+ void PrepareAndRender(const QT3DSMat44 &inViewProjection);
+
+ SOffscreenRendererEnvironment CreateOffscreenRenderEnvironment() override;
+ IRenderTask &CreateRenderToTextureRunnable() override;
+
+ void addRef();
+ void release();
+
+ protected:
+ // Used for both the normal passes and the depth pass.
+ // When doing the depth pass, we disable blending completely because it does not really make
+ // sense
+ // to write blend equations into
+ void RunRenderPass(TRenderRenderableFunction renderFn, bool inEnableBlending,
+ bool inEnableDepthWrite, bool inEnableTransparentDepthWrite,
+ QT3DSU32 indexLight, const SCamera &inCamera,
+ CResourceFrameBuffer *theFB = NULL);
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ //Functions for advanced blending mode fallback
+ void SetupDrawFB(bool depthEnabled);
+ void BlendAdvancedToFB(DefaultMaterialBlendMode::Enum blendMode, bool depthEnabled,
+ CResourceFrameBuffer *theFB);
+#endif
+ };
+}
+}
+#endif
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp
new file mode 100644
index 0000000..07ee513
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSRendererImplLayerRenderHelper.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSTextRenderer.h"
+
+using namespace qt3ds::render;
+
+namespace {
+// left/top
+QT3DSF32 GetMinValue(QT3DSF32 start, QT3DSF32 width, QT3DSF32 value, LayerUnitTypes::Enum units)
+{
+ if (units == LayerUnitTypes::Pixels)
+ return start + value;
+
+ return start + (value * width / 100.0f);
+}
+
+// width/height
+QT3DSF32 GetValueLen(QT3DSF32 width, QT3DSF32 value, LayerUnitTypes::Enum units)
+{
+ if (units == LayerUnitTypes::Pixels)
+ return value;
+
+ return width * value / 100.0f;
+}
+
+// right/bottom
+QT3DSF32 GetMaxValue(QT3DSF32 start, QT3DSF32 width, QT3DSF32 value, LayerUnitTypes::Enum units)
+{
+ if (units == LayerUnitTypes::Pixels)
+ return start + width - value;
+
+ return start + width - (value * width / 100.0f);
+}
+
+QT3DSVec2 ToRectRelativeCoords(const QT3DSVec2 &inCoords, const NVRenderRectF &inRect)
+{
+ return QT3DSVec2(inCoords.x - inRect.m_X, inCoords.y - inRect.m_Y);
+}
+}
+
+SLayerRenderHelper::SLayerRenderHelper()
+ : m_Layer(NULL)
+ , m_Camera(NULL)
+ , m_Offscreen(false)
+{
+}
+
+SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewport,
+ const NVRenderRectF &inPresentationScissor,
+ const QT3DSVec2 &inPresentationDesignDimensions,
+ SLayer &inLayer, bool inOffscreen,
+ qt3ds::render::ScaleModes::Enum inScaleMode,
+ qt3ds::QT3DSVec2 inScaleFactor)
+ : m_PresentationViewport(inPresentationViewport)
+ , m_PresentationScissor(inPresentationScissor)
+ , m_PresentationDesignDimensions(inPresentationDesignDimensions)
+ , m_Layer(&inLayer)
+ , m_Offscreen(inOffscreen)
+ , m_ScaleMode(inScaleMode)
+ , m_ScaleFactor(inScaleFactor)
+{
+ {
+ QT3DSF32 left = m_Layer->m_Left;
+ QT3DSF32 right = m_Layer->m_Right;
+ QT3DSF32 width = m_Layer->m_Width;
+
+ if (m_ScaleMode == qt3ds::render::ScaleModes::FitSelected) {
+ if (m_Layer->m_LeftUnits == LayerUnitTypes::Pixels)
+ left *= m_ScaleFactor.x;
+
+ if (m_Layer->m_RightUnits == LayerUnitTypes::Pixels)
+ right *= m_ScaleFactor.x;
+
+ if (m_Layer->m_WidthUnits == LayerUnitTypes::Pixels)
+ width *= m_ScaleFactor.x;
+ }
+
+ QT3DSF32 horzMin = GetMinValue(inPresentationViewport.m_X, inPresentationViewport.m_Width,
+ left, m_Layer->m_LeftUnits);
+ QT3DSF32 horzWidth = GetValueLen(inPresentationViewport.m_Width, width, m_Layer->m_WidthUnits);
+ QT3DSF32 horzMax = GetMaxValue(inPresentationViewport.m_X, inPresentationViewport.m_Width,
+ right, m_Layer->m_RightUnits);
+
+ switch (inLayer.m_HorizontalFieldValues) {
+ case HorizontalFieldValues::LeftWidth:
+ m_Viewport.m_X = horzMin;
+ m_Viewport.m_Width = horzWidth;
+ break;
+ case HorizontalFieldValues::LeftRight:
+ m_Viewport.m_X = horzMin;
+ m_Viewport.m_Width = horzMax - horzMin;
+ break;
+ case HorizontalFieldValues::WidthRight:
+ m_Viewport.m_Width = horzWidth;
+ m_Viewport.m_X = horzMax - horzWidth;
+ break;
+ }
+ }
+ {
+ QT3DSF32 top = m_Layer->m_Top;
+ QT3DSF32 bottom = m_Layer->m_Bottom;
+ QT3DSF32 height = m_Layer->m_Height;
+
+ if (m_ScaleMode == qt3ds::render::ScaleModes::FitSelected) {
+
+ if (m_Layer->m_TopUnits == LayerUnitTypes::Pixels)
+ top *= m_ScaleFactor.y;
+
+ if (m_Layer->m_BottomUnits == LayerUnitTypes::Pixels)
+ bottom *= m_ScaleFactor.y;
+
+ if (m_Layer->m_HeightUnits == LayerUnitTypes::Pixels)
+ height *= m_ScaleFactor.y;
+ }
+
+ QT3DSF32 vertMin = GetMinValue(inPresentationViewport.m_Y, inPresentationViewport.m_Height,
+ bottom, m_Layer->m_BottomUnits);
+ QT3DSF32 vertWidth =
+ GetValueLen(inPresentationViewport.m_Height, height, m_Layer->m_HeightUnits);
+ QT3DSF32 vertMax = GetMaxValue(inPresentationViewport.m_Y, inPresentationViewport.m_Height,
+ top, m_Layer->m_TopUnits);
+
+ switch (inLayer.m_VerticalFieldValues) {
+ case VerticalFieldValues::HeightBottom:
+ m_Viewport.m_Y = vertMin;
+ m_Viewport.m_Height = vertWidth;
+ break;
+ case VerticalFieldValues::TopBottom:
+ m_Viewport.m_Y = vertMin;
+ m_Viewport.m_Height = vertMax - vertMin;
+ break;
+ case VerticalFieldValues::TopHeight:
+ m_Viewport.m_Height = vertWidth;
+ m_Viewport.m_Y = vertMax - vertWidth;
+ break;
+ }
+ }
+
+ m_Viewport.m_Width = NVMax(1.0f, m_Viewport.m_Width);
+ m_Viewport.m_Height = NVMax(1.0f, m_Viewport.m_Height);
+ // Now force the viewport to be a multiple of four in width and height. This is because
+ // when rendering to a texture we have to respect this and not forcing it causes scaling issues
+ // that are noticeable especially in situations where customers are using text and such.
+ QT3DSF32 originalWidth = m_Viewport.m_Width;
+ QT3DSF32 originalHeight = m_Viewport.m_Height;
+
+ m_Viewport.m_Width = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Width);
+ m_Viewport.m_Height = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Height);
+
+ // Now fudge the offsets to account for this slight difference
+ m_Viewport.m_X += (originalWidth - m_Viewport.m_Width) / 2.0f;
+ m_Viewport.m_Y += (originalHeight - m_Viewport.m_Height) / 2.0f;
+
+ m_Scissor = m_Viewport;
+ m_Scissor.EnsureInBounds(inPresentationScissor);
+ QT3DS_ASSERT(m_Scissor.m_Width >= 0.0f);
+ QT3DS_ASSERT(m_Scissor.m_Height >= 0.0f);
+}
+
+// This is the viewport the camera will use to setup the projection.
+NVRenderRectF SLayerRenderHelper::GetLayerRenderViewport() const
+{
+ if (m_Offscreen)
+ return NVRenderRectF(0, 0, m_Viewport.m_Width, (QT3DSF32)m_Viewport.m_Height);
+ else
+ return m_Viewport;
+}
+
+QSize SLayerRenderHelper::GetTextureDimensions() const
+{
+ QT3DSU32 width = (QT3DSU32)m_Viewport.m_Width;
+ QT3DSU32 height = (QT3DSU32)m_Viewport.m_Height;
+ return QSize(ITextRenderer::NextMultipleOf4(width),
+ ITextRenderer::NextMultipleOf4(height));
+}
+
+SCameraGlobalCalculationResult SLayerRenderHelper::SetupCameraForRender(SCamera &inCamera)
+{
+ m_Camera = &inCamera;
+ NVRenderRectF rect = GetLayerRenderViewport();
+ if (m_ScaleMode == ScaleModes::FitSelected) {
+ rect.m_Width =
+ (QT3DSF32)(ITextRenderer::NextMultipleOf4((QT3DSU32)(rect.m_Width / m_ScaleFactor.x)));
+ rect.m_Height =
+ (QT3DSF32)(ITextRenderer::NextMultipleOf4((QT3DSU32)(rect.m_Height / m_ScaleFactor.y)));
+ }
+ return m_Camera->CalculateGlobalVariables(rect, m_PresentationDesignDimensions);
+}
+
+Option<QT3DSVec2> SLayerRenderHelper::GetLayerMouseCoords(const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inWindowDimensions,
+ bool inForceIntersect) const
+{
+ // First invert the y so we are dealing with numbers in a normal coordinate space.
+ // Second, move into our layer's coordinate space
+ QT3DSVec2 correctCoords(inMouseCoords.x, inWindowDimensions.y - inMouseCoords.y);
+ QT3DSVec2 theLocalMouse = m_Viewport.ToRectRelative(correctCoords);
+
+ QT3DSF32 theRenderRectWidth = m_Viewport.m_Width;
+ QT3DSF32 theRenderRectHeight = m_Viewport.m_Height;
+ // Crop the mouse to the rect. Apply no further translations.
+ if (inForceIntersect == false
+ && (theLocalMouse.x < 0.0f || theLocalMouse.x >= theRenderRectWidth
+ || theLocalMouse.y < 0.0f || theLocalMouse.y >= theRenderRectHeight)) {
+ return Empty();
+ }
+ return theLocalMouse;
+}
+
+Option<SRay> SLayerRenderHelper::GetPickRay(const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inWindowDimensions,
+ bool inForceIntersect,
+ bool sceneCameraView) const
+{
+ if (m_Camera == NULL)
+ return Empty();
+ Option<QT3DSVec2> theCoords(
+ GetLayerMouseCoords(inMouseCoords, inWindowDimensions, inForceIntersect));
+ if (theCoords.hasValue()) {
+ // The cameras projection is different if we are onscreen vs. offscreen.
+ // When offscreen, we need to move the mouse coordinates into a local space
+ // to the layer.
+ return m_Camera->Unproject(*theCoords, m_Viewport, m_PresentationDesignDimensions,
+ sceneCameraView);
+ }
+ return Empty();
+}
+
+bool SLayerRenderHelper::IsLayerVisible() const
+{
+ return m_Scissor.m_Height >= 2.0f && m_Scissor.m_Width >= 2.0f;
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h
new file mode 100644
index 0000000..616ebe1
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#include "Qt3DSRender.h"
+#include "foundation/Qt3DSVec2.h"
+#include "render/Qt3DSRenderBaseTypes.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderContextCore.h"
+
+namespace qt3ds {
+namespace render {
+
+ /** An independent, testable entity to encapsulate taking at least:
+ * layer, current viewport rect, current scissor rect, presentation design dimensions
+ * and producing a set of rectangles:
+ * layer viewport rect (inside viewport rect and calculated using outer viewport rect info)
+ * layer scissor rect (inside current scissor rect)
+ * layer camera rect (may be the viewport rect)
+ *
+ * In the case where we have to render offscreen for this layer then we need to handle produce
+ * a set of texture dimensions and the layer camera rect ends up being same size but with no
+ *offsets.
+ *
+ * This object should handle part of any translation from screenspace to global space.
+ * I am using language level access control on this object because it needs specific
+ * interface design that will enable future modifications.
+ */
+ struct SLayerRenderHelper
+ {
+ private:
+ NVRenderRectF m_PresentationViewport;
+ NVRenderRectF m_PresentationScissor;
+ QT3DSVec2 m_PresentationDesignDimensions;
+ SLayer *m_Layer;
+ SCamera *m_Camera;
+ bool m_Offscreen;
+
+ NVRenderRectF m_Viewport;
+ NVRenderRectF m_Scissor;
+
+ ScaleModes::Enum m_ScaleMode;
+ QT3DSVec2 m_ScaleFactor;
+
+ public:
+ SLayerRenderHelper();
+
+ SLayerRenderHelper(const NVRenderRectF &inPresentationViewport,
+ const NVRenderRectF &inPresentationScissor,
+ const QT3DSVec2 &inPresentationDesignDimensions, SLayer &inLayer,
+ bool inOffscreen, qt3ds::render::ScaleModes::Enum inScaleMode,
+ qt3ds::QT3DSVec2 inScaleFactor);
+
+ NVRenderRectF GetPresentationViewport() const { return m_PresentationViewport; }
+ NVRenderRectF GetPresentationScissor() const { return m_PresentationScissor; }
+ QT3DSVec2 GetPresentationDesignDimensions() const { return m_PresentationDesignDimensions; }
+ SLayer *GetLayer() const { return m_Layer; }
+ SCamera *GetCamera() const { return m_Camera; }
+ bool IsOffscreen() const { return m_Offscreen; }
+
+ // Does not differ whether offscreen or not, simply states how this layer maps to the
+ // presentation
+ NVRenderRectF GetLayerToPresentationViewport() const { return m_Viewport; }
+ // Does not differ whether offscreen or not, scissor rect of how this layer maps to
+ // presentation.
+ NVRenderRectF GetLayerToPresentationScissorRect() const { return m_Scissor; }
+
+ QSize GetTextureDimensions() const;
+
+ SCameraGlobalCalculationResult SetupCameraForRender(SCamera &inCamera);
+
+ Option<QT3DSVec2> GetLayerMouseCoords(const QT3DSVec2 &inMouseCoords,
+ const QT3DSVec2 &inWindowDimensions,
+ bool inForceIntersect) const;
+
+ Option<SRay> GetPickRay(const QT3DSVec2 &inMouseCoords, const QT3DSVec2 &inWindowDimensions,
+ bool inForceIntersect, bool sceneCameraView = false) const;
+
+ // Checks the various viewports and determines if the layer is visible or not.
+ bool IsLayerVisible() const;
+
+ private:
+ // Viewport used when actually rendering. In the case where this is an offscreen item then
+ // it may be
+ // different than the layer to presentation viewport.
+ NVRenderRectF GetLayerRenderViewport() const;
+ };
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
new file mode 100644
index 0000000..8afa3c0
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp
@@ -0,0 +1,1477 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSRender.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRendererImpl.h"
+#include "Qt3DSRenderLayer.h"
+#include "Qt3DSRenderEffect.h"
+#include "EASTL/sort.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderCamera.h"
+#include "Qt3DSRenderScene.h"
+#include "Qt3DSRenderPresentation.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderResourceManager.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderEffectSystem.h"
+#include "render/Qt3DSRenderFrameBuffer.h"
+#include "render/Qt3DSRenderRenderBuffer.h"
+#include "Qt3DSOffscreenRenderKey.h"
+#include "Qt3DSRenderPlugin.h"
+#include "Qt3DSRenderPluginGraphObject.h"
+#include "Qt3DSRenderResourceBufferObjects.h"
+#include "foundation/Qt3DSPerfTimer.h"
+#include "foundation/AutoDeallocatorAllocator.h"
+#include "Qt3DSRenderMaterialHelpers.h"
+#include "Qt3DSRenderBufferManager.h"
+#include "Qt3DSRenderCustomMaterialSystem.h"
+#include "Qt3DSRenderTextTextureCache.h"
+#include "Qt3DSRenderTextTextureAtlas.h"
+#include "Qt3DSRenderRenderList.h"
+#include "Qt3DSRenderPath.h"
+#include "Qt3DSRenderPathManager.h"
+
+#ifdef _WIN32
+#pragma warning(disable : 4355)
+#endif
+namespace qt3ds {
+namespace render {
+ using eastl::reverse;
+ using eastl::stable_sort;
+ using qt3ds::render::NVRenderContextScopedProperty;
+ using qt3ds::QT3DSVec2;
+
+ namespace {
+ void MaybeQueueNodeForRender(SNode &inNode, nvvector<SRenderableNodeEntry> &outRenderables,
+ nvvector<SNode *> &outCamerasAndLights, QT3DSU32 &ioDFSIndex)
+ {
+ ++ioDFSIndex;
+ inNode.m_DFSIndex = ioDFSIndex;
+ if (GraphObjectTypes::IsRenderableType(inNode.m_Type))
+ outRenderables.push_back(inNode);
+ else if (GraphObjectTypes::IsLightCameraType(inNode.m_Type))
+ outCamerasAndLights.push_back(&inNode);
+
+ for (SNode *theChild = inNode.m_FirstChild; theChild != NULL;
+ theChild = theChild->m_NextSibling)
+ MaybeQueueNodeForRender(*theChild, outRenderables, outCamerasAndLights, ioDFSIndex);
+ }
+
+ bool HasValidLightProbe(SImage *inLightProbeImage)
+ {
+ return inLightProbeImage && inLightProbeImage->m_TextureData.m_Texture;
+ }
+ }
+
+ SDefaultMaterialPreparationResult::SDefaultMaterialPreparationResult(
+ SShaderDefaultMaterialKey inKey)
+ : m_FirstImage(NULL)
+ , m_Opacity(1.0f)
+ , m_MaterialKey(inKey)
+ , m_Dirty(false)
+ {
+ }
+
+#define MAX_AA_LEVELS 8
+
+ SLayerRenderPreparationData::SLayerRenderPreparationData(SLayer &inLayer,
+ Qt3DSRendererImpl &inRenderer)
+ : m_Layer(inLayer)
+ , m_Renderer(inRenderer)
+ , m_Allocator(inRenderer.GetContext().GetAllocator())
+ , m_RenderableNodeLightEntryPool(
+ ForwardingAllocator(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_RenderableNodes"))
+ , m_RenderableNodes(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_RenderableNodes")
+ , m_LightToNodeMap(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_LightToNodeMap")
+ , m_CamerasAndLights(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_CamerasAndLights")
+ , m_Camera(NULL)
+ , m_Lights(inRenderer.GetContext().GetAllocator(), "SLayerRenderPreparationData::m_Lights")
+ , m_OpaqueObjects(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_OpaqueObjects")
+ , m_TransparentObjects(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_TransparentObjects")
+ , m_RenderedOpaqueObjects(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_RenderedOpaqueObjects")
+ , m_RenderedTransparentObjects(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_RenderedTransparentObjects")
+ , m_IRenderWidgets(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_IRenderWidgets")
+ , m_SourceLightDirections(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_SourceLightDirections")
+ , m_LightDirections(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_LightDirections")
+ , m_ModelContexts(inRenderer.GetContext().GetAllocator(),
+ "SLayerRenderPreparationData::m_ModelContexts")
+ , m_CGLightingFeatureName(
+ inRenderer.GetContext().GetStringTable().RegisterStr("QT3DS_ENABLE_CG_LIGHTING"))
+ , m_FeaturesDirty(true)
+ , m_FeatureSetHash(0)
+ , m_TooManyLightsError(false)
+ {
+ }
+
+ SLayerRenderPreparationData::~SLayerRenderPreparationData() {}
+
+ bool SLayerRenderPreparationData::NeedsWidgetTexture() const
+ {
+ return m_IRenderWidgets.size() > 0;
+ }
+
+ void SLayerRenderPreparationData::SetShaderFeature(CRegisteredString theStr, bool inValue)
+ {
+ SShaderPreprocessorFeature item(theStr, inValue);
+ eastl::vector<SShaderPreprocessorFeature>::iterator iter = m_Features.begin(),
+ end = m_Features.end();
+
+ // empty loop intentional.
+ for (; iter != end && ((iter->m_Name == theStr) == false); ++iter)
+ ;
+
+ if (iter != end) {
+ if (iter->m_Enabled != inValue) {
+ iter->m_Enabled = inValue;
+ m_FeaturesDirty = true;
+ m_FeatureSetHash = 0;
+ }
+ } else {
+ m_Features.push_back(item);
+ m_FeaturesDirty = true;
+ m_FeatureSetHash = 0;
+ }
+ }
+
+ void SLayerRenderPreparationData::SetShaderFeature(const char *inName, bool inValue)
+ {
+ CRegisteredString theStr(m_Renderer.GetQt3DSContext().GetStringTable().RegisterStr(inName));
+ SetShaderFeature(theStr, inValue);
+ }
+
+ NVConstDataRef<SShaderPreprocessorFeature> SLayerRenderPreparationData::GetShaderFeatureSet()
+ {
+ if (m_FeaturesDirty) {
+ eastl::sort(m_Features.begin(), m_Features.end());
+ m_FeaturesDirty = false;
+ }
+ return toConstDataRef(m_Features.data(), (QT3DSU32)m_Features.size());
+ }
+
+ size_t SLayerRenderPreparationData::GetShaderFeatureSetHash()
+ {
+ if (!m_FeatureSetHash)
+ m_FeatureSetHash = HashShaderFeatureSet(GetShaderFeatureSet());
+ return m_FeatureSetHash;
+ }
+
+ bool SLayerRenderPreparationData::GetShadowMapManager()
+ {
+ if (m_ShadowMapManager.mPtr)
+ return true;
+
+ m_ShadowMapManager.mPtr = Qt3DSShadowMap::Create(m_Renderer.GetQt3DSContext());
+
+ return m_ShadowMapManager.mPtr != NULL;
+ }
+
+ bool SLayerRenderPreparationData::GetOffscreenRenderer()
+ {
+ if (m_LastFrameOffscreenRenderer.mPtr)
+ return true;
+
+ if (m_Layer.m_RenderPlugin && m_Layer.m_RenderPlugin->m_Flags.IsActive()) {
+ IRenderPluginInstance *theInstance =
+ m_Renderer.GetQt3DSContext().GetRenderPluginManager().GetOrCreateRenderPluginInstance(
+ m_Layer.m_RenderPlugin->m_PluginPath, m_Layer.m_RenderPlugin);
+ if (theInstance) {
+ m_Renderer.GetQt3DSContext()
+ .GetOffscreenRenderManager()
+ .MaybeRegisterOffscreenRenderer(&theInstance, *theInstance);
+ m_LastFrameOffscreenRenderer = theInstance;
+ }
+ }
+ if (m_LastFrameOffscreenRenderer.mPtr == NULL)
+ m_LastFrameOffscreenRenderer =
+ m_Renderer.GetQt3DSContext().GetOffscreenRenderManager().GetOffscreenRenderer(
+ m_Layer.m_TexturePath);
+ return m_LastFrameOffscreenRenderer.mPtr != NULL;
+ }
+
+ QT3DSVec3 SLayerRenderPreparationData::GetCameraDirection()
+ {
+ if (m_CameraDirection.hasValue() == false) {
+ if (m_Camera)
+ m_CameraDirection = m_Camera->GetScalingCorrectDirection();
+ else
+ m_CameraDirection = QT3DSVec3(0, 0, -1);
+ }
+ return *m_CameraDirection;
+ }
+
+ // Per-frame cache of renderable objects post-sort.
+ NVDataRef<SRenderableObject *> SLayerRenderPreparationData::GetOpaqueRenderableObjects()
+ {
+ if (m_RenderedOpaqueObjects.empty() == false || m_Camera == NULL)
+ return m_RenderedOpaqueObjects;
+ if (m_Layer.m_Flags.IsLayerEnableDepthTest() && m_OpaqueObjects.empty() == false) {
+ QT3DSVec3 theCameraDirection(GetCameraDirection());
+ QT3DSVec3 theCameraPosition = m_Camera->GetGlobalPos();
+ m_RenderedOpaqueObjects.assign(m_OpaqueObjects.begin(), m_OpaqueObjects.end());
+ // Setup the object's sorting information
+ for (QT3DSU32 idx = 0, end = m_RenderedOpaqueObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theInfo = *m_RenderedOpaqueObjects[idx];
+ QT3DSVec3 difference = theInfo.m_WorldCenterPoint - theCameraPosition;
+ theInfo.m_CameraDistanceSq = difference.dot(theCameraDirection);
+ }
+
+ ForwardingAllocator alloc(m_Renderer.GetPerFrameAllocator(), "SortAllocations");
+ // Render nearest to furthest objects
+ eastl::merge_sort(m_RenderedOpaqueObjects.begin(), m_RenderedOpaqueObjects.end(), alloc,
+ ISRenderObjectPtrLessThan);
+ }
+ return m_RenderedOpaqueObjects;
+ }
+
+ // If layer depth test is false, this may also contain opaque objects.
+ NVDataRef<SRenderableObject *> SLayerRenderPreparationData::GetTransparentRenderableObjects()
+ {
+ if (m_RenderedTransparentObjects.empty() == false || m_Camera == NULL)
+ return m_RenderedTransparentObjects;
+
+ m_RenderedTransparentObjects.assign(m_TransparentObjects.begin(),
+ m_TransparentObjects.end());
+
+ if (m_Layer.m_Flags.IsLayerEnableDepthTest() == false)
+ m_RenderedTransparentObjects.insert(m_RenderedTransparentObjects.end(),
+ m_OpaqueObjects.begin(), m_OpaqueObjects.end());
+
+ if (m_RenderedTransparentObjects.empty() == false) {
+ QT3DSVec3 theCameraDirection(GetCameraDirection());
+ QT3DSVec3 theCameraPosition = m_Camera->GetGlobalPos();
+
+ // Setup the object's sorting information
+ for (QT3DSU32 idx = 0, end = m_RenderedTransparentObjects.size(); idx < end; ++idx) {
+ SRenderableObject &theInfo = *m_RenderedTransparentObjects[idx];
+ QT3DSVec3 difference = theInfo.m_WorldCenterPoint - theCameraPosition;
+ theInfo.m_CameraDistanceSq = difference.dot(theCameraDirection);
+ }
+ ForwardingAllocator alloc(m_Renderer.GetPerFrameAllocator(), "SortAllocations");
+ // render furthest to nearest.
+ eastl::merge_sort(m_RenderedTransparentObjects.begin(),
+ m_RenderedTransparentObjects.end(), alloc,
+ ISRenderObjectPtrGreatThan);
+ }
+
+ return m_RenderedTransparentObjects;
+ }
+
+#define MAX_LAYER_WIDGETS 200
+
+ void SLayerRenderPreparationData::AddRenderWidget(IRenderWidget &inWidget)
+ {
+ // The if the layer is not active then the widget can't be displayed.
+ // Furthermore ResetForFrame won't be called below which leads to stale
+ // widgets in the m_IRenderWidgets array. These stale widgets would get rendered
+ // the next time the layer was active potentially causing a crash.
+ if (!m_Layer.m_Flags.IsActive())
+ return;
+
+ // Ensure we clear the widget layer always
+ m_Renderer.LayerNeedsFrameClear(*static_cast<SLayerRenderData *>(this));
+
+ if (m_IRenderWidgets.size() < MAX_LAYER_WIDGETS)
+ m_IRenderWidgets.push_back(&inWidget);
+ }
+
+#define RENDER_FRAME_NEW(type) QT3DS_NEW(m_Renderer.GetPerFrameAllocator(), type)
+
+#define QT3DS_RENDER_MINIMUM_RENDER_OPACITY .01f
+
+ SShaderDefaultMaterialKey
+ SLayerRenderPreparationData::GenerateLightingKey(DefaultMaterialLighting::Enum inLightingType)
+ {
+ SShaderDefaultMaterialKey theGeneratedKey(GetShaderFeatureSetHash());
+ const bool lighting = inLightingType != DefaultMaterialLighting::NoLighting;
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_HasLighting.SetValue(theGeneratedKey,
+ lighting);
+ if (lighting) {
+ const bool lightProbe = m_Layer.m_LightProbe
+ && m_Layer.m_LightProbe->m_TextureData.m_Texture;
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_HasIbl.SetValue(theGeneratedKey,
+ lightProbe);
+
+ QT3DSU32 numLights = (QT3DSU32)m_Lights.size();
+ if (numLights > SShaderDefaultMaterialKeyProperties::LightCount
+ && m_TooManyLightsError == false) {
+ m_TooManyLightsError = true;
+ numLights = SShaderDefaultMaterialKeyProperties::LightCount;
+ qCCritical(INVALID_OPERATION, "Too many lights on layer, max is 7");
+ QT3DS_ASSERT(false);
+ }
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_LightCount.SetValue(theGeneratedKey,
+ numLights);
+
+ for (QT3DSU32 lightIdx = 0, lightEnd = m_Lights.size();
+ lightIdx < lightEnd; ++lightIdx) {
+ SLight *theLight(m_Lights[lightIdx]);
+ const bool isDirectional = theLight->m_LightType == RenderLightTypes::Directional;
+ const bool isArea = theLight->m_LightType == RenderLightTypes::Area;
+ const bool castShadowsArea = (theLight->m_LightType != RenderLightTypes::Area)
+ && (theLight->m_CastShadow);
+
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_LightFlags[lightIdx]
+ .SetValue(theGeneratedKey, !isDirectional);
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_LightAreaFlags[lightIdx]
+ .SetValue(theGeneratedKey, isArea);
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_LightShadowFlags[lightIdx]
+ .SetValue(theGeneratedKey, castShadowsArea);
+ }
+ }
+ return theGeneratedKey;
+ }
+
+ bool SLayerRenderPreparationData::PrepareTextForRender(
+ SText &inText, const QT3DSMat44 &inViewProjection,
+ QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags)
+ {
+ ITextTextureCache *theTextRenderer = m_Renderer.GetQt3DSContext().GetTextureCache();
+ if (theTextRenderer == NULL)
+ return false;
+
+ SRenderableObjectFlags theFlags;
+ theFlags.SetHasTransparency(true);
+ theFlags.SetCompletelyTransparent(inText.m_GlobalOpacity < .01f);
+ theFlags.SetPickable(true);
+ bool retval = false;
+
+ if (theFlags.IsCompletelyTransparent() == false) {
+ retval = inText.m_Flags.IsDirty() || inText.m_Flags.IsTextDirty();
+ inText.m_Flags.SetTextDirty(false);
+ QT3DSMat44 theMVP;
+ QT3DSMat33 theNormalMatrix;
+ inText.CalculateMVPAndNormalMatrix(inViewProjection, theMVP, theNormalMatrix);
+
+ SRenderableObject *theRenderable = nullptr;
+
+#if QT_VERSION >= QT_VERSION_CHECK(5,12,2)
+ Q3DSDistanceFieldRenderer *distanceFieldText
+ = static_cast<Q3DSDistanceFieldRenderer *>(
+ m_Renderer.GetQt3DSContext().getDistanceFieldRenderer());
+ theRenderable = RENDER_FRAME_NEW(SDistanceFieldRenderable)(
+ theFlags, inText.GetGlobalPos(), inText, inText.m_Bounds, theMVP,
+ *distanceFieldText);
+#else
+ TTPathObjectAndTexture theResult
+ = theTextRenderer->RenderText(inText, inTextScaleFactor);
+ inText.m_TextTexture = theResult.second.second.mPtr;
+ inText.m_TextTextureDetails = theResult.second.first;
+ inText.m_PathFontItem = theResult.first.second;
+ inText.m_PathFontDetails = theResult.first.first;
+ STextScaleAndOffset theScaleAndOffset(*inText.m_TextTexture,
+ inText.m_TextTextureDetails, inText);
+ QT3DSVec2 theTextScale(theScaleAndOffset.m_TextScale);
+ QT3DSVec2 theTextOffset(theScaleAndOffset.m_TextOffset);
+ QT3DSVec3 minimum(theTextOffset[0] - theTextScale[0],
+ theTextOffset[1] - theTextScale[1], 0);
+ QT3DSVec3 maximum(theTextOffset[0] + theTextScale[0],
+ theTextOffset[1] + theTextScale[1], 0);
+ inText.m_Bounds = NVBounds3(minimum, maximum);
+
+ if (inText.m_PathFontDetails)
+ ioFlags.SetRequiresStencilBuffer(true);
+
+ theRenderable = RENDER_FRAME_NEW(STextRenderable)(
+ theFlags, inText.GetGlobalPos(), m_Renderer, inText, inText.m_Bounds, theMVP,
+ inViewProjection, *inText.m_TextTexture, theTextOffset, theTextScale);
+#endif
+ // After preparation, do not push object back to queue if it is not
+ // active, because we prepare text elements regardless of their
+ // visibility (=active status).
+ if (inText.m_Flags.IsGloballyActive())
+ m_TransparentObjects.push_back(theRenderable);
+ }
+ return retval;
+ }
+
+ eastl::pair<bool, SGraphObject *>
+ SLayerRenderPreparationData::ResolveReferenceMaterial(SGraphObject *inMaterial)
+ {
+ bool subsetDirty = false;
+ bool badIdea = false;
+ SGraphObject *theSourceMaterialObject(inMaterial);
+ SGraphObject *theMaterialObject(inMaterial);
+ while (theMaterialObject
+ && theMaterialObject->m_Type == GraphObjectTypes::ReferencedMaterial && !badIdea) {
+ SReferencedMaterial *theRefMaterial =
+ static_cast<SReferencedMaterial *>(theMaterialObject);
+ theMaterialObject = theRefMaterial->m_ReferencedMaterial;
+ if (theMaterialObject == theSourceMaterialObject) {
+ badIdea = true;
+ }
+
+ if (theRefMaterial == theSourceMaterialObject) {
+ theRefMaterial->m_Dirty.UpdateDirtyForFrame();
+ }
+ subsetDirty = subsetDirty | theRefMaterial->m_Dirty.IsDirty();
+ }
+ if (badIdea) {
+ theMaterialObject = NULL;
+ }
+ return eastl::make_pair(subsetDirty, theMaterialObject);
+ }
+
+ bool SLayerRenderPreparationData::PreparePathForRender(
+ SPath &inPath, const QT3DSMat44 &inViewProjection,
+ const Option<SClippingFrustum> &inClipFrustum, SLayerRenderPreparationResultFlags &ioFlags)
+ {
+ SRenderableObjectFlags theSharedFlags;
+ theSharedFlags.SetPickable(true);
+ QT3DSF32 subsetOpacity = inPath.m_GlobalOpacity;
+ bool retval = inPath.m_Flags.IsDirty();
+ inPath.m_Flags.SetDirty(false);
+ QT3DSMat44 theMVP;
+ QT3DSMat33 theNormalMatrix;
+
+ inPath.CalculateMVPAndNormalMatrix(inViewProjection, theMVP, theNormalMatrix);
+ NVBounds3 theBounds(this->m_Renderer.GetQt3DSContext().GetPathManager().GetBounds(inPath));
+
+ if (inPath.m_GlobalOpacity >= QT3DS_RENDER_MINIMUM_RENDER_OPACITY
+ && inClipFrustum.hasValue()) {
+ // Check bounding box against the clipping planes
+ NVBounds3 theGlobalBounds = theBounds;
+ theGlobalBounds.transform(inPath.m_GlobalTransform);
+ if (inClipFrustum->intersectsWith(theGlobalBounds) == false)
+ subsetOpacity = 0.0f;
+ }
+
+ SGraphObject *theMaterials[2] = { inPath.m_Material, inPath.m_SecondMaterial };
+
+ if (inPath.m_PathType == PathTypes::Geometry
+ || inPath.m_PaintStyle != PathPaintStyles::FilledAndStroked)
+ theMaterials[1] = NULL;
+
+ // We need to fill material to be the first one rendered so the stroke goes on top.
+ // In the timeline, however, this is reversed.
+
+ if (theMaterials[1])
+ eastl::swap(theMaterials[1], theMaterials[0]);
+
+ for (QT3DSU32 idx = 0, end = 2; idx < end; ++idx) {
+ if (theMaterials[idx] == NULL)
+ continue;
+
+ SRenderableObjectFlags theFlags = theSharedFlags;
+
+ eastl::pair<bool, SGraphObject *> theMaterialAndDirty(
+ ResolveReferenceMaterial(theMaterials[idx]));
+ SGraphObject *theMaterial(theMaterialAndDirty.second);
+ retval = retval || theMaterialAndDirty.first;
+
+ if (theMaterial != NULL && theMaterial->m_Type == GraphObjectTypes::DefaultMaterial) {
+ SDefaultMaterial *theDefaultMaterial = static_cast<SDefaultMaterial *>(theMaterial);
+ // Don't clear dirty flags if the material was referenced.
+ bool clearMaterialFlags = theMaterial == inPath.m_Material;
+ SDefaultMaterialPreparationResult prepResult(PrepareDefaultMaterialForRender(
+ *theDefaultMaterial, theFlags, subsetOpacity, clearMaterialFlags));
+
+ theFlags = prepResult.m_RenderableFlags;
+ if (inPath.m_PathType == PathTypes::Geometry) {
+ if ((inPath.m_BeginCapping != PathCapping::Noner
+ && inPath.m_BeginCapOpacity < 1.0f)
+ || (inPath.m_EndCapping != PathCapping::Noner
+ && inPath.m_EndCapOpacity < 1.0f))
+ theFlags.SetHasTransparency(true);
+ } else {
+ ioFlags.SetRequiresStencilBuffer(true);
+ }
+ retval = retval || prepResult.m_Dirty;
+ bool isStroke = true;
+ if (idx == 0 && inPath.m_PathType == PathTypes::Painted) {
+ if (inPath.m_PaintStyle == PathPaintStyles::Filled
+ || inPath.m_PaintStyle == PathPaintStyles::FilledAndStroked)
+ isStroke = false;
+ }
+
+ SPathRenderable *theRenderable = RENDER_FRAME_NEW(SPathRenderable)(
+ theFlags, inPath.GetGlobalPos(), m_Renderer, inPath.m_GlobalTransform,
+ theBounds, inPath, theMVP, theNormalMatrix, *theMaterial, prepResult.m_Opacity,
+ prepResult.m_MaterialKey, isStroke);
+ theRenderable->m_FirstImage = prepResult.m_FirstImage;
+
+ IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext());
+ IPathManager &thePathManager = qt3dsContext.GetPathManager();
+ retval = thePathManager.PrepareForRender(inPath) || retval;
+ retval |= (inPath.m_WireframeMode != qt3dsContext.GetWireframeMode());
+ inPath.m_WireframeMode = qt3dsContext.GetWireframeMode();
+
+ if (theFlags.HasTransparency())
+ m_TransparentObjects.push_back(theRenderable);
+ else
+ m_OpaqueObjects.push_back(theRenderable);
+ } else if (theMaterial != NULL
+ && theMaterial->m_Type == GraphObjectTypes::CustomMaterial) {
+ SCustomMaterial *theCustomMaterial = static_cast<SCustomMaterial *>(theMaterial);
+ // Don't clear dirty flags if the material was referenced.
+ // bool clearMaterialFlags = theMaterial == inPath.m_Material;
+ SDefaultMaterialPreparationResult prepResult(
+ PrepareCustomMaterialForRender(*theCustomMaterial, theFlags, subsetOpacity));
+
+ theFlags = prepResult.m_RenderableFlags;
+ if (inPath.m_PathType == PathTypes::Geometry) {
+ if ((inPath.m_BeginCapping != PathCapping::Noner
+ && inPath.m_BeginCapOpacity < 1.0f)
+ || (inPath.m_EndCapping != PathCapping::Noner
+ && inPath.m_EndCapOpacity < 1.0f))
+ theFlags.SetHasTransparency(true);
+ } else {
+ ioFlags.SetRequiresStencilBuffer(true);
+ }
+
+ retval = retval || prepResult.m_Dirty;
+ bool isStroke = true;
+ if (idx == 0 && inPath.m_PathType == PathTypes::Painted) {
+ if (inPath.m_PaintStyle == PathPaintStyles::Filled
+ || inPath.m_PaintStyle == PathPaintStyles::FilledAndStroked)
+ isStroke = false;
+ }
+
+ SPathRenderable *theRenderable = RENDER_FRAME_NEW(SPathRenderable)(
+ theFlags, inPath.GetGlobalPos(), m_Renderer, inPath.m_GlobalTransform,
+ theBounds, inPath, theMVP, theNormalMatrix, *theMaterial, prepResult.m_Opacity,
+ prepResult.m_MaterialKey, isStroke);
+ theRenderable->m_FirstImage = prepResult.m_FirstImage;
+
+ IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext());
+ IPathManager &thePathManager = qt3dsContext.GetPathManager();
+ retval = thePathManager.PrepareForRender(inPath) || retval;
+ retval |= (inPath.m_WireframeMode != qt3dsContext.GetWireframeMode());
+ inPath.m_WireframeMode = qt3dsContext.GetWireframeMode();
+
+ if (theFlags.HasTransparency())
+ m_TransparentObjects.push_back(theRenderable);
+ else
+ m_OpaqueObjects.push_back(theRenderable);
+ }
+ }
+ return retval;
+ }
+
+ void SLayerRenderPreparationData::PrepareImageForRender(
+ SImage &inImage, ImageMapTypes::Enum inMapType, SRenderableImage *&ioFirstImage,
+ SRenderableImage *&ioNextImage, SRenderableObjectFlags &ioFlags,
+ SShaderDefaultMaterialKey &inShaderKey, QT3DSU32 inImageIndex)
+ {
+ IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext());
+ IBufferManager &bufferManager = qt3dsContext.GetBufferManager();
+ IOffscreenRenderManager &theOffscreenRenderManager(
+ qt3dsContext.GetOffscreenRenderManager());
+ IRenderPluginManager &theRenderPluginManager(qt3dsContext.GetRenderPluginManager());
+ if (inImage.ClearDirty(bufferManager, theOffscreenRenderManager, theRenderPluginManager))
+ ioFlags |= RenderPreparationResultFlagValues::Dirty;
+
+ // All objects with offscreen renderers are pickable so we can pass the pick through to the
+ // offscreen renderer and let it deal with the pick.
+ if (inImage.m_LastFrameOffscreenRenderer != NULL) {
+ ioFlags.SetPickable(true);
+ ioFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ }
+
+ if (inImage.m_TextureData.m_Texture) {
+ if (inImage.m_TextureData.m_TextureFlags.HasTransparency()
+ && (inMapType == ImageMapTypes::Diffuse
+ || inMapType == ImageMapTypes::Opacity
+ || inMapType == ImageMapTypes::Translucency)) {
+ ioFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ }
+ // Textures used in general have linear characteristics.
+ // PKC -- The filters are properly set already. Setting them here only overrides what
+ // would
+ // otherwise be a correct setting.
+ // inImage.m_TextureData.m_Texture->SetMinFilter( NVRenderTextureMinifyingOp::Linear );
+ // inImage.m_TextureData.m_Texture->SetMagFilter( NVRenderTextureMagnifyingOp::Linear );
+
+ SRenderableImage *theImage = RENDER_FRAME_NEW(SRenderableImage)(inMapType, inImage);
+ SShaderKeyImageMap &theKeyProp =
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_ImageMaps[inImageIndex];
+
+ theKeyProp.SetEnabled(inShaderKey, true);
+ switch (inImage.m_MappingMode) {
+ default:
+ QT3DS_ASSERT(false);
+ // fallthrough intentional
+ case ImageMappingModes::Normal:
+ break;
+ case ImageMappingModes::Environment:
+ theKeyProp.SetEnvMap(inShaderKey, true);
+ break;
+ case ImageMappingModes::LightProbe:
+ theKeyProp.SetLightProbe(inShaderKey, true);
+ break;
+ }
+
+ if (inImage.m_TextureData.m_TextureFlags.IsInvertUVCoords())
+ theKeyProp.SetInvertUVMap(inShaderKey, true);
+ if (ioFirstImage == NULL)
+ ioFirstImage = theImage;
+ else
+ ioNextImage->m_NextImage = theImage;
+
+ if (inImage.m_TextureData.m_TextureFlags.IsPreMultiplied())
+ theKeyProp.SetPremultiplied(inShaderKey, true);
+
+ SShaderKeyTextureSwizzle &theSwizzleKeyProp =
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_TextureSwizzle[inImageIndex];
+ theSwizzleKeyProp.SetSwizzleMode(
+ inShaderKey, inImage.m_TextureData.m_Texture->GetTextureSwizzleMode(), true);
+
+ ioNextImage = theImage;
+ }
+ }
+
+ SDefaultMaterialPreparationResult SLayerRenderPreparationData::PrepareDefaultMaterialForRender(
+ SDefaultMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
+ bool inClearDirtyFlags)
+ {
+ SDefaultMaterial *theMaterial = &inMaterial;
+ SDefaultMaterialPreparationResult retval(GenerateLightingKey(theMaterial->m_Lighting));
+ retval.m_RenderableFlags = inExistingFlags;
+ SRenderableObjectFlags &renderableFlags(retval.m_RenderableFlags);
+ SShaderDefaultMaterialKey &theGeneratedKey(retval.m_MaterialKey);
+ retval.m_Opacity = inOpacity;
+ QT3DSF32 &subsetOpacity(retval.m_Opacity);
+
+ if (theMaterial->m_Dirty.IsDirty()) {
+ renderableFlags |= RenderPreparationResultFlagValues::Dirty;
+ }
+ subsetOpacity *= theMaterial->m_Opacity;
+ if (inClearDirtyFlags)
+ theMaterial->m_Dirty.UpdateDirtyForFrame();
+
+ SRenderableImage *firstImage = NULL;
+
+ // set wireframe mode
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue(
+ theGeneratedKey, m_Renderer.GetQt3DSContext().GetWireframeMode());
+
+ if (theMaterial->m_IblProbe && CheckLightProbeDirty(*theMaterial->m_IblProbe)) {
+ m_Renderer.PrepareImageForIbl(*theMaterial->m_IblProbe);
+ }
+
+ if (!m_Renderer.DefaultMaterialShaderKeyProperties().m_HasIbl.GetValue(theGeneratedKey)) {
+ bool lightProbeValid = HasValidLightProbe(theMaterial->m_IblProbe);
+ SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE", lightProbeValid);
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_HasIbl.SetValue(theGeneratedKey,
+ lightProbeValid);
+ // SetShaderFeature( "QT3DS_ENABLE_IBL_FOV",
+ // m_Renderer.GetLayerRenderData()->m_Layer.m_ProbeFov < 180.0f );
+ }
+
+ if (subsetOpacity >= QT3DS_RENDER_MINIMUM_RENDER_OPACITY) {
+
+ if (theMaterial->m_BlendMode != DefaultMaterialBlendMode::Normal
+ || theMaterial->m_OpacityMap) {
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ }
+
+ bool specularEnabled = theMaterial->IsSpecularEnabled();
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_SpecularEnabled.SetValue(
+ theGeneratedKey, specularEnabled);
+ if (specularEnabled) {
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_SpecularModel.SetSpecularModel(
+ theGeneratedKey, theMaterial->m_SpecularModel);
+ }
+
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_FresnelEnabled.SetValue(
+ theGeneratedKey, theMaterial->IsFresnelEnabled());
+
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_VertexColorsEnabled.SetValue(
+ theGeneratedKey, theMaterial->IsVertexColorsEnabled());
+
+ // Run through the material's images and prepare them for render.
+ // this may in fact set pickable on the renderable flags if one of the images
+ // links to a sub presentation or any offscreen rendered object.
+ SRenderableImage *nextImage = NULL;
+#define CHECK_IMAGE_AND_PREPARE(img, imgtype, shadercomponent) \
+ if ((img)) \
+ PrepareImageForRender(*(img), imgtype, firstImage, nextImage, renderableFlags, \
+ theGeneratedKey, shadercomponent);
+
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[0], ImageMapTypes::Diffuse,
+ SShaderDefaultMaterialKeyProperties::DiffuseMap0);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[1], ImageMapTypes::Diffuse,
+ SShaderDefaultMaterialKeyProperties::DiffuseMap1);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_DiffuseMaps[2], ImageMapTypes::Diffuse,
+ SShaderDefaultMaterialKeyProperties::DiffuseMap2);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_EmissiveMap, ImageMapTypes::Emissive,
+ SShaderDefaultMaterialKeyProperties::EmissiveMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_EmissiveMap2, ImageMapTypes::Emissive,
+ SShaderDefaultMaterialKeyProperties::EmissiveMap2);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_SpecularReflection, ImageMapTypes::Specular,
+ SShaderDefaultMaterialKeyProperties::SpecularMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_RoughnessMap, ImageMapTypes::Roughness,
+ SShaderDefaultMaterialKeyProperties::RoughnessMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_OpacityMap, ImageMapTypes::Opacity,
+ SShaderDefaultMaterialKeyProperties::OpacityMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_BumpMap, ImageMapTypes::Bump,
+ SShaderDefaultMaterialKeyProperties::BumpMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_SpecularMap, ImageMapTypes::SpecularAmountMap,
+ SShaderDefaultMaterialKeyProperties::SpecularAmountMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_NormalMap, ImageMapTypes::Normal,
+ SShaderDefaultMaterialKeyProperties::NormalMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_DisplacementMap, ImageMapTypes::Displacement,
+ SShaderDefaultMaterialKeyProperties::DisplacementMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_TranslucencyMap, ImageMapTypes::Translucency,
+ SShaderDefaultMaterialKeyProperties::TranslucencyMap);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapIndirect,
+ ImageMapTypes::LightmapIndirect,
+ SShaderDefaultMaterialKeyProperties::LightmapIndirect);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapRadiosity,
+ ImageMapTypes::LightmapRadiosity,
+ SShaderDefaultMaterialKeyProperties::LightmapRadiosity);
+ CHECK_IMAGE_AND_PREPARE(theMaterial->m_Lightmaps.m_LightmapShadow,
+ ImageMapTypes::LightmapShadow,
+ SShaderDefaultMaterialKeyProperties::LightmapShadow);
+ }
+#undef CHECK_IMAGE_AND_PREPARE
+
+ if (subsetOpacity < QT3DS_RENDER_MINIMUM_RENDER_OPACITY) {
+ subsetOpacity = 0.0f;
+ // You can still pick against completely transparent objects(or rather their bounding
+ // box)
+ // you just don't render them.
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ renderableFlags |= RenderPreparationResultFlagValues::CompletelyTransparent;
+ }
+
+ if (IsNotOne(subsetOpacity))
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+
+ retval.m_FirstImage = firstImage;
+ if (retval.m_RenderableFlags.IsDirty())
+ retval.m_Dirty = true;
+ return retval;
+ }
+
+ SDefaultMaterialPreparationResult SLayerRenderPreparationData::PrepareCustomMaterialForRender(
+ SCustomMaterial &inMaterial, SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity)
+ {
+ SDefaultMaterialPreparationResult retval(GenerateLightingKey(
+ DefaultMaterialLighting::FragmentLighting)); // always fragment lighting
+ retval.m_RenderableFlags = inExistingFlags;
+ SRenderableObjectFlags &renderableFlags(retval.m_RenderableFlags);
+ SShaderDefaultMaterialKey &theGeneratedKey(retval.m_MaterialKey);
+ retval.m_Opacity = inOpacity;
+ QT3DSF32 &subsetOpacity(retval.m_Opacity);
+
+ // If the custom material uses subpresentations, those have to be rendered before
+ // the custom material itself
+ m_Renderer.GetQt3DSContext().GetCustomMaterialSystem().renderSubpresentations(inMaterial);
+
+ // set wireframe mode
+ m_Renderer.DefaultMaterialShaderKeyProperties().m_WireframeMode.SetValue(
+ theGeneratedKey, m_Renderer.GetQt3DSContext().GetWireframeMode());
+
+ if (subsetOpacity < QT3DS_RENDER_MINIMUM_RENDER_OPACITY) {
+ subsetOpacity = 0.0f;
+ // You can still pick against completely transparent objects(or rather their bounding
+ // box)
+ // you just don't render them.
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ renderableFlags |= RenderPreparationResultFlagValues::CompletelyTransparent;
+ }
+
+ if (IsNotOne(subsetOpacity))
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+
+ SRenderableImage *firstImage = NULL;
+ SRenderableImage *nextImage = NULL;
+
+#define CHECK_IMAGE_AND_PREPARE(img, imgtype, shadercomponent) \
+ if ((img)) \
+ PrepareImageForRender(*(img), imgtype, firstImage, nextImage, renderableFlags, \
+ theGeneratedKey, shadercomponent);
+
+ CHECK_IMAGE_AND_PREPARE(inMaterial.m_DisplacementMap, ImageMapTypes::Displacement,
+ SShaderDefaultMaterialKeyProperties::DisplacementMap);
+ CHECK_IMAGE_AND_PREPARE(inMaterial.m_Lightmaps.m_LightmapIndirect,
+ ImageMapTypes::LightmapIndirect,
+ SShaderDefaultMaterialKeyProperties::LightmapIndirect);
+ CHECK_IMAGE_AND_PREPARE(inMaterial.m_Lightmaps.m_LightmapRadiosity,
+ ImageMapTypes::LightmapRadiosity,
+ SShaderDefaultMaterialKeyProperties::LightmapRadiosity);
+ CHECK_IMAGE_AND_PREPARE(inMaterial.m_Lightmaps.m_LightmapShadow,
+ ImageMapTypes::LightmapShadow,
+ SShaderDefaultMaterialKeyProperties::LightmapShadow);
+#undef CHECK_IMAGE_AND_PREPARE
+
+ retval.m_FirstImage = firstImage;
+ return retval;
+ }
+
+ bool SLayerRenderPreparationData::PrepareModelForRender(
+ SModel &inModel, const QT3DSMat44 &inViewProjection,
+ const Option<SClippingFrustum> &inClipFrustum, TNodeLightEntryList &inScopedLights)
+ {
+ IQt3DSRenderContext &qt3dsContext(m_Renderer.GetQt3DSContext());
+ IBufferManager &bufferManager = qt3dsContext.GetBufferManager();
+ SRenderMesh *theMesh = bufferManager.LoadMesh(inModel.m_MeshPath);
+ if (theMesh == NULL)
+ return false;
+
+ SGraphObject *theSourceMaterialObject = inModel.m_FirstMaterial;
+ SModelContext &theModelContext =
+ *RENDER_FRAME_NEW(SModelContext)(inModel, inViewProjection);
+ m_ModelContexts.push_back(&theModelContext);
+
+ bool subsetDirty = false;
+
+ SScopedLightsListScope lightsScope(m_Lights, m_LightDirections, m_SourceLightDirections,
+ inScopedLights);
+ SetShaderFeature(m_CGLightingFeatureName, m_Lights.empty() == false);
+ for (QT3DSU32 idx = 0, end = theMesh->m_Subsets.size(); idx < end && theSourceMaterialObject;
+ ++idx, theSourceMaterialObject = GetNextMaterialSibling(theSourceMaterialObject)) {
+ SRenderSubset &theOuterSubset(theMesh->m_Subsets[idx]);
+ {
+ SRenderSubset &theSubset(theOuterSubset);
+ SRenderableObjectFlags renderableFlags;
+ renderableFlags.SetPickable(false);
+ renderableFlags.SetShadowCaster(inModel.m_ShadowCaster);
+ QT3DSF32 subsetOpacity = inModel.m_GlobalOpacity;
+ QT3DSVec3 theModelCenter(theSubset.m_Bounds.getCenter());
+ theModelCenter = inModel.m_GlobalTransform.transform(theModelCenter);
+
+ if (subsetOpacity >= QT3DS_RENDER_MINIMUM_RENDER_OPACITY
+ && inClipFrustum.hasValue()) {
+ // Check bounding box against the clipping planes
+ NVBounds3 theGlobalBounds = theSubset.m_Bounds;
+ theGlobalBounds.transform(theModelContext.m_Model.m_GlobalTransform);
+ if (inClipFrustum->intersectsWith(theGlobalBounds) == false)
+ subsetOpacity = 0.0f;
+ }
+
+ // For now everything is pickable. Eventually we want to have localPickable and
+ // globalPickable set on the node during
+ // updates and have the runtime tell us what is pickable and what is not pickable.
+ // Completely transparent models cannot be pickable. But models with completely
+ // transparent materials
+ // still are. This allows the artist to control pickability in a somewhat
+ // fine-grained style.
+ bool canModelBePickable = inModel.m_GlobalOpacity > .01f;
+ renderableFlags.SetPickable(canModelBePickable
+ && (theModelContext.m_Model.m_Flags.IsGloballyPickable()
+ || renderableFlags.GetPickable()));
+ SRenderableObject *theRenderableObject(NULL);
+ eastl::pair<bool, SGraphObject *> theMaterialObjectAndDirty =
+ ResolveReferenceMaterial(theSourceMaterialObject);
+ SGraphObject *theMaterialObject = theMaterialObjectAndDirty.second;
+ subsetDirty = subsetDirty || theMaterialObjectAndDirty.first;
+ if (theMaterialObject == NULL)
+ continue;
+
+ // set tessellation
+ if (inModel.m_TessellationMode != TessModeValues::NoTess) {
+ theSubset.m_PrimitiveType = NVRenderDrawMode::Patches;
+ // set tessellation factor
+ theSubset.m_EdgeTessFactor = inModel.m_EdgeTess;
+ theSubset.m_InnerTessFactor = inModel.m_InnerTess;
+ // update the vertex ver patch count in the input assembler
+ // currently we only support triangle patches so count is always 3
+ theSubset.m_InputAssembler->SetPatchVertexCount(3);
+ theSubset.m_InputAssemblerDepth->SetPatchVertexCount(3);
+ // check wireframe mode
+ theSubset.m_WireframeMode = qt3dsContext.GetWireframeMode();
+
+ subsetDirty =
+ subsetDirty | (theSubset.m_WireframeMode != inModel.m_WireframeMode);
+ inModel.m_WireframeMode = qt3dsContext.GetWireframeMode();
+ } else {
+ theSubset.m_PrimitiveType = theSubset.m_InputAssembler->GetPrimitiveType();
+ theSubset.m_InputAssembler->SetPatchVertexCount(1);
+ theSubset.m_InputAssemblerDepth->SetPatchVertexCount(1);
+ // currently we allow wirframe mode only if tessellation is on
+ theSubset.m_WireframeMode = false;
+
+ subsetDirty =
+ subsetDirty | (theSubset.m_WireframeMode != inModel.m_WireframeMode);
+ inModel.m_WireframeMode = false;
+ }
+ // Only clear flags on the materials in this direct hierarchy. Do not clear them of
+ // this
+ // references materials in another hierarchy.
+ bool clearMaterialDirtyFlags = theMaterialObject == theSourceMaterialObject;
+
+ if (theMaterialObject == NULL)
+ continue;
+
+ if (theMaterialObject->m_Type == GraphObjectTypes::DefaultMaterial) {
+ SDefaultMaterial &theMaterial(
+ static_cast<SDefaultMaterial &>(*theMaterialObject));
+ SDefaultMaterialPreparationResult theMaterialPrepResult(
+ PrepareDefaultMaterialForRender(theMaterial, renderableFlags, subsetOpacity,
+ clearMaterialDirtyFlags));
+ SShaderDefaultMaterialKey theGeneratedKey = theMaterialPrepResult.m_MaterialKey;
+ subsetOpacity = theMaterialPrepResult.m_Opacity;
+ SRenderableImage *firstImage(theMaterialPrepResult.m_FirstImage);
+ subsetDirty |= theMaterialPrepResult.m_Dirty;
+ renderableFlags = theMaterialPrepResult.m_RenderableFlags;
+
+ m_Renderer.DefaultMaterialShaderKeyProperties()
+ .m_TessellationMode.SetTessellationMode(theGeneratedKey,
+ inModel.m_TessellationMode, true);
+
+ NVConstDataRef<QT3DSMat44> boneGlobals;
+ if (theSubset.m_Joints.size()) {
+ QT3DS_ASSERT(false);
+ }
+
+ theRenderableObject = RENDER_FRAME_NEW(SSubsetRenderable)(
+ renderableFlags, theModelCenter, m_Renderer, theSubset, theMaterial,
+ theModelContext, subsetOpacity, firstImage, theGeneratedKey, boneGlobals);
+ subsetDirty = subsetDirty || renderableFlags.IsDirty();
+
+ } // if type == DefaultMaterial
+ else if (theMaterialObject->m_Type == GraphObjectTypes::CustomMaterial) {
+ SCustomMaterial &theMaterial(
+ static_cast<SCustomMaterial &>(*theMaterialObject));
+
+ ICustomMaterialSystem &theMaterialSystem(
+ qt3dsContext.GetCustomMaterialSystem());
+ subsetDirty |= theMaterialSystem.PrepareForRender(
+ theModelContext.m_Model, theSubset, theMaterial, clearMaterialDirtyFlags);
+
+ SDefaultMaterialPreparationResult theMaterialPrepResult(
+ PrepareCustomMaterialForRender(theMaterial, renderableFlags,
+ subsetOpacity));
+ SShaderDefaultMaterialKey theGeneratedKey = theMaterialPrepResult.m_MaterialKey;
+ subsetOpacity = theMaterialPrepResult.m_Opacity;
+ SRenderableImage *firstImage(theMaterialPrepResult.m_FirstImage);
+ renderableFlags = theMaterialPrepResult.m_RenderableFlags;
+
+ // prepare for render tells us if the object is transparent
+ if (theMaterial.m_hasTransparency)
+ renderableFlags |= RenderPreparationResultFlagValues::HasTransparency;
+ // prepare for render tells us if the object is transparent
+ if (theMaterial.m_hasRefraction)
+ renderableFlags |= RenderPreparationResultFlagValues::HasRefraction;
+
+ m_Renderer.DefaultMaterialShaderKeyProperties()
+ .m_TessellationMode.SetTessellationMode(theGeneratedKey,
+ inModel.m_TessellationMode, true);
+
+ if (theMaterial.m_IblProbe && CheckLightProbeDirty(*theMaterial.m_IblProbe)) {
+ m_Renderer.PrepareImageForIbl(*theMaterial.m_IblProbe);
+ }
+
+ theRenderableObject = RENDER_FRAME_NEW(SCustomMaterialRenderable)(
+ renderableFlags, theModelCenter, m_Renderer, theSubset, theMaterial,
+ theModelContext, subsetOpacity, firstImage, theGeneratedKey);
+ }
+ if (theRenderableObject) {
+ theRenderableObject->m_ScopedLights = inScopedLights;
+ // set tessellation
+ theRenderableObject->m_TessellationMode = inModel.m_TessellationMode;
+
+ if (theRenderableObject->m_RenderableFlags.HasTransparency()
+ || theRenderableObject->m_RenderableFlags.HasRefraction()) {
+ m_TransparentObjects.push_back(theRenderableObject);
+ } else {
+ m_OpaqueObjects.push_back(theRenderableObject);
+ }
+ }
+ }
+ }
+ return subsetDirty;
+ }
+
+ bool SLayerRenderPreparationData::PrepareRenderablesForRender(
+ const QT3DSMat44 &inViewProjection, const Option<SClippingFrustum> &inClipFrustum,
+ QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags)
+ {
+ SStackPerfTimer __timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::PrepareRenderablesForRender");
+ m_ViewProjection = inViewProjection;
+ QT3DSF32 theTextScaleFactor = inTextScaleFactor;
+ bool wasDataDirty = false;
+ bool hasTextRenderer = m_Renderer.GetQt3DSContext().GetTextRenderer() != NULL;
+ for (QT3DSU32 idx = 0, end = m_RenderableNodes.size(); idx < end; ++idx) {
+ SRenderableNodeEntry &theNodeEntry(m_RenderableNodes[idx]);
+ SNode *theNode = theNodeEntry.m_Node;
+ wasDataDirty = wasDataDirty || theNode->m_Flags.IsDirty();
+ switch (theNode->m_Type) {
+ case GraphObjectTypes::Model: {
+ SModel *theModel = static_cast<SModel *>(theNode);
+ theModel->CalculateGlobalVariables();
+ if (theModel->m_Flags.IsGloballyActive()) {
+ bool wasModelDirty = PrepareModelForRender(
+ *theModel, inViewProjection, inClipFrustum, theNodeEntry.m_Lights);
+ wasDataDirty = wasDataDirty || wasModelDirty;
+ }
+ } break;
+ case GraphObjectTypes::Text: {
+ if (hasTextRenderer) {
+ SText *theText = static_cast<SText *>(theNode);
+ theText->CalculateGlobalVariables();
+ // Omit check for global active flag intentionally and force
+ // render preparation for all Text items. This eliminates
+ // large delay for distance field text items becoming active
+ // mid-animation.
+ bool wasTextDirty = PrepareTextForRender(*theText, inViewProjection,
+ theTextScaleFactor, ioFlags);
+ wasDataDirty = wasDataDirty || wasTextDirty;
+
+ }
+ } break;
+ case GraphObjectTypes::Path: {
+ SPath *thePath = static_cast<SPath *>(theNode);
+ thePath->CalculateGlobalVariables();
+ if (thePath->m_Flags.IsGloballyActive()) {
+ bool wasPathDirty =
+ PreparePathForRender(*thePath, inViewProjection, inClipFrustum, ioFlags);
+ wasDataDirty = wasDataDirty || wasPathDirty;
+ }
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ return wasDataDirty;
+ }
+
+ bool SLayerRenderPreparationData::CheckLightProbeDirty(SImage &inLightProbe)
+ {
+ IQt3DSRenderContext &theContext(m_Renderer.GetQt3DSContext());
+ return inLightProbe.ClearDirty(theContext.GetBufferManager(),
+ theContext.GetOffscreenRenderManager(),
+ theContext.GetRenderPluginManager(), true);
+ }
+
+ struct SLightNodeMarker
+ {
+ SLight *m_Light;
+ QT3DSU32 m_LightIndex;
+ QT3DSU32 m_FirstValidIndex;
+ QT3DSU32 m_JustPastLastValidIndex;
+ bool m_AddOrRemove;
+ SLightNodeMarker()
+ : m_Light(NULL)
+ , m_FirstValidIndex(0)
+ , m_JustPastLastValidIndex(0)
+ , m_AddOrRemove(false)
+ {
+ }
+ SLightNodeMarker(SLight &inLight, QT3DSU32 inLightIndex, SNode &inNode, bool aorm)
+ : m_Light(&inLight)
+ , m_LightIndex(inLightIndex)
+ , m_AddOrRemove(aorm)
+ {
+ if (inNode.m_Type == GraphObjectTypes::Layer) {
+ m_FirstValidIndex = 0;
+ m_JustPastLastValidIndex = QT3DS_MAX_U32;
+ } else {
+ m_FirstValidIndex = inNode.m_DFSIndex;
+ SNode *lastChild = NULL;
+ SNode *firstChild = inNode.m_FirstChild;
+ // find deepest last child
+ while (firstChild) {
+ for (SNode *childNode = firstChild; childNode;
+ childNode = childNode->m_NextSibling)
+ lastChild = childNode;
+
+ if (lastChild)
+ firstChild = lastChild->m_FirstChild;
+ else
+ firstChild = NULL;
+ }
+ if (lastChild)
+ // last valid index would be the last child index + 1
+ m_JustPastLastValidIndex = lastChild->m_DFSIndex + 1;
+ else // no children.
+ m_JustPastLastValidIndex = m_FirstValidIndex + 1;
+ }
+ }
+ };
+
+ // m_Layer.m_Camera->CalculateViewProjectionMatrix(m_ViewProjection);
+ void
+ SLayerRenderPreparationData::PrepareForRender(const QSize &inViewportDimensions)
+ {
+ SStackPerfTimer __timer(m_Renderer.GetQt3DSContext().GetPerfTimer(),
+ "SLayerRenderData::PrepareForRender");
+ if (m_LayerPrepResult.hasValue())
+ return;
+
+ m_Features.clear();
+ m_FeatureSetHash = 0;
+ QT3DSVec2 thePresentationDimensions((QT3DSF32)inViewportDimensions.width(),
+ (QT3DSF32)inViewportDimensions.height());
+ IRenderList &theGraph(m_Renderer.GetQt3DSContext().GetRenderList());
+ NVRenderRect theViewport(theGraph.GetViewport());
+ NVRenderRect theScissor(theGraph.GetViewport());
+ if (theGraph.IsScissorTestEnabled())
+ theScissor = m_Renderer.GetContext().GetScissorRect();
+ bool wasDirty = false;
+ bool wasDataDirty = false;
+ wasDirty = m_Layer.m_Flags.IsDirty();
+ // The first pass is just to render the data.
+ QT3DSU32 maxNumAAPasses = m_Layer.m_ProgressiveAAMode == AAModeValues::NoAA
+ ? (QT3DSU32)0
+ : (QT3DSU32)(m_Layer.m_ProgressiveAAMode) + 1;
+ maxNumAAPasses = NVMin((QT3DSU32)(MAX_AA_LEVELS + 1), maxNumAAPasses);
+ SEffect *theLastEffect = NULL;
+ // Uncomment the line below to disable all progressive AA.
+ // maxNumAAPasses = 0;
+
+ SLayerRenderPreparationResult thePrepResult;
+ bool hasOffscreenRenderer = GetOffscreenRenderer();
+
+ bool SSAOEnabled = (m_Layer.m_AoStrength > 0.0f && m_Layer.m_AoDistance > 0.0f);
+ bool SSDOEnabled = (m_Layer.m_ShadowStrength > 0.0f && m_Layer.m_ShadowDist > 0.0f);
+ SetShaderFeature("QT3DS_ENABLE_SSAO", SSAOEnabled);
+ SetShaderFeature("QT3DS_ENABLE_SSDO", SSDOEnabled);
+ bool requiresDepthPrepass = (hasOffscreenRenderer == false) && (SSAOEnabled || SSDOEnabled);
+ SetShaderFeature("QT3DS_ENABLE_SSM", false); // by default no shadow map generation
+
+ if (m_Layer.m_Flags.IsActive()) {
+ // Get the layer's width and height.
+ IEffectSystem &theEffectSystem(m_Renderer.GetQt3DSContext().GetEffectSystem());
+ for (SEffect *theEffect = m_Layer.m_FirstEffect; theEffect;
+ theEffect = theEffect->m_NextEffect) {
+ if (theEffect->m_Flags.IsDirty()) {
+ wasDirty = true;
+ theEffect->m_Flags.SetDirty(false);
+ }
+ if (theEffect->m_Flags.IsActive()) {
+ // If the effect uses subpresentations, those have to be rendered before
+ // the effect itself
+ theEffectSystem.renderSubpresentations(*theEffect);
+ theLastEffect = theEffect;
+ if (hasOffscreenRenderer == false
+ && theEffectSystem.DoesEffectRequireDepthTexture(theEffect->m_ClassName))
+ requiresDepthPrepass = true;
+ }
+ }
+ if (m_Layer.m_Flags.IsDirty()) {
+ wasDirty = true;
+ m_Layer.CalculateGlobalVariables();
+ }
+
+ bool shouldRenderToTexture = true;
+
+ if (hasOffscreenRenderer) {
+ // We don't render to texture with offscreen renderers, we just render them to the
+ // viewport.
+ shouldRenderToTexture = false;
+ // Progaa disabled when using offscreen rendering.
+ maxNumAAPasses = 0;
+ }
+
+ thePrepResult = SLayerRenderPreparationResult(SLayerRenderHelper(
+ theViewport, theScissor, m_Layer.m_Scene->m_Presentation->m_PresentationDimensions,
+ m_Layer, shouldRenderToTexture, m_Renderer.GetQt3DSContext().GetScaleMode(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor()));
+ thePrepResult.m_LastEffect = theLastEffect;
+ thePrepResult.m_MaxAAPassIndex = maxNumAAPasses;
+ thePrepResult.m_Flags.SetRequiresDepthTexture(requiresDepthPrepass
+ || NeedsWidgetTexture());
+ thePrepResult.m_Flags.SetShouldRenderToTexture(shouldRenderToTexture);
+ if (m_Renderer.GetContext().GetRenderContextType() != NVRenderContextValues::GLES2)
+ thePrepResult.m_Flags.SetRequiresSsaoPass(SSAOEnabled);
+
+ if (thePrepResult.IsLayerVisible()) {
+ if (shouldRenderToTexture) {
+ m_Renderer.GetQt3DSContext().GetRenderList().AddRenderTask(
+ CreateRenderToTextureRunnable());
+ }
+ if (m_Layer.m_LightProbe && CheckLightProbeDirty(*m_Layer.m_LightProbe)) {
+ m_Renderer.PrepareImageForIbl(*m_Layer.m_LightProbe);
+ wasDataDirty = true;
+ }
+
+ bool lightProbeValid = HasValidLightProbe(m_Layer.m_LightProbe);
+
+ SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE", lightProbeValid);
+ SetShaderFeature("QT3DS_ENABLE_IBL_FOV", m_Layer.m_ProbeFov < 180.0f);
+
+ if (lightProbeValid && m_Layer.m_LightProbe2
+ && CheckLightProbeDirty(*m_Layer.m_LightProbe2)) {
+ m_Renderer.PrepareImageForIbl(*m_Layer.m_LightProbe2);
+ wasDataDirty = true;
+ }
+
+ SetShaderFeature("QT3DS_ENABLE_LIGHT_PROBE_2",
+ lightProbeValid && HasValidLightProbe(m_Layer.m_LightProbe2));
+
+ // Push nodes in reverse depth first order
+ if (m_RenderableNodes.empty()) {
+ m_CamerasAndLights.clear();
+ QT3DSU32 dfsIndex = 0;
+ for (SNode *theChild = m_Layer.m_FirstChild; theChild;
+ theChild = theChild->m_NextSibling)
+ MaybeQueueNodeForRender(*theChild, m_RenderableNodes, m_CamerasAndLights,
+ dfsIndex);
+ reverse(m_CamerasAndLights.begin(), m_CamerasAndLights.end());
+ reverse(m_RenderableNodes.begin(), m_RenderableNodes.end());
+ m_LightToNodeMap.clear();
+ }
+ m_Camera = NULL;
+ m_Lights.clear();
+ m_OpaqueObjects.clear();
+ m_TransparentObjects.clear();
+ nvvector<SLightNodeMarker> theLightNodeMarkers(m_Renderer.GetPerFrameAllocator(),
+ "LightNodeMarkers");
+ m_SourceLightDirections.clear();
+
+ for (QT3DSU32 idx = 0, end = m_CamerasAndLights.size(); idx < end; ++idx) {
+ SNode *theNode(m_CamerasAndLights[idx]);
+ wasDataDirty = wasDataDirty || theNode->m_Flags.IsDirty();
+ switch (theNode->m_Type) {
+ case GraphObjectTypes::Camera: {
+ SCamera *theCamera = static_cast<SCamera *>(theNode);
+ if (theCamera->m_Flags.IsActive()) {
+ // Only proceed with camera nodes which are currently active.
+ // SetupCameraForRender() sets the camera used for picking and
+ // updates global state e.g. IsGloballyActive()
+ SCameraGlobalCalculationResult theResult =
+ thePrepResult.SetupCameraForRender(*theCamera);
+ wasDataDirty = wasDataDirty || theResult.m_WasDirty;
+ if (theCamera->m_Flags.IsGloballyActive())
+ m_Camera = theCamera;
+ if (theResult.m_ComputeFrustumSucceeded == false) {
+ qCCritical(INTERNAL_ERROR, "Failed to calculate camera frustum");
+ }
+ }
+ } break;
+ case GraphObjectTypes::Light: {
+ SLight *theLight = static_cast<SLight *>(theNode);
+ bool lightResult = theLight->CalculateGlobalVariables();
+ wasDataDirty = lightResult || wasDataDirty;
+ // Note we setup the light index such that it is completely invariant of if
+ // the
+ // light is active or scoped.
+ QT3DSU32 lightIndex = (QT3DSU32)m_SourceLightDirections.size();
+ m_SourceLightDirections.push_back(QT3DSVec3(0.0f));
+ // Note we still need a light check when building the renderable light list.
+ // We also cannot cache shader-light bindings based on layers any more
+ // because
+ // the number of lights for a given renderable does not depend on the layer
+ // as it used to but
+ // additional perhaps on the light's scoping rules.
+ if (theLight->m_Flags.IsGloballyActive()) {
+ if (theLight->m_Scope == NULL) {
+ m_Lights.push_back(theLight);
+ if (m_Renderer.GetContext().GetRenderContextType()
+ != NVRenderContextValues::GLES2
+ && theLight->m_CastShadow && GetShadowMapManager()) {
+ // PKC -- use of "res" as an exponent of two is an annoying
+ // artifact of the XML interface
+ // I'll change this with an enum interface later on, but that's
+ // less important right now.
+ QT3DSU32 mapSize = 1 << theLight->m_ShadowMapRes;
+ ShadowMapModes::Enum mapMode =
+ (theLight->m_LightType != RenderLightTypes::Directional)
+ ? ShadowMapModes::CUBE
+ : ShadowMapModes::VSM;
+ m_ShadowMapManager->AddShadowMapEntry(
+ m_Lights.size() - 1, mapSize, mapSize,
+ NVRenderTextureFormats::R16F, 1, mapMode,
+ ShadowFilterValues::NONE);
+ thePrepResult.m_Flags.SetRequiresShadowMapPass(true);
+ SetShaderFeature("QT3DS_ENABLE_SSM", true);
+ }
+ }
+ TLightToNodeMap::iterator iter =
+ m_LightToNodeMap.insert(eastl::make_pair(theLight, (SNode *)NULL))
+ .first;
+ SNode *oldLightScope = iter->second;
+ SNode *newLightScope = theLight->m_Scope;
+
+ if (oldLightScope != newLightScope) {
+ iter->second = newLightScope;
+ if (oldLightScope)
+ theLightNodeMarkers.push_back(SLightNodeMarker(
+ *theLight, lightIndex, *oldLightScope, false));
+ if (newLightScope)
+ theLightNodeMarkers.push_back(SLightNodeMarker(
+ *theLight, lightIndex, *newLightScope, true));
+ }
+ if (newLightScope) {
+ m_SourceLightDirections.back() =
+ theLight->GetScalingCorrectDirection();
+ }
+ }
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+
+ if (theLightNodeMarkers.empty() == false) {
+ for (QT3DSU32 idx = 0, end = m_RenderableNodes.size(); idx < end; ++idx) {
+ SRenderableNodeEntry &theNodeEntry(m_RenderableNodes[idx]);
+ QT3DSU32 nodeDFSIndex = theNodeEntry.m_Node->m_DFSIndex;
+ for (QT3DSU32 markerIdx = 0, markerEnd = theLightNodeMarkers.size();
+ markerIdx < markerEnd; ++markerIdx) {
+ SLightNodeMarker &theMarker = theLightNodeMarkers[markerIdx];
+ if (nodeDFSIndex >= theMarker.m_FirstValidIndex
+ && nodeDFSIndex < theMarker.m_JustPastLastValidIndex) {
+ if (theMarker.m_AddOrRemove) {
+ SNodeLightEntry *theNewEntry =
+ m_RenderableNodeLightEntryPool.construct(
+ theMarker.m_Light, theMarker.m_LightIndex, __FILE__,
+ __LINE__);
+ theNodeEntry.m_Lights.push_back(*theNewEntry);
+ } else {
+ for (TNodeLightEntryList::iterator
+ lightIter = theNodeEntry.m_Lights.begin(),
+ lightEnd = theNodeEntry.m_Lights.end();
+ lightIter != lightEnd; ++lightIter) {
+ if (lightIter->m_Light == theMarker.m_Light) {
+ SNodeLightEntry &theEntry = *lightIter;
+ theNodeEntry.m_Lights.remove(theEntry);
+ m_RenderableNodeLightEntryPool.deallocate(&theEntry);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ QT3DSF32 theTextScaleFactor = 1.0f;
+ if (m_Camera) {
+ m_Camera->CalculateViewProjectionMatrix(m_ViewProjection);
+ theTextScaleFactor = m_Camera->GetTextScaleFactor(
+ thePrepResult.GetLayerToPresentationViewport(),
+ thePrepResult.GetPresentationDesignDimensions());
+ SClipPlane nearPlane;
+ QT3DSMat33 theUpper33(m_Camera->m_GlobalTransform.getUpper3x3InverseTranspose());
+
+ QT3DSVec3 dir(theUpper33.transform(QT3DSVec3(0, 0, -1)));
+ dir.normalize();
+ nearPlane.normal = dir;
+ QT3DSVec3 theGlobalPos = m_Camera->GetGlobalPos() + m_Camera->m_ClipNear * dir;
+ nearPlane.d = -(dir.dot(theGlobalPos));
+ // the near plane's bbox edges are calculated in the clipping frustum's
+ // constructor.
+ m_ClippingFrustum = SClippingFrustum(m_ViewProjection, nearPlane);
+ } else {
+ m_ViewProjection = QT3DSMat44::createIdentity();
+ }
+
+ // Setup the light directions here.
+
+ for (QT3DSU32 lightIdx = 0, lightEnd = m_Lights.size(); lightIdx < lightEnd;
+ ++lightIdx) {
+ m_LightDirections.push_back(m_Lights[lightIdx]->GetScalingCorrectDirection());
+ }
+
+ m_ModelContexts.clear();
+ if (GetOffscreenRenderer() == false) {
+ bool renderablesDirty =
+ PrepareRenderablesForRender(m_ViewProjection,
+ m_ClippingFrustum,
+ theTextScaleFactor, thePrepResult.m_Flags);
+ wasDataDirty = wasDataDirty || renderablesDirty;
+ if (thePrepResult.m_Flags.RequiresStencilBuffer())
+ thePrepResult.m_Flags.SetShouldRenderToTexture(true);
+ } else {
+ NVRenderRect theViewport =
+ thePrepResult.GetLayerToPresentationViewport().ToIntegerRect();
+ bool theScissor = true;
+ NVRenderRect theScissorRect =
+ thePrepResult.GetLayerToPresentationScissorRect().ToIntegerRect();
+ // This happens here because if there are any fancy render steps
+ IRenderList &theRenderList(m_Renderer.GetQt3DSContext().GetRenderList());
+ NVRenderContext &theContext(m_Renderer.GetContext());
+ SRenderListScopedProperty<bool> _listScissorEnabled(
+ theRenderList, &IRenderList::IsScissorTestEnabled,
+ &IRenderList::SetScissorTestEnabled, theScissor);
+ SRenderListScopedProperty<NVRenderRect> _listViewport(
+ theRenderList, &IRenderList::GetViewport, &IRenderList::SetViewport,
+ theViewport);
+ SRenderListScopedProperty<NVRenderRect> _listScissor(
+ theRenderList, &IRenderList::GetScissor, &IRenderList::SetScissorRect,
+ theScissorRect);
+ // Some plugins don't use the render list so they need the actual gl context
+ // setup.
+ qt3ds::render::NVRenderContextScopedProperty<bool> __scissorEnabled(
+ theContext, &NVRenderContext::IsScissorTestEnabled,
+ &NVRenderContext::SetScissorTestEnabled, true);
+ qt3ds::render::NVRenderContextScopedProperty<NVRenderRect> __scissorRect(
+ theContext, &NVRenderContext::GetScissorRect,
+ &NVRenderContext::SetScissorRect, theScissorRect);
+ qt3ds::render::NVRenderContextScopedProperty<NVRenderRect> __viewportRect(
+ theContext, &NVRenderContext::GetViewport, &NVRenderContext::SetViewport,
+ theViewport);
+ SOffscreenRenderFlags theResult = m_LastFrameOffscreenRenderer->NeedsRender(
+ CreateOffscreenRenderEnvironment(),
+ m_Renderer.GetQt3DSContext().GetPresentationScaleFactor(), &m_Layer);
+ wasDataDirty = wasDataDirty || theResult.m_HasChangedSinceLastFrame;
+ }
+ }
+ }
+ wasDirty = wasDirty || wasDataDirty;
+ thePrepResult.m_Flags.SetWasDirty(wasDirty);
+ thePrepResult.m_Flags.SetLayerDataDirty(wasDataDirty);
+
+ m_LayerPrepResult = thePrepResult;
+
+ // Per-frame cache of renderable objects post-sort.
+ GetOpaqueRenderableObjects();
+ // If layer depth test is false, this may also contain opaque objects.
+ GetTransparentRenderableObjects();
+
+ GetCameraDirection();
+ }
+
+ void SLayerRenderPreparationData::ResetForFrame()
+ {
+ m_TransparentObjects.clear_unsafe();
+ m_OpaqueObjects.clear_unsafe();
+ m_LayerPrepResult.setEmpty();
+ // The check for if the camera is or is not null is used
+ // to figure out if this layer was rendered at all.
+ m_Camera = NULL;
+ m_LastFrameOffscreenRenderer = NULL;
+ m_IRenderWidgets.clear_unsafe();
+ m_CameraDirection.setEmpty();
+ m_LightDirections.clear_unsafe();
+ m_RenderedOpaqueObjects.clear_unsafe();
+ m_RenderedTransparentObjects.clear_unsafe();
+ }
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h
new file mode 100644
index 0000000..5b8d6e1
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_RENDERER_IMPL_LAYER_RENDER_PREPARATION_DATA_H
+#define QT3DS_RENDERER_IMPL_LAYER_RENDER_PREPARATION_DATA_H
+#include "Qt3DSRender.h"
+#include "foundation/Qt3DSFlags.h"
+#include "Qt3DSRendererImplLayerRenderHelper.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderableObjects.h"
+#include "Qt3DSRenderClippingFrustum.h"
+#include "Qt3DSRenderResourceTexture2D.h"
+#include "Qt3DSOffscreenRenderManager.h"
+#include "Qt3DSRenderProfiler.h"
+#include "Qt3DSRenderShadowMap.h"
+#include "foundation/Qt3DSPool.h"
+#include "Qt3DSRenderableObjects.h"
+
+namespace qt3ds {
+namespace render {
+ struct SLayerRenderData;
+ class Qt3DSRendererImpl;
+ struct SRenderableObject;
+
+ struct LayerRenderPreparationResultFlagValues
+ {
+ enum Enum {
+ // Was the data in this layer dirty (meaning re-render to texture, possibly)
+ WasLayerDataDirty = 1,
+ // Was the data in this layer dirty *or* this layer *or* any effect dirty.
+ WasDirty = 1 << 1,
+ // An effect or flag or rotation on the layer dictates this object should
+ // render to the texture.
+ ShouldRenderToTexture = 1 << 2,
+ // Some effects require depth texturing, this should be set on the effect
+ // instance.
+ RequiresDepthTexture = 1 << 3,
+
+ // Should create independent viewport
+ // If we aren't rendering to texture we still may have width/height manipulations
+ // that require our own viewport.
+ ShouldCreateIndependentViewport = 1 << 4,
+
+ // SSAO should be done in a separate pass
+ // Note that having an AO pass necessitates a DepthTexture so this flag should
+ // never be set without the RequiresDepthTexture flag as well.
+ RequiresSsaoPass = 1 << 5,
+
+ // if some light cause shadow
+ // we need a separate per light shadow map pass
+ RequiresShadowMapPass = 1 << 6,
+
+ // Currently we use a stencil-cover algorithm to render bezier curves.
+ RequiresStencilBuffer = 1 << 7
+ };
+ };
+
+ struct SLayerRenderPreparationResultFlags
+ : public NVFlags<LayerRenderPreparationResultFlagValues::Enum, QT3DSU32>
+ {
+ bool WasLayerDataDirty() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::WasLayerDataDirty);
+ }
+ void SetLayerDataDirty(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::WasLayerDataDirty);
+ }
+
+ bool WasDirty() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::WasDirty);
+ }
+ void SetWasDirty(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::WasDirty);
+ }
+
+ bool ShouldRenderToTexture() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::ShouldRenderToTexture);
+ }
+ void SetShouldRenderToTexture(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::ShouldRenderToTexture);
+ }
+
+ bool RequiresDepthTexture() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::RequiresDepthTexture);
+ }
+ void SetRequiresDepthTexture(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::RequiresDepthTexture);
+ }
+
+ bool ShouldCreateIndependentViewport() const
+ {
+ return this->operator&(
+ LayerRenderPreparationResultFlagValues::ShouldCreateIndependentViewport);
+ }
+ void SetShouldCreateIndependentViewport(bool inValue)
+ {
+ clearOrSet(inValue,
+ LayerRenderPreparationResultFlagValues::ShouldCreateIndependentViewport);
+ }
+
+ bool RequiresSsaoPass() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::RequiresSsaoPass);
+ }
+ void SetRequiresSsaoPass(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::RequiresSsaoPass);
+ }
+
+ bool RequiresShadowMapPass() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::RequiresShadowMapPass);
+ }
+ void SetRequiresShadowMapPass(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::RequiresShadowMapPass);
+ }
+
+ bool RequiresStencilBuffer() const
+ {
+ return this->operator&(LayerRenderPreparationResultFlagValues::RequiresStencilBuffer);
+ }
+ void SetRequiresStencilBuffer(bool inValue)
+ {
+ clearOrSet(inValue, LayerRenderPreparationResultFlagValues::RequiresStencilBuffer);
+ }
+ };
+
+ struct SLayerRenderPreparationResult : public SLayerRenderHelper
+ {
+ SEffect *m_LastEffect;
+ SLayerRenderPreparationResultFlags m_Flags;
+ QT3DSU32 m_MaxAAPassIndex;
+ SLayerRenderPreparationResult()
+ : m_LastEffect(NULL)
+ , m_MaxAAPassIndex(0)
+ {
+ }
+ SLayerRenderPreparationResult(const SLayerRenderHelper &inHelper)
+ : SLayerRenderHelper(inHelper)
+ , m_LastEffect(NULL)
+ , m_MaxAAPassIndex(0)
+ {
+ }
+ };
+
+ struct SRenderableNodeEntry
+ {
+ SNode *m_Node;
+ TNodeLightEntryList m_Lights;
+ SRenderableNodeEntry()
+ : m_Node(NULL)
+ {
+ }
+ SRenderableNodeEntry(SNode &inNode)
+ : m_Node(&inNode)
+ {
+ }
+ };
+
+ struct SScopedLightsListScope
+ {
+ nvvector<SLight *> &m_LightsList;
+ nvvector<QT3DSVec3> &m_LightDirList;
+ QT3DSU32 m_ListOriginalSize;
+ SScopedLightsListScope(nvvector<SLight *> &inLights, nvvector<QT3DSVec3> &inDestLightDirList,
+ nvvector<QT3DSVec3> &inSrcLightDirList,
+ TNodeLightEntryList &inScopedLights)
+ : m_LightsList(inLights)
+ , m_LightDirList(inDestLightDirList)
+ , m_ListOriginalSize(m_LightsList.size())
+ {
+ for (TNodeLightEntryList::iterator iter = inScopedLights.begin(),
+ end = inScopedLights.end();
+ iter != end; ++iter) {
+ m_LightsList.push_back(iter->m_Light);
+ m_LightDirList.push_back(inSrcLightDirList[iter->m_LightIndex]);
+ }
+ }
+ ~SScopedLightsListScope()
+ {
+ m_LightsList.resize(m_ListOriginalSize);
+ m_LightDirList.resize(m_ListOriginalSize);
+ }
+ };
+
+ struct SDefaultMaterialPreparationResult
+ {
+ SRenderableImage *m_FirstImage;
+ QT3DSF32 m_Opacity;
+ SRenderableObjectFlags m_RenderableFlags;
+ SShaderDefaultMaterialKey m_MaterialKey;
+ bool m_Dirty;
+
+ SDefaultMaterialPreparationResult(SShaderDefaultMaterialKey inMaterialKey);
+ };
+
+ // Data used strictly in the render preparation step.
+ struct SLayerRenderPreparationData
+ {
+ typedef void (*TRenderRenderableFunction)(SLayerRenderData &inData,
+ SRenderableObject &inObject,
+ const QT3DSVec2 &inCameraProps,
+ TShaderFeatureSet inShaderFeatures,
+ QT3DSU32 lightIndex, const SCamera &inCamera);
+ typedef nvhash_map<SLight *, SNode *> TLightToNodeMap;
+ typedef Pool<SNodeLightEntry, ForwardingAllocator> TNodeLightEntryPoolType;
+
+ enum Enum {
+ MAX_AA_LEVELS = 8,
+ MAX_TEMPORAL_AA_LEVELS = 2,
+ };
+
+ SLayer &m_Layer;
+ Qt3DSRendererImpl &m_Renderer;
+ NVAllocatorCallback &m_Allocator;
+ // List of nodes we can render, not all may be active. Found by doing a depth-first
+ // search through m_FirstChild if length is zero.
+
+ TNodeLightEntryPoolType m_RenderableNodeLightEntryPool;
+ nvvector<SRenderableNodeEntry> m_RenderableNodes;
+ TLightToNodeMap m_LightToNodeMap; // map of lights to nodes to cache if we have looked up a
+ // given scoped light yet.
+ // Built at the same time as the renderable nodes map.
+ // these are processed so they are available when the shaders for the models
+ // are being generated.
+ nvvector<SNode *> m_CamerasAndLights;
+
+ // Results of prepare for render.
+ SCamera *m_Camera;
+ nvvector<SLight *> m_Lights; // Only contains lights that are global.
+ TRenderableObjectList m_OpaqueObjects;
+ TRenderableObjectList m_TransparentObjects;
+ // Sorted lists of the rendered objects. There may be other transforms applied so
+ // it is simplest to duplicate the lists.
+ TRenderableObjectList m_RenderedOpaqueObjects;
+ TRenderableObjectList m_RenderedTransparentObjects;
+ QT3DSMat44 m_ViewProjection;
+ SClippingFrustum m_ClippingFrustum;
+ Option<SLayerRenderPreparationResult> m_LayerPrepResult;
+ // Widgets drawn at particular times during the rendering process
+ nvvector<IRenderWidget *> m_IRenderWidgets;
+ Option<QT3DSVec3> m_CameraDirection;
+ // Scoped lights need a level of indirection into a light direction list. The source light
+ // directions list is as long as there are lights on the layer. It holds invalid
+ // information for
+ // any lights that are not both active and scoped; but the relative position for a given
+ // light
+ // in this list is completely constant and immutable; this relative position is saved on a
+ // structure
+ // and used when looking up the light direction for a given light.
+ nvvector<QT3DSVec3> m_SourceLightDirections;
+ nvvector<QT3DSVec3> m_LightDirections;
+ TModelContextPtrList m_ModelContexts;
+ NVScopedRefCounted<IOffscreenRenderer> m_LastFrameOffscreenRenderer;
+
+ eastl::vector<SShaderPreprocessorFeature> m_Features;
+ CRegisteredString m_CGLightingFeatureName;
+ bool m_FeaturesDirty;
+ size_t m_FeatureSetHash;
+ bool m_TooManyLightsError;
+
+ // shadow mapps
+ NVScopedRefCounted<Qt3DSShadowMap> m_ShadowMapManager;
+
+ SLayerRenderPreparationData(SLayer &inLayer, Qt3DSRendererImpl &inRenderer);
+ virtual ~SLayerRenderPreparationData();
+ bool GetOffscreenRenderer();
+ bool GetShadowMapManager();
+ bool NeedsWidgetTexture() const;
+
+ SShaderDefaultMaterialKey GenerateLightingKey(DefaultMaterialLighting::Enum inLightingType);
+
+ void PrepareImageForRender(SImage &inImage, ImageMapTypes::Enum inMapType,
+ SRenderableImage *&ioFirstImage, SRenderableImage *&ioNextImage,
+ SRenderableObjectFlags &ioFlags,
+ SShaderDefaultMaterialKey &ioGeneratedShaderKey,
+ QT3DSU32 inImageIndex);
+
+ SDefaultMaterialPreparationResult
+ PrepareDefaultMaterialForRender(SDefaultMaterial &inMaterial,
+ SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity,
+ bool inClearMaterialFlags);
+
+ SDefaultMaterialPreparationResult
+ PrepareCustomMaterialForRender(SCustomMaterial &inMaterial,
+ SRenderableObjectFlags &inExistingFlags, QT3DSF32 inOpacity);
+
+ bool PrepareModelForRender(SModel &inModel, const QT3DSMat44 &inViewProjection,
+ const Option<SClippingFrustum> &inClipFrustum,
+ TNodeLightEntryList &inScopedLights);
+
+ bool PrepareTextForRender(SText &inText, const QT3DSMat44 &inViewProjection,
+ QT3DSF32 inTextScaleFactor,
+ SLayerRenderPreparationResultFlags &ioFlags);
+ bool PreparePathForRender(SPath &inPath, const QT3DSMat44 &inViewProjection,
+ const Option<SClippingFrustum> &inClipFrustum,
+ SLayerRenderPreparationResultFlags &ioFlags);
+ // Helper function used during PRepareForRender and PrepareAndRender
+ bool PrepareRenderablesForRender(const QT3DSMat44 &inViewProjection,
+ const Option<SClippingFrustum> &inClipFrustum,
+ QT3DSF32 inTextScaleFactor,
+ SLayerRenderPreparationResultFlags &ioFlags);
+
+ // returns true if this object will render something different than it rendered the last
+ // time.
+ virtual void PrepareForRender(const QSize &inViewportDimensions);
+ bool CheckLightProbeDirty(SImage &inLightProbe);
+ void AddRenderWidget(IRenderWidget &inWidget);
+ void SetShaderFeature(const char *inName, bool inValue);
+ void SetShaderFeature(CRegisteredString inName, bool inValue);
+ NVConstDataRef<SShaderPreprocessorFeature> GetShaderFeatureSet();
+ size_t GetShaderFeatureSetHash();
+ // The graph object is not const because this traversal updates dirty state on the objects.
+ eastl::pair<bool, SGraphObject *> ResolveReferenceMaterial(SGraphObject *inMaterial);
+
+ QT3DSVec3 GetCameraDirection();
+ // Per-frame cache of renderable objects post-sort.
+ NVDataRef<SRenderableObject *> GetOpaqueRenderableObjects();
+ // If layer depth test is false, this may also contain opaque objects.
+ NVDataRef<SRenderableObject *> GetTransparentRenderableObjects();
+
+ virtual void ResetForFrame();
+
+ // The render list and gl context are setup for what the embedded item will
+ // need.
+ virtual SOffscreenRendererEnvironment CreateOffscreenRenderEnvironment() = 0;
+
+ virtual IRenderTask &CreateRenderToTextureRunnable() = 0;
+ };
+}
+}
+#endif
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp
new file mode 100644
index 0000000..a3d3fab
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.cpp
@@ -0,0 +1,3007 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "Qt3DSRendererImpl.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "Qt3DSRenderLight.h"
+#include "Qt3DSRenderContextCore.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderDynamicObjectSystem.h"
+#include "Qt3DSRenderShaderCodeGeneratorV2.h"
+#include "Qt3DSRenderDefaultMaterialShaderGenerator.h"
+#include "Qt3DSVertexPipelineImpl.h"
+
+// This adds support for the depth buffers in the shader so we can do depth
+// texture-based effects.
+#define QT3DS_RENDER_SUPPORT_DEPTH_TEXTURE 1
+
+namespace qt3ds {
+namespace render {
+
+ void STextShader::Render(NVRenderTexture2D &inTexture,
+ const STextScaleAndOffset &inScaleAndOffset, const QT3DSVec4 &inTextColor,
+ const QT3DSMat44 &inMVP, const QT3DSVec2 &inCameraVec,
+ NVRenderContext &inRenderContext,
+ NVRenderInputAssembler &inInputAssemblerBuffer, QT3DSU32 count,
+ const STextTextureDetails &inTextTextureDetails,
+ const QT3DSVec3 &inBackgroundColor)
+ {
+ inRenderContext.SetCullingEnabled(false);
+ inRenderContext.SetActiveShader(&m_Shader);
+ m_MVP.Set(inMVP);
+ m_Sampler.Set(&inTexture);
+ m_TextColor.Set(inTextColor);
+ m_Dimensions.Set(QT3DSVec4(inScaleAndOffset.m_TextScale.x, inScaleAndOffset.m_TextScale.y,
+ inScaleAndOffset.m_TextOffset.x, inScaleAndOffset.m_TextOffset.y));
+ m_CameraProperties.Set(inCameraVec);
+ STextureDetails theTextureDetails = inTexture.GetTextureDetails();
+ QT3DSF32 theWidthScale =
+ (QT3DSF32)inTextTextureDetails.m_TextWidth / (QT3DSF32)theTextureDetails.m_Width;
+ QT3DSF32 theHeightScale =
+ (QT3DSF32)inTextTextureDetails.m_TextHeight / (QT3DSF32)theTextureDetails.m_Height;
+ m_BackgroundColor.Set(inBackgroundColor);
+
+ m_TextDimensions.Set(
+ QT3DSVec3(theWidthScale, theHeightScale, inTextTextureDetails.m_FlipY ? 1.0f : 0.0f));
+ inRenderContext.SetInputAssembler(&inInputAssemblerBuffer);
+ inRenderContext.Draw(NVRenderDrawMode::Triangles, count, 0);
+ }
+
+ void STextShader::RenderPath(NVRenderPathFontItem &inPathFontItem,
+ NVRenderPathFontSpecification &inPathFontSpec,
+ const STextScaleAndOffset &inScaleAndOffset,
+ const QT3DSVec4 &inTextColor, const QT3DSMat44 &inViewProjection,
+ const QT3DSMat44 &inModel, const QT3DSVec2 &,
+ NVRenderContext &inRenderContext,
+ const STextTextureDetails &inTextTextureDetails,
+ const QT3DSVec3 &inBackgroundColor)
+ {
+ qt3ds::render::NVRenderBoolOp::Enum theDepthFunction = inRenderContext.GetDepthFunction();
+ bool isDepthEnabled = inRenderContext.IsDepthTestEnabled();
+ bool isStencilEnabled = inRenderContext.IsStencilTestEnabled();
+ bool isDepthWriteEnabled = inRenderContext.IsDepthWriteEnabled();
+ qt3ds::render::NVRenderStencilFunctionArgument theArg(qt3ds::render::NVRenderBoolOp::NotEqual, 0,
+ 0xFF);
+ qt3ds::render::NVRenderStencilOperationArgument theOpArg(qt3ds::render::NVRenderStencilOp::Keep,
+ qt3ds::render::NVRenderStencilOp::Keep,
+ qt3ds::render::NVRenderStencilOp::Zero);
+ NVScopedRefCounted<NVRenderDepthStencilState> depthStencilState =
+ inRenderContext.CreateDepthStencilState(isDepthEnabled, isDepthWriteEnabled,
+ theDepthFunction, false, theArg, theArg,
+ theOpArg, theOpArg);
+
+ inRenderContext.SetActiveShader(NULL);
+ inRenderContext.SetCullingEnabled(false);
+
+ inRenderContext.SetDepthStencilState(depthStencilState);
+
+ // setup transform
+ QT3DSMat44 offsetMatrix = QT3DSMat44::createIdentity();
+ offsetMatrix.setPosition(QT3DSVec3(
+ inScaleAndOffset.m_TextOffset.x - (QT3DSF32)inTextTextureDetails.m_TextWidth / 2.0f,
+ inScaleAndOffset.m_TextOffset.y - (QT3DSF32)inTextTextureDetails.m_TextHeight / 2.0f,
+ 0.0));
+
+ QT3DSMat44 pathMatrix = inPathFontItem.GetTransform();
+
+ inRenderContext.SetPathProjectionMatrix(inViewProjection);
+ inRenderContext.SetPathModelViewMatrix(inModel * offsetMatrix * pathMatrix);
+
+ // first pass
+ inPathFontSpec.StencilFillPathInstanced(inPathFontItem);
+
+ // second pass
+ inRenderContext.SetActiveProgramPipeline(m_ProgramPipeline);
+ m_TextColor.Set(inTextColor);
+ m_BackgroundColor.Set(inBackgroundColor);
+
+ inRenderContext.SetStencilTestEnabled(true);
+ inPathFontSpec.CoverFillPathInstanced(inPathFontItem);
+
+ inRenderContext.SetStencilTestEnabled(isStencilEnabled);
+ inRenderContext.SetDepthFunction(theDepthFunction);
+
+ inRenderContext.SetActiveProgramPipeline(NULL);
+ }
+
+ void STextShader::Render2D(NVRenderTexture2D &inTexture, const QT3DSVec4 &inTextColor,
+ const QT3DSMat44 &inMVP, NVRenderContext &inRenderContext,
+ NVRenderInputAssembler &inInputAssemblerBuffer, QT3DSU32 count,
+ QT3DSVec2 inVertexOffsets)
+ {
+ // inRenderContext.SetCullingEnabled( false );
+ inRenderContext.SetBlendingEnabled(true);
+ inRenderContext.SetDepthWriteEnabled(false);
+ inRenderContext.SetDepthTestEnabled(false);
+
+ inRenderContext.SetActiveShader(&m_Shader);
+
+ qt3ds::render::NVRenderBlendFunctionArgument blendFunc(
+ NVRenderSrcBlendFunc::SrcAlpha, NVRenderDstBlendFunc::OneMinusSrcAlpha,
+ NVRenderSrcBlendFunc::One, NVRenderDstBlendFunc::One);
+ qt3ds::render::NVRenderBlendEquationArgument blendEqu(NVRenderBlendEquation::Add,
+ NVRenderBlendEquation::Add);
+
+ inRenderContext.SetBlendFunction(blendFunc);
+ inRenderContext.SetBlendEquation(blendEqu);
+
+ m_MVP.Set(inMVP);
+ m_Sampler.Set(&inTexture);
+ m_TextColor.Set(inTextColor);
+ m_VertexOffsets.Set(inVertexOffsets);
+
+ inRenderContext.SetInputAssembler(&inInputAssemblerBuffer);
+ inRenderContext.Draw(NVRenderDrawMode::Triangles, count, 0);
+ }
+
+ using eastl::make_pair;
+
+ static inline void AddVertexDepth(SShaderVertexCodeGenerator &vertexShader)
+ {
+ // near plane, far plane
+ vertexShader.AddInclude("viewProperties.glsllib");
+ vertexShader.AddVarying("vertex_depth", "float");
+ // the w coordinate is the unormalized distance to the object from the camera
+ // We want the normalized distance, with 0 representing the far plane and 1 representing
+ // the near plane, of the object in the vertex depth variable.
+
+ vertexShader << "\tvertex_depth = calculateVertexDepth( camera_properties, gl_Position );"
+ << Endl;
+ }
+
+ // Helper implements the vertex pipeline for mesh subsets when bound to the default material.
+ // Should be completely possible to use for custom materials with a bit of refactoring.
+ struct SSubsetMaterialVertexPipeline : public SVertexPipelineImpl
+ {
+ Qt3DSRendererImpl &m_Renderer;
+ SSubsetRenderable &m_Renderable;
+ TessModeValues::Enum m_TessMode;
+
+ SSubsetMaterialVertexPipeline(Qt3DSRendererImpl &renderer, SSubsetRenderable &renderable,
+ bool inWireframeRequested)
+ : SVertexPipelineImpl(renderer.GetQt3DSContext().GetAllocator(),
+ renderer.GetQt3DSContext().GetDefaultMaterialShaderGenerator(),
+ renderer.GetQt3DSContext().GetShaderProgramGenerator(),
+ renderer.GetQt3DSContext().GetStringTable(), false)
+ , m_Renderer(renderer)
+ , m_Renderable(renderable)
+ , m_TessMode(TessModeValues::NoTess)
+ {
+ if (m_Renderer.GetContext().IsTessellationSupported()) {
+ m_TessMode = renderable.m_TessellationMode;
+ }
+
+ if (m_Renderer.GetContext().IsGeometryStageSupported()
+ && m_TessMode != TessModeValues::NoTess)
+ m_Wireframe = inWireframeRequested;
+ }
+
+ void InitializeTessControlShader()
+ {
+ if (m_TessMode == TessModeValues::NoTess
+ || ProgramGenerator().GetStage(ShaderGeneratorStages::TessControl) == NULL)
+ return;
+
+ IShaderStageGenerator &tessCtrlShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+
+ SetupTessIncludes(ShaderGeneratorStages::TessControl, m_TessMode);
+
+ tessCtrlShader.Append("void main() {\n");
+
+ tessCtrlShader.Append("\tctWorldPos[0] = varWorldPos[0];");
+ tessCtrlShader.Append("\tctWorldPos[1] = varWorldPos[1];");
+ tessCtrlShader.Append("\tctWorldPos[2] = varWorldPos[2];");
+
+ if (m_TessMode == TessModeValues::TessPhong
+ || m_TessMode == TessModeValues::TessNPatch) {
+ tessCtrlShader.Append("\tctNorm[0] = varObjectNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = varObjectNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = varObjectNormal[2];");
+ }
+ if (m_TessMode == TessModeValues::TessNPatch) {
+ tessCtrlShader.Append("\tctTangent[0] = varTangent[0];");
+ tessCtrlShader.Append("\tctTangent[1] = varTangent[1];");
+ tessCtrlShader.Append("\tctTangent[2] = varTangent[2];");
+ }
+
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ }
+ void InitializeTessEvaluationShader()
+ {
+ if (m_TessMode == TessModeValues::NoTess
+ || ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval) == NULL)
+ return;
+
+ IShaderStageGenerator &tessEvalShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+
+ SetupTessIncludes(ShaderGeneratorStages::TessEval, m_TessMode);
+
+ if (m_TessMode == TessModeValues::TessLinear)
+ m_Renderer.GetQt3DSContext()
+ .GetDefaultMaterialShaderGenerator()
+ .AddDisplacementImageUniforms(tessEvalShader, m_DisplacementIdx,
+ m_DisplacementImage);
+
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddUniform("normal_matrix", "mat3");
+
+ tessEvalShader.Append("void main() {");
+
+ if (m_TessMode == TessModeValues::TessNPatch) {
+ tessEvalShader.Append("\tctNorm[0] = varObjectNormalTC[0];");
+ tessEvalShader.Append("\tctNorm[1] = varObjectNormalTC[1];");
+ tessEvalShader.Append("\tctNorm[2] = varObjectNormalTC[2];");
+
+ tessEvalShader.Append("\tctTangent[0] = varTangentTC[0];");
+ tessEvalShader.Append("\tctTangent[1] = varTangentTC[1];");
+ tessEvalShader.Append("\tctTangent[2] = varTangentTC[2];");
+ }
+
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ }
+
+ void FinalizeTessControlShader()
+ {
+ IShaderStageGenerator &tessCtrlShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ // add varyings we must pass through
+ typedef TStrTableStrMap::const_iterator TParamIter;
+ for (TParamIter iter = m_InterpolationParameters.begin(),
+ end = m_InterpolationParameters.end();
+ iter != end; ++iter) {
+ tessCtrlShader << "\t" << iter->first.c_str()
+ << "TC[gl_InvocationID] = " << iter->first.c_str()
+ << "[gl_InvocationID];\n";
+ }
+ }
+
+ void FinalizeTessEvaluationShader()
+ {
+ IShaderStageGenerator &tessEvalShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+
+ eastl::string outExt("");
+ if (ProgramGenerator().GetEnabledStages() & ShaderGeneratorStages::Geometry)
+ outExt = "TE";
+
+ // add varyings we must pass through
+ typedef TStrTableStrMap::const_iterator TParamIter;
+ if (m_TessMode == TessModeValues::TessNPatch) {
+ for (TParamIter iter = m_InterpolationParameters.begin(),
+ end = m_InterpolationParameters.end();
+ iter != end; ++iter) {
+ tessEvalShader << "\t" << iter->first.c_str() << outExt.c_str()
+ << " = gl_TessCoord.z * " << iter->first.c_str() << "TC[0] + ";
+ tessEvalShader << "gl_TessCoord.x * " << iter->first.c_str() << "TC[1] + ";
+ tessEvalShader << "gl_TessCoord.y * " << iter->first.c_str() << "TC[2];\n";
+ }
+
+ // transform the normal
+ if (m_GenerationFlags & GenerationFlagValues::WorldNormal)
+ tessEvalShader << "\n\tvarNormal" << outExt.c_str()
+ << " = normalize(normal_matrix * teNorm);\n";
+ // transform the tangent
+ if (m_GenerationFlags & GenerationFlagValues::TangentBinormal) {
+ tessEvalShader << "\n\tvarTangent" << outExt.c_str()
+ << " = normalize(normal_matrix * teTangent);\n";
+ // transform the binormal
+ tessEvalShader << "\n\tvarBinormal" << outExt.c_str()
+ << " = normalize(normal_matrix * teBinormal);\n";
+ }
+ } else {
+ for (TParamIter iter = m_InterpolationParameters.begin(),
+ end = m_InterpolationParameters.end();
+ iter != end; ++iter) {
+ tessEvalShader << "\t" << iter->first.c_str() << outExt.c_str()
+ << " = gl_TessCoord.x * " << iter->first.c_str() << "TC[0] + ";
+ tessEvalShader << "gl_TessCoord.y * " << iter->first.c_str() << "TC[1] + ";
+ tessEvalShader << "gl_TessCoord.z * " << iter->first.c_str() << "TC[2];\n";
+ }
+
+ // displacement mapping makes only sense with linear tessellation
+ if (m_TessMode == TessModeValues::TessLinear && m_DisplacementImage) {
+ IDefaultMaterialShaderGenerator::SImageVariableNames theNames =
+ m_Renderer.GetQt3DSContext()
+ .GetDefaultMaterialShaderGenerator()
+ .GetImageVariableNames(m_DisplacementIdx);
+ tessEvalShader << "\tpos.xyz = defaultMaterialFileDisplacementTexture( "
+ << theNames.m_ImageSampler << ", displaceAmount, "
+ << theNames.m_ImageFragCoords << outExt.c_str();
+ tessEvalShader << ", varObjectNormal" << outExt.c_str() << ", pos.xyz );"
+ << Endl;
+ tessEvalShader << "\tvarWorldPos" << outExt.c_str()
+ << "= (model_matrix * pos).xyz;" << Endl;
+ tessEvalShader << "\tvarViewVector" << outExt.c_str()
+ << "= normalize(camera_position - "
+ << "varWorldPos" << outExt.c_str() << ");" << Endl;
+ }
+
+ // transform the normal
+ tessEvalShader << "\n\tvarNormal" << outExt.c_str()
+ << " = normalize(normal_matrix * varObjectNormal" << outExt.c_str()
+ << ");\n";
+ }
+
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;\n");
+ }
+
+ void BeginVertexGeneration(QT3DSU32 displacementImageIdx,
+ SRenderableImage *displacementImage) override
+ {
+ m_DisplacementIdx = displacementImageIdx;
+ m_DisplacementImage = displacementImage;
+
+ TShaderGeneratorStageFlags theStages(IShaderProgramGenerator::DefaultFlags());
+ if (m_TessMode != TessModeValues::NoTess) {
+ theStages |= ShaderGeneratorStages::TessControl;
+ theStages |= ShaderGeneratorStages::TessEval;
+ }
+ if (m_Wireframe) {
+ theStages |= ShaderGeneratorStages::Geometry;
+ }
+ ProgramGenerator().BeginProgram(theStages);
+ if (m_TessMode != TessModeValues::NoTess) {
+ InitializeTessControlShader();
+ InitializeTessEvaluationShader();
+ }
+ if (m_Wireframe) {
+ InitializeWireframeGeometryShader();
+ }
+ // Open up each stage.
+ IShaderStageGenerator &vertexShader(Vertex());
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader << "void main()" << Endl << "{" << Endl;
+ vertexShader << "\tvec3 uTransform;" << Endl;
+ vertexShader << "\tvec3 vTransform;" << Endl;
+
+ if (displacementImage) {
+ GenerateUVCoords();
+ MaterialGenerator().GenerateImageUVCoordinates(*this, displacementImageIdx, 0,
+ *displacementImage);
+ if (!HasTessellation()) {
+ vertexShader.AddUniform("displaceAmount", "float");
+ // we create the world position setup here
+ // because it will be replaced with the displaced position
+ SetCode(GenerationFlagValues::WorldPosition);
+ vertexShader.AddUniform("model_matrix", "mat4");
+
+ vertexShader.AddInclude("defaultMaterialFileDisplacementTexture.glsllib");
+ IDefaultMaterialShaderGenerator::SImageVariableNames theVarNames =
+ MaterialGenerator().GetImageVariableNames(displacementImageIdx);
+
+ vertexShader.AddUniform(theVarNames.m_ImageSampler, "sampler2D");
+
+ vertexShader
+ << "\tvec3 displacedPos = defaultMaterialFileDisplacementTexture( "
+ << theVarNames.m_ImageSampler << ", displaceAmount, "
+ << theVarNames.m_ImageFragCoords << ", attr_norm, attr_pos );" << Endl;
+ AddInterpolationParameter("varWorldPos", "vec3");
+ vertexShader.Append("\tvec3 local_model_world_position = (model_matrix * "
+ "vec4(displacedPos, 1.0)).xyz;");
+ AssignOutput("varWorldPos", "local_model_world_position");
+ }
+ }
+ // for tessellation we pass on the position in object coordinates
+ // Also note that gl_Position is written in the tess eval shader
+ if (HasTessellation())
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ else {
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ if (displacementImage)
+ vertexShader.Append(
+ "\tgl_Position = model_view_projection * vec4(displacedPos, 1.0);");
+ else
+ vertexShader.Append(
+ "\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);");
+ }
+
+ if (HasTessellation()) {
+ GenerateWorldPosition();
+ GenerateWorldNormal();
+ GenerateObjectNormal();
+ GenerateVarTangentAndBinormal();
+ }
+ }
+
+ void BeginFragmentGeneration() override
+ {
+ Fragment().AddUniform("material_diffuse", "vec4");
+ Fragment() << "void main()" << Endl << "{" << Endl;
+ // We do not pass object opacity through the pipeline.
+ Fragment() << "\tfloat object_opacity = material_diffuse.a;" << Endl;
+ }
+
+ void AssignOutput(const char8_t *inVarName, const char8_t *inVarValue) override
+ {
+ Vertex() << "\t" << inVarName << " = " << inVarValue << ";\n";
+ }
+ void DoGenerateUVCoords(QT3DSU32 inUVSet = 0) override
+ {
+ QT3DS_ASSERT(inUVSet == 0 || inUVSet == 1);
+
+ if (inUVSet == 0) {
+ Vertex().AddIncoming("attr_uv0", "vec2");
+ Vertex() << "\tvarTexCoord0 = attr_uv0;" << Endl;
+ } else if (inUVSet == 1) {
+ Vertex().AddIncoming("attr_uv1", "vec2");
+ Vertex() << "\tvarTexCoord1 = attr_uv1;" << Endl;
+ }
+ }
+
+ // fragment shader expects varying vertex normal
+ // lighting in vertex pipeline expects world_normal
+ void DoGenerateWorldNormal() override
+ {
+ IShaderStageGenerator &vertexGenerator(Vertex());
+ vertexGenerator.AddIncoming("attr_norm", "vec3");
+ vertexGenerator.AddUniform("normal_matrix", "mat3");
+ if (HasTessellation() == false) {
+ vertexGenerator.Append(
+ "\tvec3 world_normal = normalize(normal_matrix * attr_norm).xyz;");
+ vertexGenerator.Append("\tvarNormal = world_normal;");
+ }
+ }
+ void DoGenerateObjectNormal() override
+ {
+ AddInterpolationParameter("varObjectNormal", "vec3");
+ Vertex().Append("\tvarObjectNormal = attr_norm;");
+ }
+ void DoGenerateWorldPosition() override
+ {
+ Vertex().Append(
+ "\tvec3 local_model_world_position = (model_matrix * vec4(attr_pos, 1.0)).xyz;");
+ AssignOutput("varWorldPos", "local_model_world_position");
+ }
+
+ void DoGenerateVarTangentAndBinormal() override
+ {
+ Vertex().AddIncoming("attr_textan", "vec3");
+ Vertex().AddIncoming("attr_binormal", "vec3");
+
+ bool hasNPatchTessellation = m_TessMode == TessModeValues::TessNPatch;
+
+ if (!hasNPatchTessellation) {
+ Vertex() << "\tvarTangent = normal_matrix * attr_textan;" << Endl
+ << "\tvarBinormal = normal_matrix * attr_binormal;" << Endl;
+ } else {
+ Vertex() << "\tvarTangent = attr_textan;" << Endl
+ << "\tvarBinormal = attr_binormal;" << Endl;
+ }
+ }
+
+ void DoGenerateVertexColor() override
+ {
+ Vertex().AddIncoming("attr_color", "vec3");
+ Vertex().Append("\tvarColor = attr_color;");
+ }
+
+ void EndVertexGeneration(bool) override
+ {
+
+ if (HasTessellation()) {
+ // finalize tess control shader
+ FinalizeTessControlShader();
+ // finalize tess evaluation shader
+ FinalizeTessEvaluationShader();
+
+ TessControl().Append("}");
+ TessEval().Append("}");
+ }
+ if (m_Wireframe) {
+ // finalize geometry shader
+ FinalizeWireframeGeometryShader();
+ Geometry().Append("}");
+ }
+ Vertex().Append("}");
+ }
+
+ void EndFragmentGeneration(bool) override { Fragment().Append("}"); }
+
+ void AddInterpolationParameter(const char8_t *inName, const char8_t *inType) override
+ {
+ m_InterpolationParameters.insert(eastl::make_pair(Str(inName), Str(inType)));
+ Vertex().AddOutgoing(inName, inType);
+ Fragment().AddIncoming(inName, inType);
+ if (HasTessellation()) {
+ eastl::string nameBuilder(inName);
+ nameBuilder.append("TC");
+ TessControl().AddOutgoing(nameBuilder.c_str(), inType);
+
+ nameBuilder.assign(inName);
+ if (ProgramGenerator().GetEnabledStages() & ShaderGeneratorStages::Geometry) {
+ nameBuilder.append("TE");
+ Geometry().AddOutgoing(inName, inType);
+ }
+ TessEval().AddOutgoing(nameBuilder.c_str(), inType);
+ }
+ }
+
+ IShaderStageGenerator &ActiveStage() override { return Vertex(); }
+ };
+
+ NVRenderShaderProgram *Qt3DSRendererImpl::GenerateShader(SSubsetRenderable &inRenderable,
+ TShaderFeatureSet inFeatureSet)
+ {
+ // build a string that allows us to print out the shader we are generating to the log.
+ // This is time consuming but I feel like it doesn't happen all that often and is very
+ // useful to users
+ // looking at the log file.
+ QLatin1String logPrefix("mesh subset pipeline-- ");
+
+ m_GeneratedShaderString.clear();
+ m_GeneratedShaderString.assign(logPrefix.data());
+
+ SShaderDefaultMaterialKey theKey(inRenderable.m_ShaderDescription);
+ theKey.ToString(m_GeneratedShaderString, m_DefaultMaterialShaderKeyProperties);
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr(m_GeneratedShaderString.c_str());
+ NVRenderShaderProgram *cachedProgram = theCache.GetProgram(theCacheKey, inFeatureSet);
+ if (cachedProgram)
+ return cachedProgram;
+
+ SSubsetMaterialVertexPipeline pipeline(
+ *this, inRenderable,
+ m_DefaultMaterialShaderKeyProperties.m_WireframeMode.GetValue(theKey));
+ return m_qt3dsContext.GetDefaultMaterialShaderGenerator().GenerateShader(
+ inRenderable.m_Material, inRenderable.m_ShaderDescription, pipeline, inFeatureSet,
+ m_CurrentLayer->m_Lights, inRenderable.m_FirstImage,
+ inRenderable.m_RenderableFlags.HasTransparency(),
+ logPrefix.data());
+ }
+
+ // -------------- Special cases for shadows -------------------
+
+ SRenderableDepthPrepassShader *
+ Qt3DSRendererImpl::GetParaboloidDepthShader(TessModeValues::Enum inTessMode)
+ {
+ if (!m_qt3dsContext.GetRenderContext().IsTessellationSupported()
+ || inTessMode == TessModeValues::NoTess) {
+ return GetParaboloidDepthNoTessShader();
+ } else if (inTessMode == TessModeValues::TessLinear) {
+ return GetParaboloidDepthTessLinearShader();
+ } else if (inTessMode == TessModeValues::TessPhong) {
+ return GetParaboloidDepthTessPhongShader();
+ } else if (inTessMode == TessModeValues::TessNPatch) {
+ return GetParaboloidDepthTessNPatchShader();
+ }
+
+ return GetParaboloidDepthNoTessShader();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetParaboloidDepthNoTessShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_ParaboloidDepthShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("paraboloid depth shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ IShaderProgramGenerator::OutputParaboloidDepthVertex(vertexShader);
+ IShaderProgramGenerator::OutputParaboloidDepthFragment(fragmentShader);
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetParaboloidDepthTessLinearShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_ParaboloidDepthTessLinearShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("paraboloid depth tess linear shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ // vertexShader.AddOutgoing("world_pos", "vec4");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ // vertexShader.Append("\tworld_pos = attr_pos;");
+ vertexShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationLinear.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ // tessCtrlShader.AddOutgoing( "outUVTC", "vec2" );
+ // tessCtrlShader.AddOutgoing( "outNormalTC", "vec3" );
+ tessCtrlShader.Append("void main() {\n");
+ // tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ // tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ // tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationLinear.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ IShaderProgramGenerator::OutputParaboloidDepthTessEval(tessEvalShader);
+ tessEvalShader.Append("}");
+
+ IShaderProgramGenerator::OutputParaboloidDepthFragment(fragmentShader);
+ }
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetParaboloidDepthTessPhongShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_ParaboloidDepthTessPhongShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("paraboloid depth tess phong shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ // vertexShader.AddOutgoing("world_pos", "vec4");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ // vertexShader.Append("\tworld_pos = attr_pos;");
+ vertexShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationPhong.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ // tessCtrlShader.AddOutgoing( "outUVTC", "vec2" );
+ // tessCtrlShader.AddOutgoing( "outNormalTC", "vec3" );
+ tessCtrlShader.Append("void main() {\n");
+ // tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ // tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ // tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationPhong.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ IShaderProgramGenerator::OutputParaboloidDepthTessEval(tessEvalShader);
+ tessEvalShader.Append("}");
+
+ IShaderProgramGenerator::OutputParaboloidDepthFragment(fragmentShader);
+ }
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetParaboloidDepthTessNPatchShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_ParaboloidDepthTessNPatchShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("paraboloid depth tess NPatch shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ // vertexShader.AddOutgoing("world_pos", "vec4");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ // vertexShader.Append("\tworld_pos = attr_pos;");
+ vertexShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationNPatch.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ // tessCtrlShader.AddOutgoing( "outUVTC", "vec2" );
+ // tessCtrlShader.AddOutgoing( "outNormalTC", "vec3" );
+ tessCtrlShader.Append("void main() {\n");
+ // tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ // tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ // tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationNPatch.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ IShaderProgramGenerator::OutputParaboloidDepthTessEval(tessEvalShader);
+ tessEvalShader.Append("}");
+
+ IShaderProgramGenerator::OutputParaboloidDepthFragment(fragmentShader);
+ }
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *
+ Qt3DSRendererImpl::GetCubeShadowDepthShader(TessModeValues::Enum inTessMode)
+ {
+ if (!m_qt3dsContext.GetRenderContext().IsTessellationSupported()
+ || inTessMode == TessModeValues::NoTess) {
+ return GetCubeDepthNoTessShader();
+ } else if (inTessMode == TessModeValues::TessLinear) {
+ return GetCubeDepthTessLinearShader();
+ } else if (inTessMode == TessModeValues::TessPhong) {
+ return GetCubeDepthTessPhongShader();
+ } else if (inTessMode == TessModeValues::TessNPatch) {
+ return GetCubeDepthTessNPatchShader();
+ }
+
+ return GetCubeDepthNoTessShader();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetCubeDepthNoTessShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_CubemapDepthShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("cubemap face depth shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+
+ if (!depthShaderProgram) {
+ // GetProgramGenerator().BeginProgram(
+ // TShaderGeneratorStageFlags(ShaderGeneratorStages::Vertex |
+ // ShaderGeneratorStages::Fragment | ShaderGeneratorStages::Geometry) );
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ // IShaderStageGenerator& geometryShader( *GetProgramGenerator().GetStage(
+ // ShaderGeneratorStages::Geometry ) );
+
+ IShaderProgramGenerator::OutputCubeFaceDepthVertex(vertexShader);
+ // IShaderProgramGenerator::OutputCubeFaceDepthGeometry( geometryShader );
+ IShaderProgramGenerator::OutputCubeFaceDepthFragment(fragmentShader);
+ } else if (theCache.IsShaderCachePersistenceEnabled()) {
+ // we load from shader cache set default shader stages
+ GetProgramGenerator().BeginProgram();
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetCubeDepthTessLinearShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_CubemapDepthTessLinearShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("cubemap face depth linear tess shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+
+ if (!depthShaderProgram) {
+ // GetProgramGenerator().BeginProgram(
+ // TShaderGeneratorStageFlags(ShaderGeneratorStages::Vertex |
+ // ShaderGeneratorStages::Fragment | ShaderGeneratorStages::Geometry) );
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ // IShaderStageGenerator& geometryShader( *GetProgramGenerator().GetStage(
+ // ShaderGeneratorStages::Geometry ) );
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("}");
+
+ // IShaderProgramGenerator::OutputCubeFaceDepthGeometry( geometryShader );
+ IShaderProgramGenerator::OutputCubeFaceDepthFragment(fragmentShader);
+
+ tessCtrlShader.AddInclude("tessellationLinear.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationLinear.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddUniform("model_matrix", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tworld_pos = model_matrix * pos;");
+ tessEvalShader.Append("\tworld_pos /= world_pos.w;");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetCubeDepthTessPhongShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_CubemapDepthTessPhongShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("cubemap face depth phong tess shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+
+ if (!depthShaderProgram) {
+ // GetProgramGenerator().BeginProgram(
+ // TShaderGeneratorStageFlags(ShaderGeneratorStages::Vertex |
+ // ShaderGeneratorStages::Fragment | ShaderGeneratorStages::Geometry) );
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ // IShaderStageGenerator& geometryShader( *GetProgramGenerator().GetStage(
+ // ShaderGeneratorStages::Geometry ) );
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+
+ // IShaderProgramGenerator::OutputCubeFaceDepthGeometry( geometryShader );
+ IShaderProgramGenerator::OutputCubeFaceDepthFragment(fragmentShader);
+
+ tessCtrlShader.AddInclude("tessellationPhong.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationPhong.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddUniform("model_matrix", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tworld_pos = model_matrix * pos;");
+ tessEvalShader.Append("\tworld_pos /= world_pos.w;");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetCubeDepthTessNPatchShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_CubemapDepthTessNPatchShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("cubemap face depth npatch tess shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+
+ if (!depthShaderProgram) {
+ // GetProgramGenerator().BeginProgram(
+ // TShaderGeneratorStageFlags(ShaderGeneratorStages::Vertex |
+ // ShaderGeneratorStages::Fragment | ShaderGeneratorStages::Geometry) );
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ // IShaderStageGenerator& geometryShader( *GetProgramGenerator().GetStage(
+ // ShaderGeneratorStages::Geometry ) );
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+
+ // IShaderProgramGenerator::OutputCubeFaceDepthGeometry( geometryShader );
+ IShaderProgramGenerator::OutputCubeFaceDepthFragment(fragmentShader);
+
+ tessCtrlShader.AddOutgoing("outNormalTC", "vec3");
+ tessCtrlShader.AddInclude("tessellationNPatch.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append(
+ "\toutNormalTC[gl_InvocationID] = outNormal[gl_InvocationID];\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationNPatch.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddUniform("model_matrix", "mat4");
+ tessEvalShader.AddOutgoing("world_pos", "vec4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tctNorm[0] = outNormalTC[0];");
+ tessEvalShader.Append("\tctNorm[1] = outNormalTC[1];");
+ tessEvalShader.Append("\tctNorm[2] = outNormalTC[2];");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tworld_pos = model_matrix * pos;");
+ tessEvalShader.Append("\tworld_pos /= world_pos.w;");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *
+ Qt3DSRendererImpl::GetOrthographicDepthShader(TessModeValues::Enum inTessMode)
+ {
+ if (!m_qt3dsContext.GetRenderContext().IsTessellationSupported()
+ || inTessMode == TessModeValues::NoTess) {
+ return GetOrthographicDepthNoTessShader();
+ } else if (inTessMode == TessModeValues::TessLinear) {
+ return GetOrthographicDepthTessLinearShader();
+ } else if (inTessMode == TessModeValues::TessPhong) {
+ return GetOrthographicDepthTessPhongShader();
+ } else if (inTessMode == TessModeValues::TessNPatch) {
+ return GetOrthographicDepthTessNPatchShader();
+ }
+
+ return GetOrthographicDepthNoTessShader();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetOrthographicDepthNoTessShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_OrthographicDepthShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("orthographic depth shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ vertexShader.AddOutgoing("outDepth", "vec3");
+ vertexShader.Append("void main() {");
+ vertexShader.Append(
+ " gl_Position = model_view_projection * vec4( attr_pos, 1.0 );");
+ vertexShader.Append(" outDepth.x = gl_Position.z / gl_Position.w;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfloat depth = (outDepth.x + 1.0) * 0.5;");
+ fragmentShader.Append("\tfragOutput = vec4(depth);");
+ fragmentShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetOrthographicDepthTessLinearShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_OrthographicDepthTessLinearShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("orthographic depth tess linear shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfloat depth = (outDepth.x + 1.0) * 0.5;");
+ fragmentShader.Append("\tfragOutput = vec4(depth);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationLinear.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationLinear.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddOutgoing("outDepth", "vec3");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("\toutDepth.x = gl_Position.z / gl_Position.w;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetOrthographicDepthTessPhongShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_OrthographicDepthTessPhongShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("orthographic depth tess phong shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfloat depth = (outDepth.x + 1.0) * 0.5;");
+ fragmentShader.Append("\tfragOutput = vec4(depth);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationPhong.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationPhong.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddOutgoing("outDepth", "vec3");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("\toutDepth.x = gl_Position.z / gl_Position.w;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetOrthographicDepthTessNPatchShader()
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthShader =
+ m_OrthographicDepthTessNPatchShader;
+
+ if (theDepthShader.hasValue() == false) {
+ TStrType name;
+ name.assign("orthographic depth tess npatch shader");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ fragmentShader.AddUniform("model_view_projection", "mat4");
+ fragmentShader.AddUniform("camera_properties", "vec2");
+ fragmentShader.AddUniform("camera_position", "vec3");
+ fragmentShader.AddUniform("camera_direction", "vec3");
+ fragmentShader.AddInclude("depthpass.glsllib");
+
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ // fragmentShader.Append("\tfragOutput = vec4(0.0, 0.0, 0.0, 0.0);");
+ fragmentShader.Append("\tfloat depth = (outDepth.x - camera_properties.x) / "
+ "(camera_properties.y - camera_properties.x);");
+ fragmentShader.Append("\tfragOutput = vec4(depth);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationNPatch.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.AddOutgoing("outNormalTC", "vec3");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationNPatch.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.AddUniform("model_matrix", "mat4");
+ tessEvalShader.AddOutgoing("outDepth", "vec3");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+ tessEvalShader.Append("\toutDepth.x = gl_Position.z / gl_Position.w;");
+ tessEvalShader.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+
+ return theDepthShader.getValue();
+ }
+
+ // ---------------------------------
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetDepthPrepassShader(bool inDisplaced)
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthPrePassShader =
+ (!inDisplaced) ? m_DepthPrepassShader : m_DepthPrepassShaderDisplaced;
+
+ if (theDepthPrePassShader.hasValue() == false) {
+ // check if we do displacement mapping
+ TStrType name;
+ name.assign("depth prepass shader");
+ if (inDisplaced)
+ name.append(" displacement");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+
+ vertexShader.Append("void main() {");
+
+ if (inDisplaced) {
+ GetQt3DSContext()
+ .GetDefaultMaterialShaderGenerator()
+ .AddDisplacementMappingForDepthPass(vertexShader);
+ } else {
+ vertexShader.Append(
+ "\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);");
+ }
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfragOutput = vec4(0.0, 0.0, 0.0, 0.0);");
+ fragmentShader.Append("}");
+ } else if (theCache.IsShaderCachePersistenceEnabled()) {
+ // we load from shader cache set default shader stages
+ GetProgramGenerator().BeginProgram();
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthPrePassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthPrePassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+ return theDepthPrePassShader.getValue();
+ }
+
+ SRenderableDepthPrepassShader *
+ Qt3DSRendererImpl::GetDepthTessPrepassShader(TessModeValues::Enum inTessMode, bool inDisplaced)
+ {
+ if (!m_qt3dsContext.GetRenderContext().IsTessellationSupported()
+ || inTessMode == TessModeValues::NoTess) {
+ return GetDepthPrepassShader(inDisplaced);
+ } else if (inTessMode == TessModeValues::TessLinear) {
+ return GetDepthTessLinearPrepassShader(inDisplaced);
+ } else if (inTessMode == TessModeValues::TessPhong) {
+ return GetDepthTessPhongPrepassShader();
+ } else if (inTessMode == TessModeValues::TessNPatch) {
+ return GetDepthTessNPatchPrepassShader();
+ }
+
+ return GetDepthPrepassShader(inDisplaced);
+ }
+
+ SRenderableDepthPrepassShader *
+ Qt3DSRendererImpl::GetDepthTessLinearPrepassShader(bool inDisplaced)
+ {
+ Option<NVScopedRefCounted<SRenderableDepthPrepassShader>> &theDepthPrePassShader =
+ (!inDisplaced) ? m_DepthTessLinearPrepassShader
+ : m_DepthTessLinearPrepassShaderDisplaced;
+
+ if (theDepthPrePassShader.hasValue() == false) {
+ // check if we do displacement mapping
+ TStrType name;
+ name.assign("depth tess linear prepass shader");
+ if (inDisplaced)
+ name.append(" displacement");
+
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey = m_qt3dsContext.GetStringTable().RegisterStr(name.c_str());
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ if (inDisplaced) {
+ vertexShader.AddIncoming("attr_uv0", "vec2");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+
+ vertexShader.AddUniform("displacementMap_rot", "vec4");
+ vertexShader.AddUniform("displacementMap_offset", "vec3");
+
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.AddOutgoing("outUV", "vec2");
+ }
+ vertexShader.AddOutgoing("outWorldPos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ vertexShader.AddUniform("model_matrix", "mat4");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ if (inDisplaced) {
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("\tvec3 uTransform = vec3( displacementMap_rot.x, "
+ "displacementMap_rot.y, displacementMap_offset.x );");
+ vertexShader.Append("\tvec3 vTransform = vec3( displacementMap_rot.z, "
+ "displacementMap_rot.w, displacementMap_offset.y );");
+ vertexShader.AddInclude(
+ "defaultMaterialLighting.glsllib"); // getTransformedUVCoords is in the
+ // lighting code addition.
+ vertexShader << "\tvec2 uv_coords = attr_uv0;" << Endl;
+ vertexShader << "\toutUV = getTransformedUVCoords( vec3( uv_coords, 1.0), "
+ "uTransform, vTransform );\n";
+ }
+ vertexShader.Append("\toutWorldPos = (model_matrix * vec4(attr_pos, 1.0)).xyz;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfragOutput = vec4(0.0, 0.0, 0.0, 0.0);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationLinear.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.AddOutgoing("outUVTC", "vec2");
+ tessCtrlShader.AddOutgoing("outNormalTC", "vec3");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+
+ if (inDisplaced) {
+ tessCtrlShader.Append("\toutUVTC[gl_InvocationID] = outUV[gl_InvocationID];");
+ tessCtrlShader.Append(
+ "\toutNormalTC[gl_InvocationID] = outNormal[gl_InvocationID];");
+ }
+
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationLinear.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ if (inDisplaced) {
+ tessEvalShader.AddUniform("displacementSampler", "sampler2D");
+ tessEvalShader.AddUniform("displaceAmount", "float");
+ tessEvalShader.AddInclude("defaultMaterialFileDisplacementTexture.glsllib");
+ }
+ tessEvalShader.AddOutgoing("outUV", "vec2");
+ tessEvalShader.AddOutgoing("outNormal", "vec3");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+
+ if (inDisplaced) {
+ tessEvalShader << "\toutUV = gl_TessCoord.x * outUVTC[0] + gl_TessCoord.y * "
+ "outUVTC[1] + gl_TessCoord.z * outUVTC[2];"
+ << Endl;
+ tessEvalShader
+ << "\toutNormal = gl_TessCoord.x * outNormalTC[0] + gl_TessCoord.y * "
+ "outNormalTC[1] + gl_TessCoord.z * outNormalTC[2];"
+ << Endl;
+ tessEvalShader
+ << "\tvec3 displacedPos = defaultMaterialFileDisplacementTexture( "
+ "displacementSampler , displaceAmount, outUV , outNormal, pos.xyz );"
+ << Endl;
+ tessEvalShader.Append(
+ "\tgl_Position = model_view_projection * vec4(displacedPos, 1.0);");
+ } else
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;");
+
+ tessEvalShader.Append("}");
+ } else if (theCache.IsShaderCachePersistenceEnabled()) {
+ // we load from shader cache set default shader stages
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ }
+
+ SShaderCacheProgramFlags theFlags;
+ theFlags.SetTessellationEnabled(true);
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ name.c_str(), theFlags, TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ theDepthPrePassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ theDepthPrePassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+ return theDepthPrePassShader->mPtr;
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetDepthTessPhongPrepassShader()
+ {
+ if (m_DepthTessPhongPrepassShader.hasValue() == false) {
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr("depth tess phong prepass shader");
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.AddOutgoing("outWorldPos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ vertexShader.AddUniform("model_matrix", "mat4");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutWorldPos = (model_matrix * vec4(attr_pos, 1.0)).xyz;");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfragOutput = vec4(0.0, 0.0, 0.0, 0.0);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddInclude("tessellationPhong.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationPhong.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;\n");
+ tessEvalShader.Append("}");
+ } else if (theCache.IsShaderCachePersistenceEnabled()) {
+ // we load from shader cache set default shader stages
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ }
+
+ SShaderCacheProgramFlags theFlags;
+ theFlags.SetTessellationEnabled(true);
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ "depth tess phong prepass shader", theFlags, TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ m_DepthTessPhongPrepassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ m_DepthTessPhongPrepassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+ return m_DepthTessPhongPrepassShader->mPtr;
+ }
+
+ SRenderableDepthPrepassShader *Qt3DSRendererImpl::GetDepthTessNPatchPrepassShader()
+ {
+ if (m_DepthTessNPatchPrepassShader.hasValue() == false) {
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr("depth tess npatch prepass shader");
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &vertexShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &tessCtrlShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessControl));
+ IShaderStageGenerator &tessEvalShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::TessEval));
+ IShaderStageGenerator &fragmentShader(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexShader.AddIncoming("attr_pos", "vec3");
+ vertexShader.AddIncoming("attr_norm", "vec3");
+ vertexShader.AddOutgoing("outNormal", "vec3");
+ vertexShader.AddOutgoing("outWorldPos", "vec3");
+ vertexShader.AddUniform("model_view_projection", "mat4");
+ vertexShader.AddUniform("model_matrix", "mat4");
+ vertexShader.Append("void main() {");
+ vertexShader.Append("\tgl_Position = vec4(attr_pos, 1.0);");
+ vertexShader.Append("\toutWorldPos = (model_matrix * vec4(attr_pos, 1.0)).xyz;");
+ vertexShader.Append("\toutNormal = attr_norm;");
+ vertexShader.Append("}");
+ fragmentShader.Append("void main() {");
+ fragmentShader.Append("\tfragOutput = vec4(0.0, 0.0, 0.0, 0.0);");
+ fragmentShader.Append("}");
+
+ tessCtrlShader.AddOutgoing("outNormalTC", "vec3");
+ tessCtrlShader.AddInclude("tessellationNPatch.glsllib");
+ tessCtrlShader.AddUniform("tessLevelInner", "float");
+ tessCtrlShader.AddUniform("tessLevelOuter", "float");
+ tessCtrlShader.Append("void main() {\n");
+ tessCtrlShader.Append("\tctWorldPos[0] = outWorldPos[0];");
+ tessCtrlShader.Append("\tctWorldPos[1] = outWorldPos[1];");
+ tessCtrlShader.Append("\tctWorldPos[2] = outWorldPos[2];");
+ tessCtrlShader.Append("\tctNorm[0] = outNormal[0];");
+ tessCtrlShader.Append("\tctNorm[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctNorm[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tctTangent[0] = outNormal[0];"); // we don't care for the tangent
+ tessCtrlShader.Append("\tctTangent[1] = outNormal[1];");
+ tessCtrlShader.Append("\tctTangent[2] = outNormal[2];");
+ tessCtrlShader.Append(
+ "\tgl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;");
+ tessCtrlShader.Append("\ttessShader( tessLevelOuter, tessLevelInner);\n");
+ tessCtrlShader.Append(
+ "\toutNormalTC[gl_InvocationID] = outNormal[gl_InvocationID];\n");
+ tessCtrlShader.Append("}");
+
+ tessEvalShader.AddInclude("tessellationNPatch.glsllib");
+ tessEvalShader.AddUniform("model_view_projection", "mat4");
+ tessEvalShader.Append("void main() {");
+ tessEvalShader.Append("\tctNorm[0] = outNormalTC[0];");
+ tessEvalShader.Append("\tctNorm[1] = outNormalTC[1];");
+ tessEvalShader.Append("\tctNorm[2] = outNormalTC[2];");
+ tessEvalShader.Append(
+ "\tctTangent[0] = outNormalTC[0];"); // we don't care for the tangent
+ tessEvalShader.Append("\tctTangent[1] = outNormalTC[1];");
+ tessEvalShader.Append("\tctTangent[2] = outNormalTC[2];");
+ tessEvalShader.Append("\tvec4 pos = tessShader( );\n");
+ tessEvalShader.Append("\tgl_Position = model_view_projection * pos;\n");
+ tessEvalShader.Append("}");
+ } else if (theCache.IsShaderCachePersistenceEnabled()) {
+ // we load from shader cache set default shader stages
+ GetProgramGenerator().BeginProgram(TShaderGeneratorStageFlags(
+ ShaderGeneratorStages::Vertex | ShaderGeneratorStages::TessControl
+ | ShaderGeneratorStages::TessEval | ShaderGeneratorStages::Fragment));
+ }
+
+ SShaderCacheProgramFlags theFlags;
+ theFlags.SetTessellationEnabled(true);
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ "depth tess npatch prepass shader", theFlags, TShaderFeatureSet());
+
+ if (depthShaderProgram) {
+ m_DepthTessNPatchPrepassShader = NVScopedRefCounted<SRenderableDepthPrepassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(),
+ SRenderableDepthPrepassShader)(*depthShaderProgram, GetContext()));
+ } else {
+ m_DepthTessNPatchPrepassShader =
+ NVScopedRefCounted<SRenderableDepthPrepassShader>();
+ }
+ }
+ return m_DepthTessNPatchPrepassShader->mPtr;
+ }
+
+ SDefaultAoPassShader *Qt3DSRendererImpl::GetDefaultAoPassShader(TShaderFeatureSet inFeatureSet)
+ {
+ if (m_DefaultAoPassShader.hasValue() == false) {
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr("fullscreen AO pass shader");
+ NVRenderShaderProgram *aoPassShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!aoPassShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &theVertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &theFragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ theVertexGenerator.AddIncoming("attr_pos", "vec3");
+ theVertexGenerator.AddIncoming("attr_uv", "vec2");
+ theVertexGenerator.AddOutgoing("uv_coords", "vec2");
+ theVertexGenerator.Append("void main() {");
+ theVertexGenerator.Append("\tgl_Position = vec4(attr_pos.xy, 0.5, 1.0 );");
+ theVertexGenerator.Append("\tuv_coords = attr_uv;");
+ theVertexGenerator.Append("}");
+
+ // fragmentGenerator.AddInclude( "SSAOCustomMaterial.glsllib" );
+ theFragmentGenerator.AddInclude("viewProperties.glsllib");
+ theFragmentGenerator.AddInclude("screenSpaceAO.glsllib");
+ if (m_Context->GetRenderContextType() == NVRenderContextValues::GLES2) {
+ theFragmentGenerator
+ << "\tuniform vec4 ao_properties;" << Endl
+ << "\tuniform vec4 ao_properties2;" << Endl
+ << "\tuniform vec4 shadow_properties;" << Endl
+ << "\tuniform vec4 aoScreenConst;" << Endl
+ << "\tuniform vec4 UvToEyeConst;" << Endl;
+ } else {
+ theFragmentGenerator
+ << "layout (std140) uniform cbAoShadow { " << Endl << "\tvec4 ao_properties;"
+ << Endl << "\tvec4 ao_properties2;" << Endl << "\tvec4 shadow_properties;"
+ << Endl << "\tvec4 aoScreenConst;" << Endl << "\tvec4 UvToEyeConst;" << Endl
+ << "};" << Endl;
+ }
+ theFragmentGenerator.AddUniform("camera_direction", "vec3");
+ theFragmentGenerator.AddUniform("depth_sampler", "sampler2D");
+ theFragmentGenerator.Append("void main() {");
+ theFragmentGenerator << "\tfloat aoFactor;" << Endl;
+ theFragmentGenerator << "\tvec3 screenNorm;" << Endl;
+
+ // We're taking multiple depth samples and getting the derivatives at each of them
+ // to get a more
+ // accurate view space normal vector. When we do only one, we tend to get bizarre
+ // values at the edges
+ // surrounding objects, and this also ends up giving us weird AO values.
+ // If we had a proper screen-space normal map, that would also do the trick.
+ if (m_Context->GetRenderContextType() == NVRenderContextValues::GLES2) {
+ theFragmentGenerator.AddUniform("depth_sampler_size", "vec2");
+ theFragmentGenerator.Append("\tivec2 iCoords = ivec2( gl_FragCoord.xy );");
+ theFragmentGenerator.Append("\tfloat depth = getDepthValue( "
+ "texture2D(depth_sampler, vec2(iCoords)"
+ " / depth_sampler_size), camera_properties );");
+ theFragmentGenerator.Append(
+ "\tdepth = depthValueToLinearDistance( depth, camera_properties );");
+ theFragmentGenerator.Append("\tdepth = (depth - camera_properties.x) / "
+ "(camera_properties.y - camera_properties.x);");
+ theFragmentGenerator.Append("\tfloat depth2 = getDepthValue( "
+ "texture2D(depth_sampler, vec2(iCoords+ivec2(1))"
+ " / depth_sampler_size), camera_properties );");
+ theFragmentGenerator.Append(
+ "\tdepth2 = depthValueToLinearDistance( depth, camera_properties );");
+ theFragmentGenerator.Append("\tfloat depth3 = getDepthValue( "
+ "texture2D(depth_sampler, vec2(iCoords-ivec2(1))"
+ " / depth_sampler_size), camera_properties );");
+ } else {
+ theFragmentGenerator.Append("\tivec2 iCoords = ivec2( gl_FragCoord.xy );");
+ theFragmentGenerator.Append("\tfloat depth = getDepthValue( "
+ "texelFetch(depth_sampler, iCoords, 0), "
+ "camera_properties );");
+ theFragmentGenerator.Append(
+ "\tdepth = depthValueToLinearDistance( depth, camera_properties );");
+ theFragmentGenerator.Append("\tdepth = (depth - camera_properties.x) / "
+ "(camera_properties.y - camera_properties.x);");
+ theFragmentGenerator.Append("\tfloat depth2 = getDepthValue( "
+ "texelFetch(depth_sampler, iCoords+ivec2(1), 0), "
+ "camera_properties );");
+ theFragmentGenerator.Append(
+ "\tdepth2 = depthValueToLinearDistance( depth, camera_properties );");
+ theFragmentGenerator.Append("\tfloat depth3 = getDepthValue( "
+ "texelFetch(depth_sampler, iCoords-ivec2(1), 0), "
+ "camera_properties );");
+ }
+ theFragmentGenerator.Append(
+ "\tdepth3 = depthValueToLinearDistance( depth, camera_properties );");
+ theFragmentGenerator.Append("\tvec3 tanU = vec3(10, 0, dFdx(depth));");
+ theFragmentGenerator.Append("\tvec3 tanV = vec3(0, 10, dFdy(depth));");
+ theFragmentGenerator.Append("\tscreenNorm = normalize(cross(tanU, tanV));");
+ theFragmentGenerator.Append("\ttanU = vec3(10, 0, dFdx(depth2));");
+ theFragmentGenerator.Append("\ttanV = vec3(0, 10, dFdy(depth2));");
+ theFragmentGenerator.Append("\tscreenNorm += normalize(cross(tanU, tanV));");
+ theFragmentGenerator.Append("\ttanU = vec3(10, 0, dFdx(depth3));");
+ theFragmentGenerator.Append("\ttanV = vec3(0, 10, dFdy(depth3));");
+ theFragmentGenerator.Append("\tscreenNorm += normalize(cross(tanU, tanV));");
+ theFragmentGenerator.Append("\tscreenNorm = -normalize(screenNorm);");
+
+ theFragmentGenerator.Append("\taoFactor = \
+ SSambientOcclusion( depth_sampler, screenNorm, ao_properties, ao_properties2, \
+ camera_properties, aoScreenConst, UvToEyeConst );");
+
+ theFragmentGenerator.Append(
+ "\tgl_FragColor = vec4(aoFactor, aoFactor, aoFactor, 1.0);");
+
+ theFragmentGenerator.Append("}");
+ }
+
+ aoPassShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ "fullscreen AO pass shader", SShaderCacheProgramFlags(), inFeatureSet);
+
+ if (aoPassShaderProgram) {
+ m_DefaultAoPassShader = NVScopedRefCounted<SDefaultAoPassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(), SDefaultAoPassShader)(*aoPassShaderProgram,
+ GetContext()));
+ } else {
+ m_DefaultAoPassShader = NVScopedRefCounted<SDefaultAoPassShader>();
+ }
+ }
+ return m_DefaultAoPassShader->mPtr;
+ }
+
+ SDefaultAoPassShader *Qt3DSRendererImpl::GetFakeDepthShader(TShaderFeatureSet inFeatureSet)
+ {
+ if (m_FakeDepthShader.hasValue() == false) {
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr("depth display shader");
+ NVRenderShaderProgram *depthShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!depthShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &theVertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &theFragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ theVertexGenerator.AddIncoming("attr_pos", "vec3");
+ theVertexGenerator.AddIncoming("attr_uv", "vec2");
+ theVertexGenerator.AddOutgoing("uv_coords", "vec2");
+ theVertexGenerator.Append("void main() {");
+ theVertexGenerator.Append("\tgl_Position = vec4(attr_pos.xy, 0.5, 1.0 );");
+ theVertexGenerator.Append("\tuv_coords = attr_uv;");
+ theVertexGenerator.Append("}");
+
+ theFragmentGenerator.AddUniform("depth_sampler", "sampler2D");
+ theFragmentGenerator.Append("void main() {");
+ theFragmentGenerator.Append("\tivec2 iCoords = ivec2( gl_FragCoord.xy );");
+ theFragmentGenerator.Append(
+ "\tfloat depSample = texelFetch(depth_sampler, iCoords, 0).x;");
+ theFragmentGenerator.Append(
+ "\tgl_FragColor = vec4( depSample, depSample, depSample, 1.0 );");
+ theFragmentGenerator.Append("\treturn;");
+ theFragmentGenerator.Append("}");
+ }
+
+ depthShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ "depth display shader", SShaderCacheProgramFlags(), inFeatureSet);
+
+ if (depthShaderProgram) {
+ m_FakeDepthShader = NVScopedRefCounted<SDefaultAoPassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(), SDefaultAoPassShader)(
+ *depthShaderProgram, GetContext()));
+ } else {
+ m_FakeDepthShader = NVScopedRefCounted<SDefaultAoPassShader>();
+ }
+ }
+ return m_FakeDepthShader->mPtr;
+ }
+
+ SDefaultAoPassShader *Qt3DSRendererImpl::GetFakeCubeDepthShader(TShaderFeatureSet inFeatureSet)
+ {
+ if (!m_FakeCubemapDepthShader.hasValue()) {
+ IShaderCache &theCache = m_qt3dsContext.GetShaderCache();
+ CRegisteredString theCacheKey =
+ m_qt3dsContext.GetStringTable().RegisterStr("cube depth display shader");
+ NVRenderShaderProgram *cubeShaderProgram =
+ theCache.GetProgram(theCacheKey, TShaderFeatureSet());
+ if (!cubeShaderProgram) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &theVertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &theFragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ theVertexGenerator.AddIncoming("attr_pos", "vec3");
+ theVertexGenerator.AddIncoming("attr_uv", "vec2");
+ theVertexGenerator.AddOutgoing("sample_dir", "vec3");
+ theVertexGenerator.Append("void main() {");
+ theVertexGenerator.Append("\tgl_Position = vec4(attr_pos.xy, 0.5, 1.0 );");
+ theVertexGenerator.Append(
+ "\tsample_dir = vec3(4.0 * (attr_uv.x - 0.5), -1.0, 4.0 * (attr_uv.y - 0.5));");
+ theVertexGenerator.Append("}");
+ theFragmentGenerator.AddUniform("depth_cube", "samplerCube");
+ theFragmentGenerator.Append("void main() {");
+ theFragmentGenerator.Append(
+ "\tfloat smpDepth = texture( depth_cube, sample_dir ).x;");
+ theFragmentGenerator.Append(
+ "\tgl_FragColor = vec4(smpDepth, smpDepth, smpDepth, 1.0);");
+ theFragmentGenerator.Append("}");
+ }
+
+ cubeShaderProgram = GetProgramGenerator().CompileGeneratedShader(
+ "cube depth display shader", SShaderCacheProgramFlags(), inFeatureSet);
+
+ if (cubeShaderProgram) {
+ m_FakeCubemapDepthShader = NVScopedRefCounted<SDefaultAoPassShader>(
+ QT3DS_NEW(GetContext().GetAllocator(), SDefaultAoPassShader)(*cubeShaderProgram,
+ GetContext()));
+ } else {
+ m_FakeCubemapDepthShader = NVScopedRefCounted<SDefaultAoPassShader>();
+ }
+ }
+ return m_FakeCubemapDepthShader.getValue();
+ }
+
+ STextRenderHelper Qt3DSRendererImpl::GetTextShader(bool inUsePathRendering)
+ {
+ STextShaderPtr &thePtr = (!inUsePathRendering) ? m_TextShader : m_TextPathShader;
+ if (thePtr.HasGeneratedShader())
+ return STextRenderHelper(thePtr, *m_QuadInputAssembler);
+
+ NVRenderShaderProgram *theShader = NULL;
+ NVRenderProgramPipeline *thePipeline = NULL;
+
+ if (!inUsePathRendering) {
+ GetProgramGenerator().BeginProgram();
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ // xy of text dimensions are scaling factors, zw are offset factors.
+ vertexGenerator.AddUniform("text_dimensions", "vec4");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator
+ << "\tvec3 textPos = vec3(attr_pos.x * text_dimensions.x + text_dimensions.z"
+ << ", attr_pos.y * text_dimensions.y + text_dimensions.w"
+ << ", attr_pos.z);" << Endl;
+
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(textPos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+
+ fragmentGenerator.AddUniform("text_textcolor", "vec4");
+ fragmentGenerator.AddUniform("text_textdimensions", "vec3");
+ fragmentGenerator.AddUniform("text_image", "sampler2D");
+ fragmentGenerator.AddUniform("text_backgroundcolor", "vec3");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 theCoords = uv_coords;");
+ // Enable rendering from a sub-rect
+
+ fragmentGenerator
+ << "\ttheCoords.x = theCoords.x * text_textdimensions.x;" << Endl
+ << "\ttheCoords.y = theCoords.y * text_textdimensions.y;" << Endl
+ // flip the y uv coord if the dimension's z variable is set
+ << "\tif ( text_textdimensions.z > 0.0 ) theCoords.y = 1.0 - theCoords.y;" << Endl;
+ fragmentGenerator.Append(
+ "\tvec4 c = texture2D(text_image, theCoords);");
+ fragmentGenerator.Append(
+ "\tfragOutput = vec4(mix(text_backgroundcolor.rgb, "
+ "text_textcolor.rgb, c.rgb), c.a) * text_textcolor.a;");
+
+ vertexGenerator.Append("}");
+ fragmentGenerator.Append("}");
+ const char *shaderName = "text shader";
+ theShader = GetProgramGenerator().CompileGeneratedShader(
+ shaderName, SShaderCacheProgramFlags(), TShaderFeatureSet(), false);
+ } else {
+ GetProgramGenerator().BeginProgram(
+ TShaderGeneratorStageFlags(ShaderGeneratorStages::Fragment));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ fragmentGenerator.AddUniform("text_textcolor", "vec4");
+ fragmentGenerator.AddUniform("text_backgroundcolor", "vec3");
+
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tfragOutput = vec4(mix(text_backgroundcolor.rgb, "
+ "text_textcolor.rgb, text_textcolor.a), text_textcolor.a );");
+ fragmentGenerator.Append("}");
+
+ const char *shaderName = "text path shader";
+ theShader = GetProgramGenerator().CompileGeneratedShader(
+ shaderName, SShaderCacheProgramFlags(), TShaderFeatureSet(), true);
+
+ // setup program pipeline
+ if (theShader) {
+ thePipeline = GetContext().CreateProgramPipeline();
+ if (thePipeline) {
+ thePipeline->SetProgramStages(
+ theShader,
+ qt3ds::render::NVRenderShaderTypeFlags(NVRenderShaderTypeValue::Fragment));
+ }
+ }
+ }
+
+ if (theShader == NULL) {
+ thePtr.Set(NULL);
+ } else {
+ GenerateXYQuad();
+ thePtr.Set(QT3DS_NEW(m_Context->GetAllocator(), STextShader)(*theShader, thePipeline));
+ }
+ return STextRenderHelper(thePtr, *m_QuadInputAssembler);
+ }
+
+ STextDepthShader *Qt3DSRendererImpl::GetTextDepthShader()
+ {
+ if (m_TextDepthPrepassShader.hasValue() == false) {
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ // xy of text dimensions are scaling factors, zw are offset factors.
+ vertexGenerator.AddUniform("text_dimensions", "vec4");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator
+ << "\tvec3 textPos = vec3(attr_pos.x * text_dimensions.x + text_dimensions.z"
+ << ", attr_pos.y * text_dimensions.y + text_dimensions.w"
+ << ", attr_pos.z);" << Endl;
+
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(textPos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+
+ fragmentGenerator.AddUniform("text_textdimensions", "vec3");
+ fragmentGenerator.AddUniform("text_image", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 theCoords = uv_coords;");
+ // Enable rendering from a sub-rect
+
+ fragmentGenerator
+ << "\ttheCoords.x = theCoords.x * text_textdimensions.x;" << Endl
+ << "\ttheCoords.y = theCoords.y * text_textdimensions.y;" << Endl
+ // flip the y uv coord if the dimension's z variable is set
+ << "\tif ( text_textdimensions.z > 0.0 ) theCoords.y = 1.0 - theCoords.y;" << Endl;
+ fragmentGenerator.Append("\tfloat alpha_mask = texture2D( text_image, theCoords ).r;");
+ fragmentGenerator.Append("\tif ( alpha_mask < .05 ) discard;");
+ vertexGenerator.Append("}");
+ fragmentGenerator.Append("}");
+ const char *shaderName = "text depth shader";
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ shaderName, SShaderCacheProgramFlags(), TShaderFeatureSet());
+ if (theShader == NULL) {
+ m_TextDepthPrepassShader = NVScopedRefCounted<STextDepthShader>();
+ } else {
+ GenerateXYQuad();
+ m_TextDepthPrepassShader = NVScopedRefCounted<STextDepthShader>(
+ QT3DS_NEW(m_Context->GetAllocator(), STextDepthShader)(
+ m_Context->GetAllocator(), *theShader, *m_QuadInputAssembler));
+ }
+ }
+ return m_TextDepthPrepassShader->mPtr;
+ }
+
+ STextRenderHelper Qt3DSRendererImpl::GetTextWidgetShader()
+ {
+ if (m_TextWidgetShader.HasGeneratedShader())
+ return STextRenderHelper(m_TextWidgetShader, *m_QuadInputAssembler);
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ // xy of text dimensions are scaling factors, zw are offset factors.
+ vertexGenerator.AddUniform("text_dimensions", "vec4");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator
+ << "\tvec3 textPos = vec3(attr_pos.x * text_dimensions.x + text_dimensions.z"
+ << ", attr_pos.y * text_dimensions.y + text_dimensions.w"
+ << ", attr_pos.z);" << Endl;
+
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(textPos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("text_textcolor", "vec4");
+ fragmentGenerator.AddUniform("text_textdimensions", "vec3");
+ fragmentGenerator.AddUniform("text_image", "sampler2D");
+ fragmentGenerator.AddUniform("text_backgroundcolor", "vec3");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 theCoords = uv_coords;");
+ // Enable rendering from a sub-rect
+
+ fragmentGenerator << "\ttheCoords.x = theCoords.x * text_textdimensions.x;" << Endl
+ << "\ttheCoords.y = theCoords.y * text_textdimensions.y;" << Endl
+ // flip the y uv coord if the dimension's z variable is set
+ << "\tif ( text_textdimensions.z > 0.0 ) theCoords.y = 1.0 - theCoords.y;"
+ << Endl;
+ fragmentGenerator.Append(
+ "\tfloat alpha_mask = texture2D( text_image, theCoords ).r * text_textcolor.a;");
+ fragmentGenerator.Append("\tfragOutput = vec4(mix(text_backgroundcolor.rgb, "
+ "text_textcolor.rgb, alpha_mask), 1.0 );");
+ fragmentGenerator.Append("}");
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "text widget shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (theShader == NULL)
+ m_TextWidgetShader.Set(NULL);
+ else {
+ GenerateXYQuad();
+ m_TextWidgetShader.Set(QT3DS_NEW(m_Context->GetAllocator(), STextShader)(*theShader));
+ }
+ return STextRenderHelper(m_TextWidgetShader, *m_QuadInputAssembler);
+ }
+
+ STextRenderHelper Qt3DSRendererImpl::GetOnscreenTextShader()
+ {
+ if (m_TextOnscreenShader.HasGeneratedShader())
+ return STextRenderHelper(m_TextOnscreenShader, *m_QuadStripInputAssembler);
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddUniform("vertex_offsets", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+
+ vertexGenerator.Append("\tvec3 pos = attr_pos + vec3(vertex_offsets, 0.0);");
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(pos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("text_textcolor", "vec4");
+ fragmentGenerator.AddUniform("text_image", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tfloat alpha = texture2D( text_image, uv_coords ).a;");
+ fragmentGenerator.Append(
+ "\tfragOutput = vec4(text_textcolor.r, text_textcolor.g, text_textcolor.b, alpha);");
+ fragmentGenerator.Append("}");
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "onscreen texture shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ if (theShader == NULL)
+ m_TextOnscreenShader.Set(NULL);
+ else {
+ GenerateXYQuadStrip();
+ m_TextOnscreenShader.Set(QT3DS_NEW(m_Context->GetAllocator(), STextShader)(*theShader));
+ }
+ return STextRenderHelper(m_TextOnscreenShader, *m_QuadStripInputAssembler);
+ }
+
+ NVRenderShaderProgram *Qt3DSRendererImpl::GetTextAtlasEntryShader()
+ {
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("text_image", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tfloat alpha = texture2D( text_image, uv_coords ).a;");
+ fragmentGenerator.Append("\tfragOutput = vec4(alpha, alpha, alpha, alpha);");
+ fragmentGenerator.Append("}");
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "texture atlas entry shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ return theShader;
+ }
+
+ STextRenderHelper Qt3DSRendererImpl::GetShader(STextRenderable & /*inRenderable*/,
+ bool inUsePathRendering)
+ {
+ return GetTextShader(inUsePathRendering);
+ }
+
+ SLayerSceneShader *Qt3DSRendererImpl::GetSceneLayerShader()
+ {
+ if (m_SceneLayerShader.hasValue())
+ return m_SceneLayerShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ // xy of text dimensions are scaling factors, zw are offset factors.
+ vertexGenerator.AddUniform("layer_dimensions", "vec2");
+ vertexGenerator.AddUniform("model_view_projection", "mat4");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator << "\tvec3 layerPos = vec3(attr_pos.x * layer_dimensions.x / 2.0"
+ << ", attr_pos.y * layer_dimensions.y / 2.0"
+ << ", attr_pos.z);" << Endl;
+
+ vertexGenerator.Append("\tgl_Position = model_view_projection * vec4(layerPos, 1.0);");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("layer_image", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 theCoords = uv_coords;\n");
+ fragmentGenerator.Append("\tvec4 theLayerTexture = texture2D( layer_image, theCoords );\n");
+ fragmentGenerator.Append("\tif( theLayerTexture.a == 0.0 ) discard;\n");
+ fragmentGenerator.Append("\tfragOutput = theLayerTexture;\n");
+ fragmentGenerator.Append("}");
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "layer shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SLayerSceneShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SLayerSceneShader)(*theShader);
+ m_SceneLayerShader = retval;
+ return m_SceneLayerShader.getValue();
+ }
+
+ SLayerProgAABlendShader *Qt3DSRendererImpl::GetLayerProgAABlendShader()
+ {
+ if (m_LayerProgAAShader.hasValue())
+ return m_LayerProgAAShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+ fragmentGenerator.AddUniform("accumulator", "sampler2D");
+ fragmentGenerator.AddUniform("last_frame", "sampler2D");
+ fragmentGenerator.AddUniform("blend_factors", "vec2");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec4 accum = texture2D( accumulator, uv_coords );");
+ fragmentGenerator.Append("\tvec4 lastFrame = texture2D( last_frame, uv_coords );");
+ fragmentGenerator.Append(
+ "\tgl_FragColor = accum*blend_factors.y + lastFrame*blend_factors.x;");
+ fragmentGenerator.Append("}");
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "layer progressiveAA blend shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SLayerProgAABlendShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SLayerProgAABlendShader)(*theShader);
+ m_LayerProgAAShader = retval;
+ return m_LayerProgAAShader.getValue();
+ }
+
+ SShadowmapPreblurShader *Qt3DSRendererImpl::GetCubeShadowBlurXShader()
+ {
+ if (m_CubeShadowBlurXShader.hasValue())
+ return m_CubeShadowBlurXShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ // vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords.xy = attr_pos.xy;");
+ vertexGenerator.Append("}");
+
+ // This with the ShadowBlurYShader design for a 2-pass 5x5 (sigma=1.0)
+ // Weights computed using -- http://dev.theomader.com/gaussian-kernel-calculator/
+ fragmentGenerator.AddUniform("camera_properties", "vec2");
+ fragmentGenerator.AddUniform("depthCube", "samplerCube");
+ // fragmentGenerator.AddUniform("depthSrc", "sampler2D");
+ fragmentGenerator.Append("layout(location = 0) out vec4 frag0;");
+ fragmentGenerator.Append("layout(location = 1) out vec4 frag1;");
+ fragmentGenerator.Append("layout(location = 2) out vec4 frag2;");
+ fragmentGenerator.Append("layout(location = 3) out vec4 frag3;");
+ fragmentGenerator.Append("layout(location = 4) out vec4 frag4;");
+ fragmentGenerator.Append("layout(location = 5) out vec4 frag5;");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tfloat ofsScale = camera_properties.x / 2500.0;");
+ fragmentGenerator.Append("\tvec3 dir0 = vec3(1.0, -uv_coords.y, -uv_coords.x);");
+ fragmentGenerator.Append("\tvec3 dir1 = vec3(-1.0, -uv_coords.y, uv_coords.x);");
+ fragmentGenerator.Append("\tvec3 dir2 = vec3(uv_coords.x, 1.0, uv_coords.y);");
+ fragmentGenerator.Append("\tvec3 dir3 = vec3(uv_coords.x, -1.0, -uv_coords.y);");
+ fragmentGenerator.Append("\tvec3 dir4 = vec3(uv_coords.x, -uv_coords.y, 1.0);");
+ fragmentGenerator.Append("\tvec3 dir5 = vec3(-uv_coords.x, -uv_coords.y, -1.0);");
+ fragmentGenerator.Append("\tfloat depth0;");
+ fragmentGenerator.Append("\tfloat depth1;");
+ fragmentGenerator.Append("\tfloat depth2;");
+ fragmentGenerator.Append("\tfloat outDepth;");
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir0).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir0 + vec3(0.0, 0.0, -ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir0 + vec3(0.0, 0.0, ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir0 + vec3(0.0, 0.0, -2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir0 + vec3(0.0, 0.0, 2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag0 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir1).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir1 + vec3(0.0, 0.0, -ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir1 + vec3(0.0, 0.0, ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir1 + vec3(0.0, 0.0, -2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir1 + vec3(0.0, 0.0, 2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag1 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir2).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir2 + vec3(-ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir2 + vec3(ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir2 + vec3(-2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir2 + vec3(2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag2 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir3).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir3 + vec3(-ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir3 + vec3(ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir3 + vec3(-2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir3 + vec3(2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag3 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir4).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir4 + vec3(-ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir4 + vec3(ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir4 + vec3(-2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir4 + vec3(2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag4 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir5).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir5 + vec3(-ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir5 + vec3(ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir5 + vec3(-2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir5 + vec3(2.0*ofsScale, 0.0, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag5 = vec4(outDepth);");
+
+ fragmentGenerator.Append("}");
+
+ CRegisteredString featureName(m_StringTable->RegisterStr("NO_FRAG_OUTPUT"));
+ SShaderPreprocessorFeature noFragOutputFeature(featureName, true);
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "cubemap shadow blur X shader", SShaderCacheProgramFlags(),
+ TShaderFeatureSet(&noFragOutputFeature, 1));
+ NVScopedRefCounted<SShadowmapPreblurShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SShadowmapPreblurShader)(*theShader);
+ m_CubeShadowBlurXShader = retval;
+ return m_CubeShadowBlurXShader.getValue();
+ }
+
+ SShadowmapPreblurShader *Qt3DSRendererImpl::GetCubeShadowBlurYShader()
+ {
+ if (m_CubeShadowBlurYShader.hasValue())
+ return m_CubeShadowBlurYShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ // vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords.xy = attr_pos.xy;");
+ vertexGenerator.Append("}");
+
+ // This with the ShadowBlurXShader design for a 2-pass 5x5 (sigma=1.0)
+ // Weights computed using -- http://dev.theomader.com/gaussian-kernel-calculator/
+ fragmentGenerator.AddUniform("camera_properties", "vec2");
+ fragmentGenerator.AddUniform("depthCube", "samplerCube");
+ // fragmentGenerator.AddUniform("depthSrc", "sampler2D");
+ fragmentGenerator.Append("layout(location = 0) out vec4 frag0;");
+ fragmentGenerator.Append("layout(location = 1) out vec4 frag1;");
+ fragmentGenerator.Append("layout(location = 2) out vec4 frag2;");
+ fragmentGenerator.Append("layout(location = 3) out vec4 frag3;");
+ fragmentGenerator.Append("layout(location = 4) out vec4 frag4;");
+ fragmentGenerator.Append("layout(location = 5) out vec4 frag5;");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tfloat ofsScale = camera_properties.x / 2500.0;");
+ fragmentGenerator.Append("\tvec3 dir0 = vec3(1.0, -uv_coords.y, -uv_coords.x);");
+ fragmentGenerator.Append("\tvec3 dir1 = vec3(-1.0, -uv_coords.y, uv_coords.x);");
+ fragmentGenerator.Append("\tvec3 dir2 = vec3(uv_coords.x, 1.0, uv_coords.y);");
+ fragmentGenerator.Append("\tvec3 dir3 = vec3(uv_coords.x, -1.0, -uv_coords.y);");
+ fragmentGenerator.Append("\tvec3 dir4 = vec3(uv_coords.x, -uv_coords.y, 1.0);");
+ fragmentGenerator.Append("\tvec3 dir5 = vec3(-uv_coords.x, -uv_coords.y, -1.0);");
+ fragmentGenerator.Append("\tfloat depth0;");
+ fragmentGenerator.Append("\tfloat depth1;");
+ fragmentGenerator.Append("\tfloat depth2;");
+ fragmentGenerator.Append("\tfloat outDepth;");
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir0).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir0 + vec3(0.0, -ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir0 + vec3(0.0, ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir0 + vec3(0.0, -2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir0 + vec3(0.0, 2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag0 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir1).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir1 + vec3(0.0, -ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir1 + vec3(0.0, ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir1 + vec3(0.0, -2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir1 + vec3(0.0, 2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag1 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir2).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir2 + vec3(0.0, 0.0, -ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir2 + vec3(0.0, 0.0, ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir2 + vec3(0.0, 0.0, -2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir2 + vec3(0.0, 0.0, 2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag2 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir3).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir3 + vec3(0.0, 0.0, -ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir3 + vec3(0.0, 0.0, ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir3 + vec3(0.0, 0.0, -2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir3 + vec3(0.0, 0.0, 2.0*ofsScale)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag3 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir4).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir4 + vec3(0.0, -ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir4 + vec3(0.0, ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir4 + vec3(0.0, -2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir4 + vec3(0.0, 2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag4 = vec4(outDepth);");
+
+ fragmentGenerator.Append("\tdepth0 = texture(depthCube, dir5).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 = texture(depthCube, dir5 + vec3(0.0, -ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth1 += texture(depthCube, dir5 + vec3(0.0, ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 = texture(depthCube, dir5 + vec3(0.0, -2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\tdepth2 += texture(depthCube, dir5 + vec3(0.0, 2.0*ofsScale, 0.0)).x;");
+ fragmentGenerator.Append(
+ "\toutDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfrag5 = vec4(outDepth);");
+
+ fragmentGenerator.Append("}");
+
+ CRegisteredString featureName(m_StringTable->RegisterStr("NO_FRAG_OUTPUT"));
+ SShaderPreprocessorFeature noFragOutputFeature(featureName, true);
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "cubemap shadow blur Y shader", SShaderCacheProgramFlags(),
+ TShaderFeatureSet(&noFragOutputFeature, 1));
+ NVScopedRefCounted<SShadowmapPreblurShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SShadowmapPreblurShader)(*theShader);
+ m_CubeShadowBlurYShader = retval;
+ return m_CubeShadowBlurYShader.getValue();
+ }
+
+ SShadowmapPreblurShader *Qt3DSRendererImpl::GetOrthoShadowBlurXShader()
+ {
+ if (m_OrthoShadowBlurXShader.hasValue())
+ return m_OrthoShadowBlurXShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords.xy = attr_uv.xy;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("camera_properties", "vec2");
+ fragmentGenerator.AddUniform("depthSrc", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 ofsScale = vec2( camera_properties.x / 7680.0, 0.0 );");
+ fragmentGenerator.Append("\tfloat depth0 = texture(depthSrc, uv_coords).x;");
+ fragmentGenerator.Append("\tfloat depth1 = texture(depthSrc, uv_coords + ofsScale).x;");
+ fragmentGenerator.Append("\tdepth1 += texture(depthSrc, uv_coords - ofsScale).x;");
+ fragmentGenerator.Append(
+ "\tfloat depth2 = texture(depthSrc, uv_coords + 2.0 * ofsScale).x;");
+ fragmentGenerator.Append("\tdepth2 += texture(depthSrc, uv_coords - 2.0 * ofsScale).x;");
+ fragmentGenerator.Append(
+ "\tfloat outDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfragOutput = vec4(outDepth);");
+ fragmentGenerator.Append("}");
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "shadow map blur X shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SShadowmapPreblurShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SShadowmapPreblurShader)(*theShader);
+ m_OrthoShadowBlurXShader = retval;
+ return m_OrthoShadowBlurXShader.getValue();
+ }
+
+ SShadowmapPreblurShader *Qt3DSRendererImpl::GetOrthoShadowBlurYShader()
+ {
+ if (m_OrthoShadowBlurYShader.hasValue())
+ return m_OrthoShadowBlurYShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords.xy = attr_uv.xy;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("camera_properties", "vec2");
+ fragmentGenerator.AddUniform("depthSrc", "sampler2D");
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec2 ofsScale = vec2( 0.0, camera_properties.x / 7680.0 );");
+ fragmentGenerator.Append("\tfloat depth0 = texture(depthSrc, uv_coords).x;");
+ fragmentGenerator.Append("\tfloat depth1 = texture(depthSrc, uv_coords + ofsScale).x;");
+ fragmentGenerator.Append("\tdepth1 += texture(depthSrc, uv_coords - ofsScale).x;");
+ fragmentGenerator.Append(
+ "\tfloat depth2 = texture(depthSrc, uv_coords + 2.0 * ofsScale).x;");
+ fragmentGenerator.Append("\tdepth2 += texture(depthSrc, uv_coords - 2.0 * ofsScale).x;");
+ fragmentGenerator.Append(
+ "\tfloat outDepth = 0.38774 * depth0 + 0.24477 * depth1 + 0.06136 * depth2;");
+ fragmentGenerator.Append("\tfragOutput = vec4(outDepth);");
+ fragmentGenerator.Append("}");
+
+ NVRenderShaderProgram *theShader = GetProgramGenerator().CompileGeneratedShader(
+ "shadow map blur Y shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SShadowmapPreblurShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SShadowmapPreblurShader)(*theShader);
+ m_OrthoShadowBlurYShader = retval;
+ return m_OrthoShadowBlurYShader.getValue();
+ }
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ SAdvancedModeBlendShader *
+ Qt3DSRendererImpl::GetAdvancedBlendModeShader(AdvancedBlendModes::Enum blendMode)
+ {
+ // Select between blend equations.
+ if (blendMode == AdvancedBlendModes::Overlay) {
+ return GetOverlayBlendModeShader();
+ } else if (blendMode == AdvancedBlendModes::ColorBurn) {
+ return GetColorBurnBlendModeShader();
+ } else if (blendMode == AdvancedBlendModes::ColorDodge) {
+ return GetColorDodgeBlendModeShader();
+ }
+ return {};
+ }
+
+ SAdvancedModeBlendShader *Qt3DSRendererImpl::GetOverlayBlendModeShader()
+ {
+ if (m_AdvancedModeOverlayBlendShader.hasValue())
+ return m_AdvancedModeOverlayBlendShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("base_layer", "sampler2D");
+ fragmentGenerator.AddUniform("blend_layer", "sampler2D");
+
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec4 base = texture2D(base_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (base.a != 0.0) base.rgb /= base.a;");
+ fragmentGenerator.Append("\telse base = vec4(0.0);");
+ fragmentGenerator.Append("\tvec4 blend = texture2D(blend_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (blend.a != 0.0) blend.rgb /= blend.a;");
+ fragmentGenerator.Append("\telse blend = vec4(0.0);");
+
+ fragmentGenerator.Append("\tvec4 res = vec4(0.0);");
+ fragmentGenerator.Append("\tfloat p0 = base.a * blend.a;");
+ fragmentGenerator.Append("\tfloat p1 = base.a * (1.0 - blend.a);");
+ fragmentGenerator.Append("\tfloat p2 = blend.a * (1.0 - base.a);");
+ fragmentGenerator.Append("\tres.a = p0 + p1 + p2;");
+
+ NVRenderShaderProgram *theShader;
+ fragmentGenerator.Append(
+ "\tfloat f_rs_rd = (base.r < 0.5? (2.0 * base.r * blend.r) : "
+ "(1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r)));");
+ fragmentGenerator.Append(
+ "\tfloat f_gs_gd = (base.g < 0.5? (2.0 * base.g * blend.g) : "
+ "(1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g)));");
+ fragmentGenerator.Append(
+ "\tfloat f_bs_bd = (base.b < 0.5? (2.0 * base.b * blend.b) : "
+ "(1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b)));");
+ fragmentGenerator.Append("\tres.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;");
+ fragmentGenerator.Append("\tres.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;");
+ fragmentGenerator.Append("\tres.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;");
+ fragmentGenerator.Append("\tgl_FragColor = vec4(res.rgb * res.a, res.a);");
+ fragmentGenerator.Append("}");
+ theShader = GetProgramGenerator().CompileGeneratedShader(
+ "advanced overlay shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+
+ NVScopedRefCounted<SAdvancedModeBlendShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SAdvancedModeBlendShader)(*theShader);
+ m_AdvancedModeOverlayBlendShader = retval;
+ return m_AdvancedModeOverlayBlendShader.getValue();
+ }
+
+ SAdvancedModeBlendShader *Qt3DSRendererImpl::GetColorBurnBlendModeShader()
+ {
+ if (m_AdvancedModeColorBurnBlendShader.hasValue())
+ return m_AdvancedModeColorBurnBlendShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("base_layer", "sampler2D");
+ fragmentGenerator.AddUniform("blend_layer", "sampler2D");
+
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec4 base = texture2D(base_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (base.a != 0.0) base.rgb /= base.a;");
+ fragmentGenerator.Append("\telse base = vec4(0.0);");
+ fragmentGenerator.Append("\tvec4 blend = texture2D(blend_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (blend.a != 0.0) blend.rgb /= blend.a;");
+ fragmentGenerator.Append("\telse blend = vec4(0.0);");
+
+ fragmentGenerator.Append("\tvec4 res = vec4(0.0);");
+ fragmentGenerator.Append("\tfloat p0 = base.a * blend.a;");
+ fragmentGenerator.Append("\tfloat p1 = base.a * (1.0 - blend.a);");
+ fragmentGenerator.Append("\tfloat p2 = blend.a * (1.0 - base.a);");
+ fragmentGenerator.Append("\tres.a = p0 + p1 + p2;");
+
+ NVRenderShaderProgram *theShader;
+ fragmentGenerator.Append(
+ "\tfloat f_rs_rd = ((base.r == 1.0) ? 1.0 : "
+ "(blend.r == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.r) / blend.r)));");
+ fragmentGenerator.Append(
+ "\tfloat f_gs_gd = ((base.g == 1.0) ? 1.0 : "
+ "(blend.g == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.g) / blend.g)));");
+ fragmentGenerator.Append(
+ "\tfloat f_bs_bd = ((base.b == 1.0) ? 1.0 : "
+ "(blend.b == 0.0) ? 0.0 : 1.0 - min(1.0, ((1.0 - base.b) / blend.b)));");
+ fragmentGenerator.Append("\tres.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;");
+ fragmentGenerator.Append("\tres.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;");
+ fragmentGenerator.Append("\tres.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;");
+ fragmentGenerator.Append("\tgl_FragColor = vec4(res.rgb * res.a, res.a);");
+ fragmentGenerator.Append("}");
+
+ theShader = GetProgramGenerator().CompileGeneratedShader(
+ "advanced colorBurn shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SAdvancedModeBlendShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SAdvancedModeBlendShader)(*theShader);
+ m_AdvancedModeColorBurnBlendShader = retval;
+ return m_AdvancedModeColorBurnBlendShader.getValue();
+
+ }
+
+ SAdvancedModeBlendShader *Qt3DSRendererImpl::GetColorDodgeBlendModeShader()
+ {
+ if (m_AdvancedModeColorDodgeBlendShader.hasValue())
+ return m_AdvancedModeColorDodgeBlendShader.getValue();
+
+ GetProgramGenerator().BeginProgram();
+
+ IShaderStageGenerator &vertexGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Vertex));
+ IShaderStageGenerator &fragmentGenerator(
+ *GetProgramGenerator().GetStage(ShaderGeneratorStages::Fragment));
+ vertexGenerator.AddIncoming("attr_pos", "vec3");
+ vertexGenerator.AddIncoming("attr_uv", "vec2");
+ vertexGenerator.AddOutgoing("uv_coords", "vec2");
+ vertexGenerator.Append("void main() {");
+ vertexGenerator.Append("\tgl_Position = vec4(attr_pos, 1.0 );");
+ vertexGenerator.Append("\tuv_coords = attr_uv;");
+ vertexGenerator.Append("}");
+
+ fragmentGenerator.AddUniform("base_layer", "sampler2D");
+ fragmentGenerator.AddUniform("blend_layer", "sampler2D");
+
+ fragmentGenerator.Append("void main() {");
+ fragmentGenerator.Append("\tvec4 base = texture2D(base_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (base.a != 0.0) base.rgb /= base.a;");
+ fragmentGenerator.Append("\telse base = vec4(0.0);");
+ fragmentGenerator.Append("\tvec4 blend = texture2D(blend_layer, uv_coords);");
+ fragmentGenerator.Append("\tif (blend.a != 0.0) blend.rgb /= blend.a;");
+ fragmentGenerator.Append("\telse blend = vec4(0.0);");
+
+ fragmentGenerator.Append("\tvec4 res = vec4(0.0);");
+ fragmentGenerator.Append("\tfloat p0 = base.a * blend.a;");
+ fragmentGenerator.Append("\tfloat p1 = base.a * (1.0 - blend.a);");
+ fragmentGenerator.Append("\tfloat p2 = blend.a * (1.0 - base.a);");
+ fragmentGenerator.Append("\tres.a = p0 + p1 + p2;");
+
+ NVRenderShaderProgram *theShader;
+ fragmentGenerator.Append(
+ "\tfloat f_rs_rd = ((base.r == 0.0) ? 0.0 : "
+ "(blend.r == 1.0) ? 1.0 : min(base.r / (1.0 - blend.r), 1.0));");
+ fragmentGenerator.Append(
+ "\tfloat f_gs_gd = ((base.g == 0.0) ? 0.0 : "
+ "(blend.g == 1.0) ? 1.0 : min(base.g / (1.0 - blend.g), 1.0));");
+ fragmentGenerator.Append(
+ "\tfloat f_bs_bd = ((base.b == 0.0) ? 0.0 : "
+ "(blend.b == 1.0) ? 1.0 : min(base.b / (1.0 - blend.b), 1.0));");
+ fragmentGenerator.Append("\tres.r = f_rs_rd * p0 + base.r * p1 + blend.r * p2;");
+ fragmentGenerator.Append("\tres.g = f_gs_gd * p0 + base.g * p1 + blend.g * p2;");
+ fragmentGenerator.Append("\tres.b = f_bs_bd * p0 + base.b * p1 + blend.b * p2;");
+
+ fragmentGenerator.Append("\tgl_FragColor = vec4(res.rgb * res.a, res.a);");
+ fragmentGenerator.Append("}");
+ theShader = GetProgramGenerator().CompileGeneratedShader(
+ "advanced colorDodge shader", SShaderCacheProgramFlags(), TShaderFeatureSet());
+ NVScopedRefCounted<SAdvancedModeBlendShader> retval;
+ if (theShader)
+ retval = QT3DS_NEW(m_Context->GetAllocator(), SAdvancedModeBlendShader)(*theShader);
+ m_AdvancedModeColorDodgeBlendShader = retval;
+ return m_AdvancedModeColorDodgeBlendShader.getValue();
+
+ }
+#endif
+}
+}
diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h
new file mode 100644
index 0000000..1ac85db
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplShaders.h
@@ -0,0 +1,452 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_RENDERER_IMPL_SHADERS_H
+#define QT3DS_RENDERER_IMPL_SHADERS_H
+#include "Qt3DSRender.h"
+#include "render/Qt3DSRenderShaderProgram.h"
+#include "render/Qt3DSRenderProgramPipeline.h"
+
+namespace qt3ds {
+namespace render {
+ using qt3ds::render::NVRenderCachedShaderProperty;
+ using qt3ds::render::NVRenderCachedShaderBuffer;
+
+ /**
+ * Cached tessellation property lookups this is on a per mesh base
+ */
+ struct SShaderTessellationProperties
+ {
+ NVRenderCachedShaderProperty<QT3DSF32> m_EdgeTessLevel; ///< tesselation value for the edges
+ NVRenderCachedShaderProperty<QT3DSF32> m_InsideTessLevel; ///< tesselation value for the inside
+ NVRenderCachedShaderProperty<QT3DSF32>
+ m_PhongBlend; ///< blending between linear and phong component
+ NVRenderCachedShaderProperty<QT3DSVec2>
+ m_DistanceRange; ///< distance range for min and max tess level
+ NVRenderCachedShaderProperty<QT3DSF32> m_DisableCulling; ///< if set to 1.0 this disables
+ ///backface culling optimization in
+ ///the tess shader
+
+ SShaderTessellationProperties() {}
+ SShaderTessellationProperties(NVRenderShaderProgram &inShader)
+ : m_EdgeTessLevel("tessLevelOuter", inShader)
+ , m_InsideTessLevel("tessLevelInner", inShader)
+ , m_PhongBlend("phongBlend", inShader)
+ , m_DistanceRange("distanceRange", inShader)
+ , m_DisableCulling("disableCulling", inShader)
+ {
+ }
+ };
+
+ /**
+ * The results of generating a shader. Caches all possible variable names into
+ * typesafe objects.
+ */
+ struct SShaderGeneratorGeneratedShader
+ {
+ QT3DSU32 m_LayerSetIndex;
+ CRegisteredString m_QueryString;
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_ViewportMatrix;
+ SShaderTessellationProperties m_Tessellation;
+
+ SShaderGeneratorGeneratedShader(CRegisteredString inQueryString,
+ NVRenderShaderProgram &inShader)
+ : m_LayerSetIndex(QT3DS_MAX_U32)
+ , m_QueryString(inQueryString)
+ , m_Shader(inShader)
+ , m_ViewportMatrix("viewport_matrix", inShader)
+ , m_Tessellation(inShader)
+ {
+ m_Shader.addRef();
+ }
+ ~SShaderGeneratorGeneratedShader() { m_Shader.release(); }
+ static QT3DSU32 GetLayerIndex(const SShaderGeneratorGeneratedShader &inShader)
+ {
+ return inShader.m_LayerSetIndex;
+ }
+ static void SetLayerIndex(SShaderGeneratorGeneratedShader &inShader, QT3DSU32 idx)
+ {
+ inShader.m_LayerSetIndex = idx;
+ }
+ };
+
+ struct SDefaultMaterialRenderableDepthShader
+ {
+ NVAllocatorCallback &m_Allocator;
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+
+ QT3DSI32 m_RefCount;
+ SDefaultMaterialRenderableDepthShader(NVRenderShaderProgram &inShader,
+ NVRenderContext &inContext)
+ : m_Allocator(inContext.GetAllocator())
+ , m_Shader(inShader)
+ , m_MVP("model_view_projection", inShader)
+ , m_RefCount(0)
+ {
+ m_Shader.addRef();
+ }
+
+ ~SDefaultMaterialRenderableDepthShader() { m_Shader.release(); }
+
+ void addRef() { ++m_RefCount; }
+ void release()
+ {
+ --m_RefCount;
+ if (m_RefCount <= 0)
+ NVDelete(m_Allocator, this);
+ }
+ };
+
+ /**
+ * Cached texture property lookups, used one per texture so a shader generator for N
+ * textures will have an array of N of these lookup objects.
+ */
+ struct SShaderTextureProperties
+ {
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_Sampler;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_Offsets;
+ NVRenderCachedShaderProperty<QT3DSVec4> m_Rotations;
+ SShaderTextureProperties(const char *sampName, const char *offName, const char *rotName,
+ NVRenderShaderProgram &inShader)
+ : m_Sampler(sampName, inShader)
+ , m_Offsets(offName, inShader)
+ , m_Rotations(rotName, inShader)
+ {
+ }
+ SShaderTextureProperties() {}
+ };
+
+ struct SRenderableDepthPrepassShader
+ {
+ NVAllocatorCallback &m_Allocator;
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_GlobalTransform;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_Projection;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_CameraPosition;
+ NVRenderCachedShaderProperty<QT3DSF32> m_DisplaceAmount;
+ SShaderTextureProperties m_DisplacementProps;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraProperties;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_CameraDirection;
+ // NVRenderCachedShaderProperty<QT3DSMat44> m_ShadowMV[6];
+
+ QT3DSI32 m_RefCount;
+ // Cache the tessellation property name lookups
+ SShaderTessellationProperties m_Tessellation;
+
+ SRenderableDepthPrepassShader(NVRenderShaderProgram &inShader, NVRenderContext &inContext)
+ : m_Allocator(inContext.GetAllocator())
+ , m_Shader(inShader)
+ , m_MVP("model_view_projection", inShader)
+ , m_GlobalTransform("model_matrix", inShader)
+ , m_Projection("projection", inShader)
+ , m_CameraPosition("camera_position", inShader)
+ , m_DisplaceAmount("displaceAmount", inShader)
+ , m_DisplacementProps("displacementSampler", "displacementMap_offset",
+ "displacementMap_rot", inShader)
+ , m_CameraProperties("camera_properties", inShader)
+ , m_CameraDirection("camera_direction", inShader)
+ , m_RefCount(0)
+ , m_Tessellation(inShader)
+ {
+ /*
+ m_ShadowMV[0].m_Shader = &inShader;
+ m_ShadowMV[0].m_Constant = inShader.GetShaderConstant( "shadow_mv0" );
+ m_ShadowMV[1].m_Shader = &inShader;
+ m_ShadowMV[1].m_Constant = inShader.GetShaderConstant( "shadow_mv1" );
+ m_ShadowMV[2].m_Shader = &inShader;
+ m_ShadowMV[2].m_Constant = inShader.GetShaderConstant( "shadow_mv2" );
+ m_ShadowMV[3].m_Shader = &inShader;
+ m_ShadowMV[3].m_Constant = inShader.GetShaderConstant( "shadow_mv3" );
+ m_ShadowMV[4].m_Shader = &inShader;
+ m_ShadowMV[4].m_Constant = inShader.GetShaderConstant( "shadow_mv4" );
+ m_ShadowMV[5].m_Shader = &inShader;
+ m_ShadowMV[5].m_Constant = inShader.GetShaderConstant( "shadow_mv5" );
+ */
+ m_Shader.addRef();
+ }
+
+ ~SRenderableDepthPrepassShader() { m_Shader.release(); }
+
+ void addRef() { ++m_RefCount; }
+ void release()
+ {
+ --m_RefCount;
+ if (m_RefCount <= 0)
+ NVDelete(m_Allocator, this);
+ }
+ };
+
+ struct SDefaultAoPassShader
+ {
+ NVAllocatorCallback &m_Allocator;
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_ViewMatrix;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraProperties;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_CameraDirection;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_DepthTexture;
+ NVRenderCachedShaderProperty<NVRenderTextureCube *> m_CubeTexture;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_DepthSamplerSize;
+
+ NVRenderCachedShaderBuffer<qt3ds::render::NVRenderShaderConstantBuffer *> m_AoShadowParams;
+ QT3DSI32 m_RefCount;
+
+ SDefaultAoPassShader(NVRenderShaderProgram &inShader, NVRenderContext &inContext)
+ : m_Allocator(inContext.GetAllocator())
+ , m_Shader(inShader)
+ , m_ViewMatrix("view_matrix", inShader)
+ , m_CameraProperties("camera_properties", inShader)
+ , m_CameraDirection("camera_direction", inShader)
+ , m_DepthTexture("depth_sampler", inShader)
+ , m_CubeTexture("depth_cube", inShader)
+ , m_DepthSamplerSize("depth_sampler_size", inShader)
+ , m_AoShadowParams("cbAoShadow", inShader)
+ , m_RefCount(0)
+ {
+ m_Shader.addRef();
+ }
+ ~SDefaultAoPassShader() { m_Shader.release(); }
+
+ void addRef() { ++m_RefCount; }
+ void release()
+ {
+ --m_RefCount;
+ if (m_RefCount <= 0)
+ NVDelete(m_Allocator, this);
+ }
+ };
+
+ struct STextShader
+ {
+ NVRenderShaderProgram &m_Shader;
+
+ NVScopedRefCounted<NVRenderProgramPipeline> m_ProgramPipeline;
+
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+ // Dimensions and offsetting of the image.
+ NVRenderCachedShaderProperty<QT3DSVec4> m_Dimensions;
+ // The fourth member of text color is the opacity
+ NVRenderCachedShaderProperty<QT3DSVec4> m_TextColor;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_BackgroundColor;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_Sampler;
+ // Dimensions and offsetting of the texture
+ NVRenderCachedShaderProperty<QT3DSVec3> m_TextDimensions;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraProperties;
+ // Used only for onscreen text
+ NVRenderCachedShaderProperty<QT3DSVec2> m_VertexOffsets;
+
+ STextShader(NVRenderShaderProgram &shader, NVRenderProgramPipeline *pipeline = NULL)
+ : m_Shader(shader)
+ , m_ProgramPipeline(pipeline)
+ , m_MVP("model_view_projection", shader)
+ , m_Dimensions("text_dimensions", shader)
+ , m_TextColor("text_textcolor", shader)
+ , m_BackgroundColor("text_backgroundcolor", shader)
+ , m_Sampler("text_image", shader)
+ , m_TextDimensions("text_textdimensions", shader)
+ , m_CameraProperties("camera_properties", shader)
+ , m_VertexOffsets("vertex_offsets", shader)
+ {
+ if (!pipeline)
+ m_Shader.addRef();
+ }
+ ~STextShader()
+ {
+ if (!m_ProgramPipeline.mPtr)
+ m_Shader.release();
+ }
+ void Render(NVRenderTexture2D &inTexture, const STextScaleAndOffset &inScaleAndOffset,
+ const QT3DSVec4 &inTextColor, const QT3DSMat44 &inMVP, const QT3DSVec2 &inCameraVec,
+ NVRenderContext &inRenderContext,
+ NVRenderInputAssembler &inInputAssemblerBuffer, QT3DSU32 count,
+ const STextTextureDetails &inTextTextureDetails,
+ const QT3DSVec3 &inBackgroundColor);
+
+ void RenderPath(NVRenderPathFontItem &inPathFontItem,
+ NVRenderPathFontSpecification &inPathFontSpec,
+ const STextScaleAndOffset &inScaleAndOffset, const QT3DSVec4 &inTextColor,
+ const QT3DSMat44 &inViewProjection, const QT3DSMat44 &inModel,
+ const QT3DSVec2 &inCameraVec, NVRenderContext &inRenderContext,
+ const STextTextureDetails &inTextTextureDetails,
+ const QT3DSVec3 &inBackgroundColor);
+
+ void Render2D(NVRenderTexture2D &inTexture, const QT3DSVec4 &inTextColor, const QT3DSMat44 &inMVP,
+ NVRenderContext &inRenderContext,
+ NVRenderInputAssembler &inInputAssemblerBuffer, QT3DSU32 count,
+ QT3DSVec2 inVertexOffsets);
+ };
+
+ struct STextDepthShader
+ {
+ NVAllocatorCallback &m_Allocator;
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+ // Dimensions and offsetting of the image.
+ NVRenderCachedShaderProperty<QT3DSVec4> m_Dimensions;
+ NVRenderCachedShaderProperty<QT3DSVec3> m_TextDimensions;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraProperties;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_Sampler;
+ NVRenderInputAssembler &m_QuadInputAssembler;
+ QT3DSI32 m_RefCount;
+
+ STextDepthShader(NVAllocatorCallback &alloc, NVRenderShaderProgram &prog,
+ NVRenderInputAssembler &assembler)
+ : m_Allocator(alloc)
+ , m_Shader(prog)
+ , m_MVP("model_view_projection", prog)
+ , m_Dimensions("text_dimensions", prog)
+ , m_TextDimensions("text_textdimensions", prog)
+ , m_CameraProperties("camera_properties", prog)
+ , m_Sampler("text_image", prog)
+ , m_QuadInputAssembler(assembler)
+ , m_RefCount(0)
+ {
+ m_Shader.addRef();
+ }
+ ~STextDepthShader() { m_Shader.release(); }
+ void addRef() { ++m_RefCount; }
+ void release()
+ {
+ --m_RefCount;
+ if (m_RefCount <= 0)
+ NVDelete(m_Allocator, this);
+ }
+ };
+
+ struct SLayerProgAABlendShader
+ {
+ NVScopedRefCounted<NVRenderShaderProgram> m_Shader;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_AccumSampler;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_LastFrame;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_BlendFactors;
+ volatile QT3DSI32 mRefCount;
+ SLayerProgAABlendShader(NVRenderShaderProgram &inShader)
+ : m_Shader(inShader)
+ , m_AccumSampler("accumulator", inShader)
+ , m_LastFrame("last_frame", inShader)
+ , m_BlendFactors("blend_factors", inShader)
+ , mRefCount(0)
+ {
+ }
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader->GetRenderContext().GetAllocator())
+ };
+
+ struct SLayerSceneShader
+ {
+ NVRenderShaderProgram &m_Shader;
+
+ NVRenderCachedShaderProperty<QT3DSMat44> m_MVP;
+ // Dimensions and offsetting of the image.
+ NVRenderCachedShaderProperty<QT3DSVec2> m_Dimensions;
+ // The fourth member of text color is the opacity
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_Sampler;
+
+ volatile QT3DSI32 mRefCount;
+
+ SLayerSceneShader(NVRenderShaderProgram &inShader)
+ : m_Shader(inShader)
+ , m_MVP("model_view_projection", inShader)
+ , m_Dimensions("layer_dimensions", inShader)
+ , m_Sampler("layer_image", inShader)
+ , mRefCount(0)
+ {
+ m_Shader.addRef();
+ }
+ ~SLayerSceneShader() { m_Shader.release(); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader.GetRenderContext().GetAllocator())
+ };
+
+ struct SShadowmapPreblurShader
+ {
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<QT3DSVec2> m_CameraProperties;
+ NVRenderCachedShaderProperty<NVRenderTextureCube *> m_DepthCube;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_DepthMap;
+
+ volatile QT3DSI32 mRefCount;
+
+ SShadowmapPreblurShader(NVRenderShaderProgram &inShader)
+ : m_Shader(inShader)
+ , m_CameraProperties("camera_properties", inShader)
+ , m_DepthCube("depthCube", inShader)
+ , m_DepthMap("depthSrc", inShader)
+ , mRefCount(0)
+ {
+ m_Shader.addRef();
+ }
+ ~SShadowmapPreblurShader() { m_Shader.release(); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader.GetRenderContext().GetAllocator())
+ };
+
+#ifdef ADVANCED_BLEND_SW_FALLBACK
+ struct SAdvancedModeBlendShader
+ {
+ NVRenderShaderProgram &m_Shader;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_baseLayer;
+ NVRenderCachedShaderProperty<NVRenderTexture2D *> m_blendLayer;
+
+ volatile QT3DSI32 mRefCount;
+
+ SAdvancedModeBlendShader(NVRenderShaderProgram &inShader)
+ : m_Shader(inShader)
+ , m_baseLayer("base_layer", inShader)
+ , m_blendLayer("blend_layer", inShader)
+ , mRefCount(0)
+ {
+ m_Shader.addRef();
+ }
+ ~SAdvancedModeBlendShader() { m_Shader.release(); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Shader.GetRenderContext().GetAllocator())
+
+ };
+#endif
+
+ struct SGGSGet
+ {
+ QT3DSU32 operator()(const SShaderGeneratorGeneratedShader &inShader)
+ {
+ return inShader.m_LayerSetIndex;
+ }
+ };
+ struct SGGSSet
+ {
+ void operator()(SShaderGeneratorGeneratedShader &inShader, QT3DSU32 idx)
+ {
+ inShader.m_LayerSetIndex = idx;
+ }
+ };
+}
+}
+#endif
diff --git a/src/runtimerender/rendererimpl/Qt3DSVertexPipelineImpl.h b/src/runtimerender/rendererimpl/Qt3DSVertexPipelineImpl.h
new file mode 100644
index 0000000..a9b5e7b
--- /dev/null
+++ b/src/runtimerender/rendererimpl/Qt3DSVertexPipelineImpl.h
@@ -0,0 +1,463 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#pragma once
+#ifndef QT3DS_VERTEX_PIPELINE_IMPL_H
+#define QT3DS_VERTEX_PIPELINE_IMPL_H
+#include "Qt3DSRenderDefaultMaterialShaderGenerator.h"
+
+namespace qt3ds {
+namespace render {
+ // Baseclass for the vertex pipelines to be sure we have consistent implementations.
+ struct SVertexPipelineImpl : public IDefaultMaterialVertexPipeline
+ {
+ struct GenerationFlagValues
+ {
+ enum Enum {
+ UVCoords = 1,
+ EnvMapReflection = 1 << 1,
+ ViewVector = 1 << 2,
+ WorldNormal = 1 << 3,
+ ObjectNormal = 1 << 4,
+ WorldPosition = 1 << 5,
+ TangentBinormal = 1 << 6,
+ UVCoords1 = 1 << 7,
+ VertexColor = 1 << 8,
+ };
+ };
+
+ typedef TStrTableStrMap::const_iterator TParamIter;
+ typedef NVFlags<GenerationFlagValues::Enum> TGenerationFlags;
+
+ IMaterialShaderGenerator &m_MaterialGenerator;
+ IShaderProgramGenerator &m_ProgramGenerator;
+ IStringTable &m_StringTable;
+ Qt3DSString m_TempString;
+
+ TGenerationFlags m_GenerationFlags;
+ bool m_Wireframe;
+ TStrTableStrMap m_InterpolationParameters;
+ QT3DSU32 m_DisplacementIdx;
+ SRenderableImage *m_DisplacementImage;
+ QStringList m_addedFunctions;
+
+ SVertexPipelineImpl(NVAllocatorCallback &inAllocator, IMaterialShaderGenerator &inMaterial,
+ IShaderProgramGenerator &inProgram, IStringTable &inStringTable,
+ bool inWireframe // only works if tessellation is true
+ )
+
+ : m_MaterialGenerator(inMaterial)
+ , m_ProgramGenerator(inProgram)
+ , m_StringTable(inStringTable)
+ , m_Wireframe(inWireframe)
+ , m_InterpolationParameters(inAllocator, "m_InterpolationParameters")
+ , m_DisplacementIdx(0)
+ , m_DisplacementImage(NULL)
+ {
+ }
+
+ // Trues true if the code was *not* set.
+ bool SetCode(GenerationFlagValues::Enum inCode)
+ {
+ if (((QT3DSU32)m_GenerationFlags & inCode) != 0)
+ return true;
+ m_GenerationFlags |= inCode;
+ return false;
+ }
+ bool HasCode(GenerationFlagValues::Enum inCode)
+ {
+ return ((QT3DSU32)(m_GenerationFlags & inCode)) != 0;
+ }
+ IShaderProgramGenerator &ProgramGenerator() { return m_ProgramGenerator; }
+ IShaderStageGenerator &Vertex()
+ {
+ return *ProgramGenerator().GetStage(ShaderGeneratorStages::Vertex);
+ }
+ IShaderStageGenerator &TessControl()
+ {
+ return *ProgramGenerator().GetStage(ShaderGeneratorStages::TessControl);
+ }
+ IShaderStageGenerator &TessEval()
+ {
+ return *ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval);
+ }
+ IShaderStageGenerator &Geometry()
+ {
+ return *ProgramGenerator().GetStage(ShaderGeneratorStages::Geometry);
+ }
+ IShaderStageGenerator &Fragment()
+ {
+ return *ProgramGenerator().GetStage(ShaderGeneratorStages::Fragment);
+ }
+ IMaterialShaderGenerator &MaterialGenerator() { return m_MaterialGenerator; }
+
+ void SetupDisplacement(QT3DSU32 displacementImageIdx, SRenderableImage *displacementImage)
+ {
+ m_DisplacementIdx = displacementImageIdx;
+ m_DisplacementImage = displacementImage;
+ }
+
+ CRegisteredString Str(const char8_t *inItem) { return m_StringTable.RegisterStr(inItem); }
+
+ bool HasTessellation() const
+ {
+ return m_ProgramGenerator.GetEnabledStages() & ShaderGeneratorStages::TessEval;
+ }
+ bool HasGeometryStage() const
+ {
+ return m_ProgramGenerator.GetEnabledStages() & ShaderGeneratorStages::Geometry;
+ }
+ bool HasDisplacment() const { return m_DisplacementImage != NULL; }
+
+ void InitializeWireframeGeometryShader()
+ {
+ if (m_Wireframe && ProgramGenerator().GetStage(ShaderGeneratorStages::Geometry)
+ && ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval)) {
+ IShaderStageGenerator &geometryShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::Geometry));
+ // currently geometry shader is only used for drawing wireframe
+ if (m_Wireframe) {
+ geometryShader.AddUniform("viewport_matrix", "mat4");
+ geometryShader.AddOutgoing("varEdgeDistance", "vec3");
+ geometryShader.Append("layout (triangles) in;");
+ geometryShader.Append("layout (triangle_strip, max_vertices = 3) out;");
+ geometryShader.Append("void main() {");
+
+ // how this all work see
+ // http://developer.download.nvidia.com/SDK/10.5/direct3d/Source/SolidWireframe/Doc/SolidWireframe.pdf
+
+ geometryShader.Append(
+ "// project points to screen space\n"
+ "\tvec3 p0 = vec3(viewport_matrix * (gl_in[0].gl_Position / "
+ "gl_in[0].gl_Position.w));\n"
+ "\tvec3 p1 = vec3(viewport_matrix * (gl_in[1].gl_Position / "
+ "gl_in[1].gl_Position.w));\n"
+ "\tvec3 p2 = vec3(viewport_matrix * (gl_in[2].gl_Position / "
+ "gl_in[2].gl_Position.w));\n"
+ "// compute triangle heights\n"
+ "\tfloat e1 = length(p1 - p2);\n"
+ "\tfloat e2 = length(p2 - p0);\n"
+ "\tfloat e3 = length(p1 - p0);\n"
+ "\tfloat alpha = acos( (e2*e2 + e3*e3 - e1*e1) / (2.0*e2*e3) );\n"
+ "\tfloat beta = acos( (e1*e1 + e3*e3 - e2*e2) / (2.0*e1*e3) );\n"
+ "\tfloat ha = abs( e3 * sin( beta ) );\n"
+ "\tfloat hb = abs( e3 * sin( alpha ) );\n"
+ "\tfloat hc = abs( e2 * sin( alpha ) );\n");
+ }
+ }
+ }
+
+ void FinalizeWireframeGeometryShader()
+ {
+ IShaderStageGenerator &geometryShader(
+ *ProgramGenerator().GetStage(ShaderGeneratorStages::Geometry));
+
+ if (m_Wireframe == true && ProgramGenerator().GetStage(ShaderGeneratorStages::Geometry)
+ && ProgramGenerator().GetStage(ShaderGeneratorStages::TessEval)) {
+ const char8_t *theExtension("TE[");
+ // we always assume triangles
+ for (int i = 0; i < 3; i++) {
+ char buf[10];
+ sprintf(buf, "%d", i);
+ for (TStrTableStrMap::const_iterator iter = m_InterpolationParameters.begin(),
+ end = m_InterpolationParameters.end();
+ iter != end; ++iter) {
+ geometryShader << "\t" << iter->first.c_str() << " = "
+ << iter->first.c_str() << theExtension << buf << "];\n";
+ }
+
+ geometryShader << "\tgl_Position = gl_in[" << buf << "].gl_Position;\n";
+ // the triangle distance is interpolated through the shader stage
+ if (i == 0)
+ geometryShader << "\n\tvarEdgeDistance = vec3(ha*"
+ << "gl_in[" << buf << "].gl_Position.w, 0.0, 0.0);\n";
+ else if (i == 1)
+ geometryShader << "\n\tvarEdgeDistance = vec3(0.0, hb*"
+ << "gl_in[" << buf << "].gl_Position.w, 0.0);\n";
+ else if (i == 2)
+ geometryShader << "\n\tvarEdgeDistance = vec3(0.0, 0.0, hc*"
+ << "gl_in[" << buf << "].gl_Position.w);\n";
+
+ // submit vertex
+ geometryShader << "\tEmitVertex();\n";
+ }
+ // end primitive
+ geometryShader << "\tEndPrimitive();\n";
+ }
+ }
+
+ virtual void SetupTessIncludes(ShaderGeneratorStages::Enum inStage,
+ TessModeValues::Enum inTessMode)
+ {
+ IShaderStageGenerator &tessShader(*ProgramGenerator().GetStage(inStage));
+
+ // depending on the selected tessellation mode chose program
+ switch (inTessMode) {
+ case TessModeValues::TessPhong:
+ tessShader.AddInclude("tessellationPhong.glsllib");
+ break;
+ case TessModeValues::TessNPatch:
+ tessShader.AddInclude("tessellationNPatch.glsllib");
+ break;
+ default:
+ QT3DS_ASSERT(false); // fallthrough intentional
+ case TessModeValues::TessLinear:
+ tessShader.AddInclude("tessellationLinear.glsllib");
+ break;
+ }
+ }
+
+ void GenerateUVCoords(QT3DSU32 inUVSet = 0) override
+ {
+ if (inUVSet == 0 && SetCode(GenerationFlagValues::UVCoords))
+ return;
+ if (inUVSet == 1 && SetCode(GenerationFlagValues::UVCoords1))
+ return;
+
+ QT3DS_ASSERT(inUVSet == 0 || inUVSet == 1);
+
+ if (inUVSet == 0)
+ AddInterpolationParameter("varTexCoord0", "vec2");
+ else if (inUVSet == 1)
+ AddInterpolationParameter("varTexCoord1", "vec2");
+
+ DoGenerateUVCoords(inUVSet);
+ }
+ void GenerateEnvMapReflection() override
+ {
+ if (SetCode(GenerationFlagValues::EnvMapReflection))
+ return;
+
+ GenerateWorldPosition();
+ GenerateWorldNormal();
+ IShaderStageGenerator &activeGenerator(ActiveStage());
+ activeGenerator.AddInclude("viewProperties.glsllib");
+ AddInterpolationParameter("var_object_to_camera", "vec3");
+ activeGenerator.Append("\tvar_object_to_camera = normalize( local_model_world_position "
+ "- camera_position );");
+ // World normal cannot be relied upon in the vertex shader because of bump maps.
+ Fragment().Append("\tvec3 environment_map_reflection = reflect( "
+ "normalize(var_object_to_camera), world_normal.xyz );");
+ Fragment().Append("\tenvironment_map_reflection *= vec3( 0.5, 0.5, 0 );");
+ Fragment().Append("\tenvironment_map_reflection += vec3( 0.5, 0.5, 1.0 );");
+ }
+ void GenerateViewVector() override
+ {
+ if (SetCode(GenerationFlagValues::ViewVector))
+ return;
+ GenerateWorldPosition();
+ IShaderStageGenerator &activeGenerator(ActiveStage());
+ activeGenerator.AddInclude("viewProperties.glsllib");
+ AddInterpolationParameter("varViewVector", "vec3");
+ activeGenerator.Append("\tvec3 local_view_vector = normalize(camera_position - "
+ "local_model_world_position);");
+ AssignOutput("varViewVector", "local_view_vector");
+ Fragment() << "\tvec3 view_vector = normalize(varViewVector);" << Endl;
+ }
+
+ // fragment shader expects varying vertex normal
+ // lighting in vertex pipeline expects world_normal
+ void GenerateWorldNormal() override
+ {
+ if (SetCode(GenerationFlagValues::WorldNormal))
+ return;
+ AddInterpolationParameter("varNormal", "vec3");
+ DoGenerateWorldNormal();
+ Fragment().Append("\tvec3 world_normal = normalize( varNormal );");
+ }
+ void GenerateObjectNormal() override
+ {
+ if (SetCode(GenerationFlagValues::ObjectNormal))
+ return;
+ DoGenerateObjectNormal();
+ Fragment().Append("\tvec3 object_normal = normalize(varObjectNormal);");
+ }
+ void GenerateWorldPosition() override
+ {
+ if (SetCode(GenerationFlagValues::WorldPosition))
+ return;
+
+ ActiveStage().AddUniform("model_matrix", "mat4");
+ AddInterpolationParameter("varWorldPos", "vec3");
+ DoGenerateWorldPosition();
+
+ AssignOutput("varWorldPos", "local_model_world_position");
+ }
+ void GenerateVarTangentAndBinormal() override
+ {
+ if (SetCode(GenerationFlagValues::TangentBinormal))
+ return;
+ AddInterpolationParameter("varTangent", "vec3");
+ AddInterpolationParameter("varBinormal", "vec3");
+ DoGenerateVarTangentAndBinormal();
+ Fragment() << "\tvec3 tangent = normalize(varTangent);" << Endl
+ << "\tvec3 binormal = normalize(varBinormal);" << Endl;
+ }
+ void GenerateVertexColor() override
+ {
+ if (SetCode(GenerationFlagValues::VertexColor))
+ return;
+ AddInterpolationParameter("varColor", "vec3");
+ DoGenerateVertexColor();
+ Fragment().Append("\tvec3 vertColor = varColor;");
+ }
+
+ bool HasActiveWireframe() override { return m_Wireframe; }
+
+ // IShaderStageGenerator interface
+ void AddIncoming(const char8_t *name, const char8_t *type) override
+ {
+ ActiveStage().AddIncoming(name, type);
+ }
+ void AddIncoming(const TStrType &name, const char8_t *type) override
+ {
+ AddIncoming(name.c_str(), type);
+ }
+ void AddIncoming(const QString &name, const char8_t *type) override
+ {
+ AddIncoming(name.toUtf8().constData(), type);
+ }
+
+ void AddOutgoing(const char8_t *name, const char8_t *type) override
+ {
+ AddInterpolationParameter(name, type);
+ }
+ void AddOutgoing(const TStrType &name, const char8_t *type) override
+ {
+ AddOutgoing(name.c_str(), type);
+ }
+ void AddOutgoing(const QString &name, const char8_t *type) override
+ {
+ AddOutgoing(name.toUtf8().constData(), type);
+ }
+ void AddUniform(const QString &name, const char8_t *type) override
+ {
+ AddUniform(name.toUtf8().constData(), type);
+ }
+
+ void AddUniform(const char8_t *name, const char8_t *type) override
+ {
+ ActiveStage().AddUniform(name, type);
+ }
+ void AddUniform(const TStrType &name, const char8_t *type) override
+ {
+ AddUniform(name.c_str(), type);
+ }
+
+ void AddInclude(const char8_t *name) override { ActiveStage().AddInclude(name); }
+ void AddInclude(const TStrType &name) override { AddInclude(name.c_str()); }
+ void AddInclude(const QString &name) override
+ {
+ QByteArray arr = name.toLatin1();
+ AddInclude(arr.data());
+ }
+
+ void AddFunction(const QString &functionName) override
+ {
+ if (!m_addedFunctions.contains(functionName)) {
+ m_addedFunctions.push_back(functionName);
+ QString includeName;
+ QTextStream stream(&includeName);
+ stream << "func" << functionName << ".glsllib";
+ AddInclude(includeName);
+ }
+ }
+
+ void AddConstantBuffer(const char *name, const char *layout) override
+ {
+ ActiveStage().AddConstantBuffer(name, layout);
+ }
+ void AddConstantBuffer(const QString &name, const char *layout) override
+ {
+ AddConstantBuffer(name.toUtf8().constData(), layout);
+ }
+
+ void AddConstantBufferParam(const char *cbName, const char *paramName,
+ const char *type) override
+ {
+ ActiveStage().AddConstantBufferParam(cbName, paramName, type);
+ }
+ void AddConstantBufferParam(const QString &cbName, const QString &paramName,
+ const char *type) override
+ {
+ AddConstantBufferParam(cbName.toUtf8().constData(),
+ paramName.toUtf8().constData(), type);
+ }
+
+ IShaderStageGenerator &operator<<(const char *data) override
+ {
+ ActiveStage() << data;
+ return *this;
+ }
+ IShaderStageGenerator &operator<<(const TStrType &data) override
+ {
+ ActiveStage() << data;
+ return *this;
+ }
+ IShaderStageGenerator &operator<<(const QString &data) override
+ {
+ ActiveStage() << data;
+ return *this;
+ }
+ IShaderStageGenerator &operator<<(const SEndlType &data) override
+ {
+ ActiveStage() << data;
+ return *this;
+ }
+ void Append(const char *data) override { ActiveStage().Append(data); }
+ void AppendPartial(const char *data) override { ActiveStage().Append(data); }
+
+ ShaderGeneratorStages::Enum Stage() const override
+ {
+ return const_cast<SVertexPipelineImpl *>(this)->ActiveStage().Stage();
+ }
+
+ void BeginVertexGeneration(QT3DSU32 displacementImageIdx,
+ SRenderableImage *displacementImage) override = 0;
+ void AssignOutput(const char8_t *inVarName, const char8_t *inVarValueExpr) override = 0;
+ void EndVertexGeneration(bool customShader) override = 0;
+
+ void BeginFragmentGeneration() override = 0;
+ void EndFragmentGeneration(bool customShader) override = 0;
+
+ virtual IShaderStageGenerator &ActiveStage() = 0;
+ virtual void AddInterpolationParameter(const char8_t *inParamName,
+ const char8_t *inParamType) = 0;
+
+ virtual void DoGenerateUVCoords(QT3DSU32 inUVSet) = 0;
+ virtual void DoGenerateWorldNormal() = 0;
+ virtual void DoGenerateObjectNormal() = 0;
+ virtual void DoGenerateWorldPosition() = 0;
+ virtual void DoGenerateVarTangentAndBinormal() = 0;
+ virtual void DoGenerateVertexColor() = 0;
+ };
+}
+}
+
+#endif