diff options
Diffstat (limited to 'src/runtimerender/Qt3DSRenderWidgets.cpp')
-rw-r--r-- | src/runtimerender/Qt3DSRenderWidgets.cpp | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/src/runtimerender/Qt3DSRenderWidgets.cpp b/src/runtimerender/Qt3DSRenderWidgets.cpp new file mode 100644 index 0000000..311b218 --- /dev/null +++ b/src/runtimerender/Qt3DSRenderWidgets.cpp @@ -0,0 +1,319 @@ +/**************************************************************************** +** +** 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 "Qt3DSRenderWidgets.h" +#include "Qt3DSRenderNode.h" +#include "render/Qt3DSRenderContext.h" +#include "Qt3DSRenderShaderCodeGeneratorV2.h" +#include "render/Qt3DSRenderShaderProgram.h" + +using namespace qt3ds::render; + +namespace { + +struct SWidgetBBox : public IRenderWidget +{ + NVBounds3 m_Bounds; + QT3DSVec3 m_Color; + NVRenderVertexBuffer *m_BoxVertexBuffer; + NVRenderIndexBuffer *m_BoxIndexBuffer; + NVRenderInputAssembler *m_BoxInputAssembler; + NVRenderShaderProgram *m_BoxShader; + CRegisteredString m_ItemName; + SWidgetBBox(SNode &inNode, const NVBounds3 &inBounds, const QT3DSVec3 &inColor) + : IRenderWidget(inNode) + , m_Bounds(inBounds) + , m_Color(inColor) + , m_BoxVertexBuffer(NULL) + , m_BoxIndexBuffer(NULL) + , m_BoxInputAssembler(NULL) + , m_BoxShader(NULL) + { + } + + void SetupBoxShader(IRenderWidgetContext &inContext) + { + m_BoxShader = inContext.GetShader(m_ItemName); + if (!m_BoxShader) { + qt3ds::render::IShaderProgramGenerator &theGenerator(inContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + qt3ds::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(qt3ds::render::ShaderGeneratorStages::Vertex)); + qt3ds::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(qt3ds::render::ShaderGeneratorStages::Fragment)); + + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator.Append( + "\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);"); + theVertexGenerator.Append("}"); + theFragmentGenerator.AddUniform("output_color", "vec3"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor.rgb = output_color;"); + theFragmentGenerator.Append("\tgl_FragColor.a = 1.0;"); + theFragmentGenerator.Append("}"); + m_BoxShader = inContext.CompileAndStoreShader(m_ItemName); + } + } + + void SetupBoundingBoxGraphicsObjects(IRenderWidgetContext &inContext, + NVDataRef<QT3DSVec3> thePoints) + { + qt3ds::render::NVRenderVertexBufferEntry theEntry( + "attr_pos", qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3); + m_BoxVertexBuffer = &inContext.GetOrCreateVertexBuffer( + m_ItemName, 3 * sizeof(QT3DSF32), toU8DataRef(thePoints.begin(), thePoints.size())); + m_BoxIndexBuffer = inContext.GetIndexBuffer(m_ItemName); + if (!m_BoxIndexBuffer) { + // The way the bounds lays out the bounds for the box + // capitalization indicates whether this was a max or min value. + enum _Indexes { + xyz = 0, + Xyz, + xYz, + xyZ, + XYZ, + xYZ, + XyZ, + XYz, + }; + QT3DSU8 indexes[] = { + // The toBoxBounds function lays out points such that + // xyz, Xyz, xYz, xyZ, XYZ, xYZ, XyZ, XYz + // Min corner + xyz, Xyz, xyz, xYz, xyz, xyZ, + + // Max corner + XYZ, xYZ, XYZ, XyZ, XYZ, XYz, + + // Now connect the rest of the dots. + // the rules are that only one letter can change + // else you are connecting *across* the box somehow. + + Xyz, XYz, Xyz, XyZ, + + xYz, XYz, xYz, xYZ, + + xyZ, XyZ, xyZ, xYZ, + }; + m_BoxIndexBuffer = &inContext.GetOrCreateIndexBuffer( + m_ItemName, qt3ds::render::NVRenderComponentTypes::QT3DSU8, sizeof(indexes), + toU8DataRef(indexes, sizeof(indexes))); + } + + m_BoxInputAssembler = inContext.GetInputAssembler(m_ItemName); + if (!m_BoxInputAssembler && m_BoxIndexBuffer && m_BoxVertexBuffer) { + // create our attribute layout + NVRenderAttribLayout *theAttribLAyout = + &inContext.CreateAttributeLayout(toConstDataRef(&theEntry, 1)); + + QT3DSU32 strides = m_BoxVertexBuffer->GetStride(); + QT3DSU32 offsets = 0; + m_BoxInputAssembler = &inContext.GetOrCreateInputAssembler( + m_ItemName, theAttribLAyout, toConstDataRef(&m_BoxVertexBuffer, 1), + m_BoxIndexBuffer, toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1)); + } + SetupBoxShader(inContext); + } + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + m_ItemName = inRenderContext.GetStringTable().RegisterStr("SWidgetBBox"); + SWidgetRenderInformation theInfo(inWidgetContext.GetWidgetRenderInformation( + *m_Node, m_Node->m_Position, RenderWidgetModes::Local)); + TNVBounds2BoxPoints thePoints; + m_Bounds.expand(thePoints); + QT3DSMat44 theNodeRotation; + QT3DSMat44 theNodeToCamera = theInfo.m_NodeParentToCamera * m_Node->m_LocalTransform; + for (QT3DSU32 idx = 0; idx < 8; ++idx) + thePoints[idx] = theNodeToCamera.transform(thePoints[idx]); + SetupBoundingBoxGraphicsObjects(inWidgetContext, toDataRef(thePoints, 8)); + if (m_BoxShader && m_BoxInputAssembler) { + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthWriteEnabled(true); + inRenderContext.SetDepthTestEnabled(true); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_BoxShader); + m_BoxShader->SetPropertyValue("model_view_projection", theInfo.m_LayerProjection); + m_BoxShader->SetPropertyValue("output_color", m_Color); + inRenderContext.SetInputAssembler(m_BoxInputAssembler); + inRenderContext.Draw(qt3ds::render::NVRenderDrawMode::Lines, + m_BoxInputAssembler->GetIndexCount(), 0); + } + } +}; + +struct SWidgetAxis : public IRenderWidget +{ + NVRenderVertexBuffer *m_AxisVertexBuffer; + NVRenderInputAssembler *m_AxisInputAssembler; + NVRenderShaderProgram *m_AxisShader; + CRegisteredString m_ItemName; + + SWidgetAxis(SNode &inNode) + : IRenderWidget(inNode) + , m_AxisVertexBuffer(NULL) + , m_AxisInputAssembler(NULL) + , m_AxisShader(NULL) + { + } + + void SetupAxisShader(IRenderWidgetContext &inContext) + { + m_AxisShader = inContext.GetShader(m_ItemName); + if (!m_AxisShader) { + qt3ds::render::IShaderProgramGenerator &theGenerator(inContext.GetProgramGenerator()); + theGenerator.BeginProgram(); + qt3ds::render::IShaderStageGenerator &theVertexGenerator( + *theGenerator.GetStage(qt3ds::render::ShaderGeneratorStages::Vertex)); + qt3ds::render::IShaderStageGenerator &theFragmentGenerator( + *theGenerator.GetStage(qt3ds::render::ShaderGeneratorStages::Fragment)); + theVertexGenerator.AddIncoming("attr_pos", "vec3"); + theVertexGenerator.AddIncoming("attr_color", "vec3"); + theVertexGenerator.AddOutgoing("output_color", "vec3"); + theVertexGenerator.AddUniform("model_view_projection", "mat4"); + theVertexGenerator.Append("void main() {"); + theVertexGenerator.Append( + "\tgl_Position = model_view_projection * vec4(attr_pos, 1.0);"); + theVertexGenerator.Append("\toutput_color = attr_color;"); + theVertexGenerator.Append("}"); + theFragmentGenerator.Append("void main() {"); + theFragmentGenerator.Append("\tgl_FragColor.rgb = output_color;"); + theFragmentGenerator.Append("\tgl_FragColor.a = 1.0;"); + theFragmentGenerator.Append("}"); + m_AxisShader = inContext.CompileAndStoreShader(m_ItemName); + } + } + + void SetupAxesGraphicsObjects(IRenderWidgetContext &inContext, NVDataRef<QT3DSVec3> theAxes) + { + qt3ds::render::NVRenderVertexBufferEntry theEntries[] = { + qt3ds::render::NVRenderVertexBufferEntry("attr_pos", + qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3), + qt3ds::render::NVRenderVertexBufferEntry("attr_color", + qt3ds::render::NVRenderComponentTypes::QT3DSF32, 3, 12), + }; + + m_AxisVertexBuffer = &inContext.GetOrCreateVertexBuffer( + m_ItemName, 6 * sizeof(QT3DSF32), toU8DataRef(theAxes.begin(), theAxes.size())); + m_AxisInputAssembler = inContext.GetInputAssembler(m_ItemName); + if (!m_AxisInputAssembler && m_AxisVertexBuffer) { + // create our attribute layout + NVRenderAttribLayout *theAttribLAyout = + &inContext.CreateAttributeLayout(toConstDataRef(theEntries, 2)); + + QT3DSU32 strides = m_AxisVertexBuffer->GetStride(); + QT3DSU32 offsets = 0; + m_AxisInputAssembler = &inContext.GetOrCreateInputAssembler( + m_ItemName, theAttribLAyout, toConstDataRef(&m_AxisVertexBuffer, 1), nullptr, + toConstDataRef(&strides, 1), toConstDataRef(&offsets, 1)); + } + } + + inline QT3DSVec3 TransformDirection(const QT3DSMat33 &inMatrix, const QT3DSVec3 &inDir) + { + QT3DSVec3 retval = inMatrix.transform(inDir); + return retval; + } + + void Render(IRenderWidgetContext &inWidgetContext, NVRenderContext &inRenderContext) override + { + m_ItemName = inRenderContext.GetStringTable().RegisterStr("SWidgetAxis"); + + SetupAxisShader(inWidgetContext); + + if (m_AxisShader) { + static const QT3DSVec3 pivotCol = QT3DSVec3(0, 0, 1); + if (m_Node->m_Parent && m_Node->m_Parent->m_Type != GraphObjectTypes::Layer) { + m_Node->m_Parent->CalculateGlobalVariables(); + } + QT3DSVec3 thePivot(m_Node->m_Pivot); + if (m_Node->m_Flags.IsLeftHanded()) + thePivot.z *= -1; + + SWidgetRenderInformation theInfo(inWidgetContext.GetWidgetRenderInformation( + *m_Node, QT3DSVec3(0, 0, 0), RenderWidgetModes::Local)); + + QT3DSMat44 theNodeRotation; + m_Node->CalculateRotationMatrix(theNodeRotation); + if (m_Node->m_Flags.IsLeftHanded()) + SNode::FlipCoordinateSystem(theNodeRotation); + + QT3DSMat33 theRotationMatrix(theNodeRotation.column0.getXYZ(), + theNodeRotation.column1.getXYZ(), + theNodeRotation.column2.getXYZ()); + + // Move the camera position into camera space. This is so that when we render we don't + // have to account + // for scaling done in the camera's MVP. + QT3DSVec3 theItemPosition = theInfo.m_Position; + + QT3DSMat33 theAxisTransform = theInfo.m_NormalMatrix * theRotationMatrix; + + // Scale the effective pivot line end point according to node scale + // so that pivot line always hits object center. + thePivot = thePivot.multiply(m_Node->m_Scale); + QT3DSVec3 pivotVec = TransformDirection( + theAxisTransform, QT3DSVec3(-thePivot.x, -thePivot.y, -thePivot.z)); + + QT3DSVec3 thePivotLine[] = { + theItemPosition, pivotCol, theItemPosition + pivotVec, pivotCol + }; + + SetupAxesGraphicsObjects(inWidgetContext, toDataRef(thePivotLine, 4)); + + if (m_AxisInputAssembler) { + inRenderContext.SetBlendingEnabled(false); + inRenderContext.SetDepthWriteEnabled(false); + inRenderContext.SetDepthTestEnabled(false); + inRenderContext.SetCullingEnabled(false); + inRenderContext.SetActiveShader(m_AxisShader); + m_AxisShader->SetPropertyValue("model_view_projection", theInfo.m_LayerProjection); + inRenderContext.SetInputAssembler(m_AxisInputAssembler); + // Draw line from pivot to object center. + inRenderContext.Draw(qt3ds::render::NVRenderDrawMode::Lines, 2, 0); + } + } + } +}; +} + +IRenderWidget &IRenderWidget::CreateBoundingBoxWidget(SNode &inNode, const NVBounds3 &inBounds, + const QT3DSVec3 &inColor, + NVAllocatorCallback &inAlloc) +{ + return *QT3DS_NEW(inAlloc, SWidgetBBox)(inNode, inBounds, inColor); +} + +IRenderWidget &IRenderWidget::CreateAxisWidget(SNode &inNode, NVAllocatorCallback &inAlloc) +{ + return *QT3DS_NEW(inAlloc, SWidgetAxis)(inNode); +} |