diff options
Diffstat (limited to 'src/Authoring/Qt3DStudio/Render/StudioRendererTranslation.cpp')
-rw-r--r-- | src/Authoring/Qt3DStudio/Render/StudioRendererTranslation.cpp | 4083 |
1 files changed, 4083 insertions, 0 deletions
diff --git a/src/Authoring/Qt3DStudio/Render/StudioRendererTranslation.cpp b/src/Authoring/Qt3DStudio/Render/StudioRendererTranslation.cpp new file mode 100644 index 00000000..82678986 --- /dev/null +++ b/src/Authoring/Qt3DStudio/Render/StudioRendererTranslation.cpp @@ -0,0 +1,4083 @@ +/**************************************************************************** +** +** Copyright (C) 2006 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-EXCEPT$ +** 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 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** 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 "Qt3DSCommonPrecompile.h" +#include "StudioRendererImpl.h" +#include "StudioRendererTranslation.h" +#include "Qt3DSRenderEffectSystem.h" +#include "foundation/StrConvertUTF.h" +#include "Qt3DSFileTools.h" +#include "Qt3DSRenderUIPLoader.h" +#include "Qt3DSRenderWidgets.h" +#include "foundation/Qt3DSBounds3.h" +#include "Qt3DSRenderResourceManager.h" +#include "render/Qt3DSRenderFrameBuffer.h" +#include "Qt3DSRenderCamera.h" +#include "foundation/Qt3DSPlane.h" +#include "Qt3DSRenderRotationHelper.h" +#include "Qt3DSRenderPluginGraphObject.h" +#include "Qt3DSRenderPlugin.h" +#include "StudioCoreSystem.h" +#include "Qt3DSDMDataCore.h" +#include "Qt3DSRenderPluginPropertyValue.h" +#include "Qt3DSRenderEffectSystem.h" +#include "render/Qt3DSRenderShaderProgram.h" +#include "Qt3DSRenderMaterialHelpers.h" +#include "Qt3DSRenderDynamicObjectSystem.h" +#include "Qt3DSRenderCustomMaterialSystem.h" +#include "Qt3DSRenderReferencedMaterial.h" +#include "Qt3DSRenderPixelGraphicsTypes.h" +#include "Qt3DSRenderPixelGraphicsRenderer.h" +#include "Qt3DSRenderPathManager.h" + +#include "PathWidget.h" +#include "Qt3DSRenderLightmaps.h" +#include "StudioPreferences.h" +#include "HotKeys.h" +#include "Qt3DSRenderCamera.h" +#include "Qt3DSRenderLight.h" + +#pragma warning(disable : 4100) // unreferenced formal parameter + +using namespace qt3ds::studio; +QT3DSU32 qt3ds::studio::g_GraphObjectTranslatorTag; +using qt3ds::render::SPGGraphObject; +using qt3ds::render::SPGRect; +using qt3ds::render::SPGVertLine; +using qt3ds::render::SPGHorzLine; +using qt3ds::render::NVRenderRectF; +using qt3ds::render::NVRenderRect; + +namespace { +using namespace qt3dsdm; + +struct STranslatorDataModelParser +{ + STranslation &m_Context; + Qt3DSDMInstanceHandle m_InstanceHandle; + STranslatorDataModelParser(STranslation &inContext, Qt3DSDMInstanceHandle inInstance) + : m_Context(inContext) + , m_InstanceHandle(inInstance) + { + } + Qt3DSDMInstanceHandle GetInstanceHandle() { return m_InstanceHandle; } + + template <typename TDataType> + inline Option<TDataType> GetPropertyValue(qt3dsdm::Qt3DSDMPropertyHandle inProperty) + { + Option<SValue> theValue = + m_Context.m_Reader.GetRawInstancePropertyValue(GetInstanceHandle(), inProperty); + if (theValue.hasValue()) + return qt3dsdm::get<TDataType>(*theValue); + return Empty(); + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + Option<float> theValue = GetPropertyValue<float>(inProperty); + if (theValue.hasValue()) { + outValue = theValue.getValue(); + return true; + } + return false; + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSU32 &outValue) + { + auto theValue = GetPropertyValue<qt3ds::QT3DSI32>(inProperty); + if (theValue.hasValue()) { + outValue = qMax(theValue.getValue(), 0); + return true; + } + return false; + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSI32 &outValue) + { + auto theValue = GetPropertyValue<qt3ds::QT3DSI32>(inProperty); + if (theValue.hasValue()) { + outValue = *theValue; + return true; + } + return false; + } + + bool ParseRadianProperty(Qt3DSDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + TORAD(outValue); + return true; + } + return false; + } + bool ParseRadianProperty(Qt3DSDMPropertyHandle inProperty, QT3DSVec3 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + TORAD(outValue.x); + TORAD(outValue.y); + TORAD(outValue.z); + return true; + } + return false; + } + bool ParseOpacityProperty(Qt3DSDMPropertyHandle inProperty, QT3DSF32 &outValue) + { + if (ParseProperty(inProperty, outValue)) { + outValue = (1.0f / 100.0f) * outValue; + return true; + } + return false; + } + bool ParseRotationOrder(Qt3DSDMPropertyHandle inProperty, QT3DSU32 &outValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + outValue = qt3ds::render::MapRotationOrder(temp); + return true; + } + return false; + } + bool ParseOrientation(Qt3DSDMPropertyHandle inProperty, qt3ds::render::NodeFlags &outValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + bool isLeftHanded = strcmp(temp.c_str(), "Left Handed") == 0; + outValue.SetLeftHanded(isLeftHanded); + return true; + } + return false; + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, bool &outValue) + { + Option<bool> theValue = GetPropertyValue<bool>(inProperty); + if (theValue.hasValue()) { + outValue = theValue.getValue(); + return true; + } + return false; + } + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSVec2 &outValue) + { + Option<qt3dsdm::SFloat2> theValue = GetPropertyValue<qt3dsdm::SFloat2>(inProperty); + if (theValue.hasValue()) { + outValue = QT3DSVec2(theValue->m_Floats[0], theValue->m_Floats[1]); + return true; + } + return false; + } + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSVec3 &outValue) + { + Option<SFloat3> theValue = GetPropertyValue<SFloat3>(inProperty); + if (theValue.hasValue()) { + outValue = QT3DSVec3(theValue->m_Floats[0], theValue->m_Floats[1], theValue->m_Floats[2]); + return true; + } + return false; + } + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, QT3DSVec4 &outValue) + { + Option<SFloat4> theValue = GetPropertyValue<SFloat4>(inProperty); + if (theValue.hasValue()) { + outValue = QT3DSVec4(theValue->m_Floats[0], theValue->m_Floats[1], + theValue->m_Floats[2], theValue->m_Floats[3]); + return true; + } + return false; + } + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, qt3ds::render::CRegisteredString &outValue) + { + Option<qt3dsdm::TDataStrPtr> theValue = GetPropertyValue<qt3dsdm::TDataStrPtr>(inProperty); + if (theValue.hasValue() && *theValue) { + qt3ds::render::IStringTable &theStrTable(m_Context.m_Context.GetStringTable()); + outValue = theStrTable.RegisterStr((*theValue)->GetData()); + return true; + } + return false; + } + + bool ParseAndResolveSourcePath(qt3dsdm::Qt3DSDMPropertyHandle inProperty, + qt3ds::render::CRegisteredString &outValue) + { + if (ParseProperty(inProperty, outValue)) { + if (outValue.IsValid() && outValue.c_str()[0] != '#') { + Q3DStudio::CFilePath theDirectory = m_Context.m_Doc.GetDocumentDirectory(); + Q3DStudio::CFilePath theResolvedPath = + Q3DStudio::CFilePath::CombineBaseAndRelative(theDirectory, outValue.c_str()); + if (theResolvedPath.exists()) { + outValue = m_Context.m_Context.GetStringTable() + .RegisterStr(theResolvedPath.toCString()); + } + } + return true; + } + return false; + } + + template <typename TEnumType> + bool ParseEnumProperty(qt3dsdm::Qt3DSDMPropertyHandle inProperty, TEnumType &ioValue) + { + qt3ds::render::CRegisteredString temp; + if (ParseProperty(inProperty, temp)) { + qt3ds::render::SEnumNameMap *theNameMap(qt3ds::render::SEnumParseMap<TEnumType>::GetMap()); + for (qt3ds::render::SEnumNameMap *theIter = theNameMap; + theIter->m_Name && *theIter->m_Name; ++theIter) { + // hack to match advanced overlay types, whose name start with a '*' + const char8_t *p = temp; + if (*p == '*') + ++p; + if (strcmp(p, theIter->m_Name) == 0) { + ioValue = (TEnumType)theIter->m_Enum; + return true; + } + } + } + return false; + } + + bool ParseNodeFlagsProperty(qt3dsdm::Qt3DSDMPropertyHandle inProperty, + qt3ds::render::NodeFlags &outValue, + qt3ds::render::NodeFlagValues::Enum theFlag) + { + bool temp = false; + if (ParseProperty(inProperty, temp)) { + outValue.ClearOrSet(temp, theFlag); + return true; + } + return false; + } + bool ParseNodeFlagsInverseProperty(qt3dsdm::Qt3DSDMPropertyHandle inProperty, + qt3ds::render::NodeFlags &outValue, + qt3ds::render::NodeFlagValues::Enum theFlag) + { + bool temp = false; + if (ParseProperty(inProperty, temp)) { + outValue.ClearOrSet(!temp, theFlag); + return true; + } + return false; + } + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, qt3ds::render::SImage *&ioImage) + { + Option<SLong4> theData = GetPropertyValue<SLong4>(inProperty); + if (theData.hasValue()) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForGuid(*theData)); + SGraphObjectTranslator *imageTranslator = m_Context.GetOrCreateTranslator(theInstance); + if (imageTranslator + && imageTranslator->GetGraphObject().m_Type + == qt3ds::render::GraphObjectTypes::Image) { + SImage *theNewImage = static_cast<SImage *>(&imageTranslator->GetGraphObject()); + ioImage = theNewImage; + } else + ioImage = nullptr; + return true; + } + return false; + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, qt3ds::render::SGraphObject *&ioObjRef) + { + Option<SObjectRefType> theData = GetPropertyValue<SObjectRefType>(inProperty); + if (theData.hasValue()) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForObjectRef(m_InstanceHandle, *theData)); + SGraphObjectTranslator *theItemTranslator = + m_Context.GetOrCreateTranslator(theInstance); + if (theItemTranslator) + ioObjRef = &theItemTranslator->GetGraphObject(); + } + return true; + } + + bool ParseProperty(Qt3DSDMPropertyHandle inProperty, qt3ds::render::SNode *&ioNodePtr) + { + Option<SObjectRefType> theData = GetPropertyValue<SObjectRefType>(inProperty); + SNode *theNewNodePtr = nullptr; + if (theData.hasValue()) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance( + m_Context.m_Reader.GetInstanceForObjectRef(m_InstanceHandle, *theData)); + SGraphObjectTranslator *theItemTranslator = + m_Context.GetOrCreateTranslator(theInstance); + if (theItemTranslator) { + SGraphObject &theObject = theItemTranslator->GetGraphObject(); + if (GraphObjectTypes::IsNodeType(theObject.m_Type)) + theNewNodePtr = &static_cast<SNode &>(theObject); + } + } + ioNodePtr = theNewNodePtr; + return true; + } +}; + +// Define parse tables +#define Scene_ClearColor m_Scene.m_BackgroundColor +#define Scene_UseClearColor m_Scene.m_BgColorEnable +#define Node_Rotation m_Node.m_Rotation +#define Node_Position m_Node.m_Position +#define Node_Scale m_Node.m_Scale +#define Node_Pivot m_Node.m_Pivot +#define Node_LocalOpacity m_Node.m_Opacity +#define Node_RotationOrder m_Node.m_RotationOrder +#define Node_LeftHanded m_Node.m_Orientation +#define Layer_TemporalAAEnabled m_Layer.m_TemporalAA +#define Layer_LayerEnableDepthTest m_Layer.m_DisableDepthTest +#define Layer_LayerEnableDepthPrePass m_Layer.m_DisableDepthPrepass +#define Layer_ClearColor m_Layer.m_BackgroundColor +#define Layer_Background m_Layer.m_Background +#define Layer_BlendType m_Layer.m_BlendType +#define Layer_Size m_Layer.m_Size +#define Layer_Location m_Layer.m_Location +#define Layer_ProgressiveAAMode m_Layer.m_ProgressiveAA +#define Layer_MultisampleAAMode m_Layer.m_MultisampleAA +#define Layer_HorizontalFieldValues m_Layer.m_HorizontalFieldValues +#define Layer_Left m_Layer.m_Left +#define Layer_LeftUnits m_Layer.m_LeftUnits +#define Layer_Width m_Layer.m_Width +#define Layer_WidthUnits m_Layer.m_WidthUnits +#define Layer_Right m_Layer.m_Right +#define Layer_RightUnits m_Layer.m_RightUnits +#define Layer_VerticalFieldValues m_Layer.m_VerticalFieldValues +#define Layer_Top m_Layer.m_Top +#define Layer_TopUnits m_Layer.m_TopUnits +#define Layer_Height m_Layer.m_Height +#define Layer_HeightUnits m_Layer.m_HeightUnits +#define Layer_Bottom m_Layer.m_Bottom +#define Layer_BottomUnits m_Layer.m_BottomUnits +#define Layer_AoStrength m_Layer.m_AoStrength +#define Layer_AoDistance m_Layer.m_AoDistance +#define Layer_AoSoftness m_Layer.m_AoSoftness +#define Layer_AoBias m_Layer.m_AoBias +#define Layer_AoSamplerate m_Layer.m_AoSamplerate +#define Layer_AoDither m_Layer.m_AoDither +#define Layer_ShadowStrength m_Layer.m_ShadowStrength +#define Layer_ShadowDist m_Layer.m_ShadowDist +#define Layer_ShadowSoftness m_Layer.m_ShadowSoftness +#define Layer_ShadowBias m_Layer.m_ShadowBias +#define Layer_LightProbe m_Layer.m_LightProbe +#define Layer_ProbeBright m_Layer.m_ProbeBright +#define Layer_FastIbl m_Layer.m_FastIbl +#define Layer_ProbeHorizon m_Layer.m_ProbeHorizon +#define Layer_ProbeFov m_Layer.m_ProbeFov +#define Layer_LightProbe2 m_Layer.m_LightProbe2 +#define Layer_Probe2Fade m_Layer.m_Probe2Fade +#define Layer_Probe2Window m_Layer.m_Probe2Window +#define Layer_Probe2Pos m_Layer.m_Probe2Pos +#define Layer_TexturePath m_Asset.m_SourcePath +#define Camera_ClipNear m_Camera.m_ClipNear +#define Camera_ClipFar m_Camera.m_ClipFar +#define Camera_FOV m_Camera.m_Fov +#define Camera_FOVHorizontal m_Camera.m_FovHorizontal +#define Camera_Orthographic m_Camera.m_Orthographic +#define Camera_ScaleMode m_Camera.m_ScaleMode +#define Camera_ScaleAnchor m_Camera.m_ScaleAnchor +#define Light_LightType m_Light.m_LightType +#define Light_Scope m_Light.m_Scope +#define Light_DiffuseColor m_Light.m_LightColor +#define Light_SpecularColor m_Light.m_SpecularColor +#define Light_AmbientColor m_Light.m_AmbientColor +#define Light_Brightness m_Light.m_Brightness +#define Light_LinearFade m_Light.m_LinearFade +#define Light_ExponentialFade m_Light.m_ExpFade +#define Light_AreaWidth m_Light.m_AreaWidth +#define Light_AreaHeight m_Light.m_AreaHeight +#define Light_CastShadow m_Light.m_CastShadow +#define Light_ShadowBias m_Light.m_ShadowBias +#define Light_ShadowFactor m_Light.m_ShadowFactor +#define Light_ShadowMapRes m_Light.m_ShadowMapRes +#define Light_ShadowMapFar m_Light.m_ShadowMapFar +#define Light_ShadowMapFov m_Light.m_ShadowMapFov +#define Light_ShadowFilter m_Light.m_ShadowFilter +#define Model_MeshPath m_Asset.m_SourcePath +#define Model_ShadowCaster m_Model.m_ShadowCaster +#define Model_TessellationMode m_Model.m_Tessellation +#define Model_EdgeTess m_Model.m_EdgeTess +#define Model_InnerTess m_Model.m_InnerTess +#define Lightmaps_LightmapIndirect m_Lightmaps.m_LightmapIndirect +#define Lightmaps_LightmapRadiosity m_Lightmaps.m_LightmapRadiosity +#define Lightmaps_LightmapShadow m_Lightmaps.m_LightmapShadow +#define MaterialBase_IblProbe m_MaterialBase.m_IblProbe +#define Material_Lighting m_Material.m_ShaderLighting +#define Material_BlendMode m_Material.m_BlendMode +#define Material_DiffuseColor m_Material.m_DiffuseColor +#define Material_DiffuseMaps_0 m_Material.m_DiffuseMap1 +#define Material_DiffuseMaps_1 m_Material.m_DiffuseMap2 +#define Material_DiffuseMaps_2 m_Material.m_DiffuseMap3 +#define Material_EmissivePower m_Material.m_EmissivePower +#define Material_EmissiveColor m_Material.m_EmissiveColor +#define Material_EmissiveMap m_Material.m_EmissiveMap +#define Material_EmissiveMap2 m_Material.m_EmissiveMap2 +#define Material_SpecularReflection m_Material.m_SpecularReflection +#define Material_SpecularMap m_Material.m_SpecularMap +#define Material_SpecularModel m_Material.m_SpecularModel +#define Material_SpecularTint m_Material.m_SpecularTint +#define Material_IOR m_Material.m_IOR +#define Material_FresnelPower m_Material.m_FresnelPower +#define Material_SpecularAmount m_Material.m_SpecularAmount +#define Material_SpecularRoughness m_Material.m_SpecularRoughness +#define Material_RoughnessMap m_Material.m_RoughnessMap +#define Material_Opacity m_Material.m_Opacity +#define Material_OpacityMap m_Material.m_OpacityMap +#define Material_BumpMap m_Material.m_BumpMap +#define Material_BumpAmount m_Material.m_BumpAmount +#define Material_NormalMap m_Material.m_NormalMap +#define Material_DisplacementMap m_Material.m_DisplacementMap +#define Material_DisplaceAmount m_Material.m_DisplaceAmount +#define Material_TranslucencyMap m_Material.m_TranslucencyMap +#define Material_TranslucentFalloff m_Material.m_TranslucentFalloff +#define Material_DiffuseLightWrap m_Material.m_DiffuseLightWrap +#define Material_ReferencedMaterial m_ReferencedMaterial.m_ReferencedMaterial +#define Material_VertexColors m_Material.m_VertexColors +#define Image_ImagePath m_Asset.m_SourcePath +#define Image_OffscreenRendererId m_Image.m_SubPresentation +#define Image_Scale_X m_Image.m_RepeatU +#define Image_Scale_Y m_Image.m_RepeatV +#define Image_Pivot_X m_Image.m_PivotU +#define Image_Pivot_Y m_Image.m_PivotV +#define Image_Rotation m_Image.m_RotationUV +#define Image_Position_X m_Image.m_PositionU +#define Image_Position_Y m_Image.m_PositionV +#define Image_MappingMode m_Image.m_TextureMapping +#define Image_HorizontalTilingMode m_Image.m_TilingU +#define Image_VerticalTilingMode m_Image.m_TilingV +#define Text_Text m_Text.m_TextString +#define Text_Font m_Text.m_Font +#define Text_FontSize m_Text.m_Size +#define Text_HorizontalAlignment m_Text.m_HorzAlign +#define Text_VerticalAlignment m_Text.m_VertAlign +#define Text_Leading m_Text.m_Leading +#define Text_Tracking m_Text.m_Tracking +#define Text_DropShadow m_Text.m_DropShadow +#define Text_DropShadowStrength m_Text.m_DropShadowStrength +#define Text_DropShadowOffsetX m_Text.m_DropShadowOffsetX +#define Text_DropShadowOffsetY m_Text.m_DropShadowOffsetY +#define Text_WordWrap m_Text.m_WordWrap +#define Text_BoundingBox m_Text.m_BoundingBox +#define Text_Elide m_Text.m_Elide +#define Text_TextColor m_Text.m_TextColor +#define Text_EnableAcceleratedFont m_Text.m_EnableAcceleratedFont +#define Path_Width m_Path.m_Width +#define Path_LinearError m_Path.m_LinearError +#define Path_InnerTessAmount m_Path.m_InnerTessAmount +#define Path_EdgeTessAmount m_Path.m_EdgeTessAmount +#define Path_Opacity m_Path.m_Opacity +#define Path_BeginCapping m_Path.m_BeginCap +#define Path_BeginCapOffset m_Path.m_BeginCapOffset +#define Path_BeginCapOpacity m_Path.m_BeginCapOpacity +#define Path_BeginCapWidth m_Path.m_BeginCapWidth +#define Path_EndCapping m_Path.m_EndCap +#define Path_EndCapOffset m_Path.m_EndCapOffset +#define Path_EndCapOpacity m_Path.m_EndCapOpacity +#define Path_EndCapWidth m_Path.m_EndCapWidth +#define Path_PathType m_Path.m_PathType +#define Path_PaintStyle m_Path.m_PaintStyle +#define Path_PathBuffer m_Asset.m_SourcePath +#define SubPath_Closed m_SubPath.m_Closed + +// Fill in implementations for the actual parse tables. +#define HANDLE_QT3DS_RENDER_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_VEC3_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_REAL_VEC2_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_COLOR_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_RADIAN_PROPERTY(type, name, dirty) \ + theParser.ParseRadianProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_VEC3_RADIAN_PROPERTY(type, name, dirty) \ + theParser.ParseRadianProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_OPACITY_PROPERTY(type, name, dirty) \ + theParser.ParseOpacityProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_ROTATION_ORDER_PROPERTY(type, name, dirty) \ + theParser.ParseRotationOrder(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_NODE_ORIENTATION_PROPERTY(type, name, dirty) \ + theParser.ParseOrientation(inContext.m_ObjectDefinitions.type##_##name, theItem.m_Flags); +#define HANDLE_QT3DS_RENDER_DEPTH_TEST_PROPERTY(type, name, dirty) \ + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name)) \ + theItem.m_##name = !theItem.m_##name; +#define HANDLE_QT3DS_NODE_FLAGS_PROPERTY(type, name, dirty) \ + theParser.ParseNodeFlagsProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_Flags, \ + qt3ds::render::NodeFlagValues::name); +#define HANDLE_QT3DS_NODE_FLAGS_INVERSE_PROPERTY(type, name, dirty) \ + theParser.ParseNodeFlagsInverseProperty(inContext.m_ObjectDefinitions.type##_##name, \ + theItem.m_Flags, qt3ds::render::NodeFlagValues::name); +#define HANDLE_QT3DS_RENDER_ENUM_PROPERTY(type, name, dirty) \ + theParser.ParseEnumProperty(inContext.m_ObjectDefinitions.type##_##name, theItem.m_##name); +#define HANDLE_QT3DS_RENDER_SOURCEPATH_PROPERTY(type, name, dirty) \ + theParser.ParseAndResolveSourcePath(inContext.m_ObjectDefinitions.type##_##name, \ + theItem.m_##name); +#define HANDLE_QT3DS_RENDER_ARRAY_PROPERTY(type, name, index, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##index, \ + theItem.m_##name[index]); +#define HANDLE_QT3DS_RENDER_VEC2_PROPERTY(type, name, dirty) \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##X, \ + theItem.m_##name.x); \ + theParser.ParseProperty(inContext.m_ObjectDefinitions.type##_##name##_##Y, theItem.m_##name.y); +#define HANDLE_QT3DS_RENDER_COLOR_VEC3_PROPERTY( \ + type, name, dirty) // noop by intention already handled by HANDLE_QT3DS_RENDER_COLOR_PROPERTY +#define HANDLE_QT3DS_RENDER_TRANSFORM_VEC3_PROPERTY( \ + type, name, dirty) // noop by intention already handled by HANDLE_QT3DS_RENDER_VEC3_PROPERTY + +struct SSceneTranslator : public SGraphObjectTranslator +{ + SSceneTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SScene)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SScene &theItem = static_cast<SScene &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_SCENE_PROPERTIES + SLayer *theCurrentLayer = nullptr; + theItem.m_FirstChild = nullptr; + for (long idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + SGraphObjectTranslator::PushTranslation(inContext); + qt3dsdm::Qt3DSDMInstanceHandle theLayer = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + SGraphObjectTranslator *theTranslator = inContext.GetOrCreateTranslator(theLayer); + if (theTranslator && theTranslator->GetGraphObject().m_Type == + qt3ds::render::GraphObjectTypes::Layer) { + SLayer *theLayerObj = static_cast<SLayer *>(&theTranslator->GetGraphObject()); + theLayerObj->m_NextSibling = nullptr; + if (theItem.m_FirstChild == nullptr) + theItem.m_FirstChild = theLayerObj; + else + theCurrentLayer->m_NextSibling = theLayerObj; + theCurrentLayer = theLayerObj; + } + } + } + void ClearChildren() override + { + SScene &theItem = static_cast<SScene &>(GetGraphObject()); + SLayer *theLastChild = nullptr; + + for (SLayer *theChild = theItem.m_FirstChild; theChild; + theChild = static_cast<SLayer *>(theChild->m_NextSibling)) { + if (theLastChild) + theLastChild->m_NextSibling = nullptr; + theChild->m_Parent = nullptr; + theLastChild = theChild; + } + theItem.m_FirstChild = nullptr; + } + void AppendChild(SGraphObject &inChild) override + { + if (inChild.m_Type != GraphObjectTypes::Layer) + return; + SScene &theItem = static_cast<SScene &>(GetGraphObject()); + SLayer &theLayer = static_cast<SLayer &>(inChild); + theItem.AddChild(theLayer); + } + void SetActive(bool /*inActive*/) override + { + // How could we not be active? + } +}; + +struct SNodeTranslator : public SGraphObjectTranslator +{ + SNodeTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SNode)()) + { + Initialize(); + } + SNodeTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, SNode &inNode) + : SGraphObjectTranslator(inInstance, inNode) + { + Initialize(); + } + void Initialize() + { + SNode &theNode = static_cast<SNode &>(GetGraphObject()); + // Ensure the global transform is valid because we use this before we render sometimes. + theNode.m_GlobalTransform = QT3DSMat44::createIdentity(); + } + static inline bool IsNodeType(qt3ds::render::GraphObjectTypes::Enum inType) + { + return qt3ds::render::GraphObjectTypes::IsNodeType(inType); + } + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SNode &theItem = static_cast<SNode &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_NODE_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_BoneId, + theItem.m_SkeletonId); + bool ignoresParent = false; + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_IgnoresParent, + ignoresParent)) + theItem.m_Flags.SetIgnoreParentTransform(ignoresParent); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type) == false) { + QT3DS_ASSERT(false); + return; + } + + SNode &theItem = static_cast<SNode &>(GetGraphObject()); + SNode &theChild = static_cast<SNode &>(inChild); + theItem.AddChild(theChild); + theItem.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); + theChild.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); + } + void ClearChildren() override + { + SNode &theItem = static_cast<SNode &>(GetGraphObject()); + SNode *theLastChild = nullptr; + for (SNode *theChild = theItem.m_FirstChild; theChild; theChild = theChild->m_NextSibling) { + if (theLastChild) + theLastChild->m_NextSibling = nullptr; + theLastChild = theChild; + theChild->m_Parent = nullptr; + } + theItem.m_FirstChild = nullptr; + } + + void SetActive(bool inActive) override + { + SNode &theNode = static_cast<SNode &>(GetGraphObject()); + if (inActive != theNode.m_Flags.IsActive()) { + theNode.m_Flags.SetActive(inActive); + theNode.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); + } + } +}; + +struct SLayerTranslator : public SNodeTranslator +{ + SLayerTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SLayer)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SLayer &theItem = static_cast<SLayer &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_LAYER_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Layer.m_AoSamplerate, + theItem.m_AoSamplerate); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } else if (inChild.m_Type == GraphObjectTypes::Effect) { + SLayer &theItem = static_cast<SLayer &>(GetGraphObject()); + theItem.AddEffect(static_cast<SEffect &>(inChild)); + } else if (inChild.m_Type == GraphObjectTypes::RenderPlugin) { + SLayer &theItem = static_cast<SLayer &>(GetGraphObject()); + theItem.m_RenderPlugin = &static_cast<qt3ds::render::SRenderPlugin &>(inChild); + } + } + void ClearChildren() override + { + SNodeTranslator::ClearChildren(); + SLayer &theItem = static_cast<SLayer &>(GetGraphObject()); + SEffect *theLastChild = nullptr; + for (SEffect *theChild = theItem.m_FirstEffect; theChild; + theChild = theChild->m_NextEffect) { + if (theLastChild) + theLastChild->m_NextEffect = nullptr; + theLastChild = theChild; + theChild->m_Layer = nullptr; + } + theItem.m_FirstEffect = nullptr; + theItem.m_RenderPlugin = nullptr; + // Don't clear the light probe properties because those are added/removed as part of the + // normal + // property scan, they aren't added as generic children. + } +}; +struct SLightTranslator : public SNodeTranslator +{ + SLightTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SLight)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SLight &theItem = static_cast<SLight &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_LIGHT_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Light.m_ShadowMapRes, + theItem.m_ShadowMapRes); + } + void AppendChild(SGraphObject &inChild) override { SNodeTranslator::AppendChild(inChild); } + void ClearChildren() override { SNodeTranslator::ClearChildren(); } +}; +struct SCameraTranslator : public SNodeTranslator +{ + SCameraTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SCamera)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SCamera &theItem = static_cast<SCamera &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_CAMERA_PROPERTIES + } +}; +struct SModelTranslator : public SNodeTranslator +{ + SModelTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SModel)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SModel &theItem = static_cast<SModel &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_MODEL_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Model.m_PoseRoot, + theItem.m_SkeletonRoot); + + theItem.m_FirstMaterial = nullptr; + for (long idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theItemHandle = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + SGraphObjectTranslator *theTranslator = inContext.GetOrCreateTranslator(theItemHandle); + if (theTranslator && IsMaterial(theTranslator->GetGraphObject())) { + SGraphObject *theMaterial = &theTranslator->GetGraphObject(); + SetNextMaterialSibling(*theMaterial, nullptr); + theItem.AddMaterial(*theMaterial); + } + } + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } else if (IsMaterial(inChild)) { + SModel &theItem = static_cast<SModel &>(GetGraphObject()); + theItem.AddMaterial(inChild); + } else { + QT3DS_ASSERT(false); + } + } + void ClearChildren() override + { + SModel &theItem = static_cast<SModel &>(GetGraphObject()); + SNodeTranslator::ClearChildren(); + + SGraphObject *theLastMaterial = nullptr; + for (SGraphObject *theMaterial = theItem.m_FirstMaterial; theMaterial; + theMaterial = qt3ds::render::GetNextMaterialSibling(theMaterial)) { + if (theLastMaterial) + qt3ds::render::SetNextMaterialSibling(*theLastMaterial, nullptr); + theLastMaterial = theMaterial; + } + theItem.m_FirstMaterial = nullptr; + } +}; + +static SFloat2 ToFloat2(const Option<SValue> &inValue) +{ + if (inValue.hasValue()) + return inValue->getData<SFloat2>(); + return SFloat2(); +} + +static float ToFloat(const Option<SValue> &inValue) +{ + if (inValue.hasValue()) + return inValue->getData<QT3DSF32>(); + return 0.0f; +} + +struct SPathSubPathTranslator : public SGraphObjectTranslator +{ + eastl::vector<qt3ds::render::SPathAnchorPoint> m_PathBuffer; + SPathSubPathTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SPathSubPath)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SPathSubPath &theItem = static_cast<SPathSubPath &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_PATH_SUBPATH_PROPERTIES + m_PathBuffer.clear(); + Q3DStudio::IDocumentReader &theReader(inContext.m_Doc.GetDocumentReader()); + QT3DSU32 anchorCount = 0; + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theAnchor = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + if (theReader.GetObjectTypeName(theAnchor) == L"PathAnchorPoint") + ++anchorCount; + } + QT3DSU32 anchorIdx = 0; + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(GetInstanceHandle()); + idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theAnchor = + inContext.m_AssetGraph.GetChild(GetInstanceHandle(), idx); + if (theReader.GetObjectTypeName(theAnchor) == L"PathAnchorPoint") { + SFloat2 theAnchorPos = ToFloat2(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_Position.m_Property)); + float theIncomingAngle = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingAngle.m_Property)); + float theIncomingDistance = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingDistance.m_Property)); + float theOutgoingDistance = ToFloat(theReader.GetInstancePropertyValue( + theAnchor, + inContext.m_ObjectDefinitions.m_PathAnchorPoint.m_OutgoingDistance.m_Property)); + qt3ds::render::SPathAnchorPoint thePoint(QT3DSVec2(theAnchorPos[0], theAnchorPos[1]), + theIncomingAngle, theIncomingAngle + 180.0f, + theIncomingDistance, theOutgoingDistance); + m_PathBuffer.push_back(thePoint); + ++anchorIdx; + } + } + inContext.m_Context.GetPathManager().SetPathSubPathData( + theItem, + qt3ds::foundation::toConstDataRef(m_PathBuffer.begin(), (QT3DSU32)m_PathBuffer.size())); + } + + void AppendChild(SGraphObject &) override {} + + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; + +struct SPathTranslator : public SNodeTranslator +{ + SPathTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SPath)()) + { + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsMaterialType(inChild.m_Type)) { + SPath &theItem = static_cast<SPath &>(GetGraphObject()); + theItem.AddMaterial(&inChild); + theItem.m_Flags.SetDirty(true); + } else if (inChild.m_Type == GraphObjectTypes::PathSubPath) { + SPath &theItem = static_cast<SPath &>(GetGraphObject()); + theItem.AddSubPath(static_cast<SPathSubPath &>(inChild)); + theItem.m_Flags.SetDirty(true); + } else { + SNodeTranslator::AppendChild(inChild); + } + } + + void ClearChildren() override + { + SNodeTranslator::ClearChildren(); + SPath &theItem = static_cast<SPath &>(GetGraphObject()); + theItem.ClearMaterials(); + theItem.ClearSubPaths(); + } + + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + SPath &theItem = static_cast<SPath &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_PATH_PROPERTIES + } +}; + +struct SDefaultMaterialTranslator : public SGraphObjectTranslator +{ + SDefaultMaterialTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SDefaultMaterial)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SDefaultMaterial &theItem = static_cast<SDefaultMaterial &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_MATERIAL_PROPERTIES + + // qt3dsdm::Qt3DSDMInstanceHandle parent = inContext.m_AssetGraph.GetParent( + // GetInstanceHandle() ); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theItem.m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theItem.m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theItem.m_Lightmaps.m_LightmapShadow); + } + + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; + +struct SImageTranslator : public SGraphObjectTranslator +{ + SImageTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SImage)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SImage &theItem = static_cast<SImage &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_IMAGE_PROPERTIES + + theItem.m_Flags.SetDirty(true); + theItem.m_Flags.SetTransformDirty(true); + } + void AppendChild(SGraphObject &child) override + { + SImage &theItem = static_cast<SImage &>(GetGraphObject()); + if (child.m_Type == GraphObjectTypes::RenderPlugin) + theItem.m_RenderPlugin = &static_cast<qt3ds::render::SRenderPlugin &>(child); + } + void ClearChildren() override + { + SImage &theItem = static_cast<SImage &>(GetGraphObject()); + theItem.m_RenderPlugin = nullptr; + } + + void SetActive(bool /*inActive*/) override {} +}; + +struct STextTranslator : public SNodeTranslator +{ + STextTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SNodeTranslator(inInstance, *QT3DS_NEW(inAlloc, SText)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SNodeTranslator::PushTranslation(inContext); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + SText &theItem = static_cast<SText &>(GetGraphObject()); + ITERATE_QT3DS_RENDER_TEXT_PROPERTIES + theItem.m_Flags.SetTextDirty(true); + } +}; + +inline qt3ds::QT3DSVec2 ToRenderType(const qt3dsdm::SFloat2 &inType) +{ + return qt3ds::QT3DSVec2(inType.m_Floats[0], inType.m_Floats[1]); +} +inline qt3ds::QT3DSVec3 ToRenderType(const qt3dsdm::SFloat3 &inType) +{ + return qt3ds::QT3DSVec3(inType.m_Floats[0], inType.m_Floats[1], inType.m_Floats[2]); +} +inline qt3ds::QT3DSVec4 ToRenderType(const qt3dsdm::SFloat4 &inType) +{ + return qt3ds::QT3DSVec4(inType.m_Floats[0], inType.m_Floats[1], inType.m_Floats[2], + inType.m_Floats[3]); +} + +struct SDynamicObjectTranslator : public SGraphObjectTranslator +{ + typedef eastl::vector<eastl::pair<QT3DSU32, int>> TIdxToPropertyMap; + eastl::basic_string<qt3ds::foundation::TWCharEASTLConverter::TCharType> m_ConvertStr; + TIdxToPropertyMap m_PropertyMap; + + SDynamicObjectTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &, + SDynamicObject &inObject) + : SGraphObjectTranslator(inInstance, inObject) + { + } + + void PushTranslation(STranslation &inContext) override + { + SDynamicObject &theItem = static_cast<SDynamicObject &>(GetGraphObject()); + IDynamicObjectSystem &theSystem = inContext.m_Context.GetDynamicObjectSystem(); + using namespace qt3ds::render::dynamic; + using qt3ds::foundation::NVConstDataRef; + NVConstDataRef<SPropertyDefinition> theProperties = + theSystem.GetProperties(theItem.m_ClassName); + if (m_PropertyMap.size() == 0) { + for (QT3DSU32 idx = 0, end = theProperties.size(); idx < end; ++idx) { + const SPropertyDefinition &theDefinition(theProperties[idx]); + qt3ds::foundation::ConvertUTF(theDefinition.m_Name.c_str(), 0, m_ConvertStr); + const wchar_t *thePropName = + reinterpret_cast<const wchar_t *>(m_ConvertStr.c_str()); + qt3dsdm::Qt3DSDMPropertyHandle theProperty = + inContext.m_Reader.FindProperty(GetInstanceHandle(), thePropName); + if (theProperty.Valid()) + m_PropertyMap.push_back(eastl::make_pair(idx, theProperty.GetHandleValue())); + } + } + std::shared_ptr<IDataCore> theDataCore = + inContext.m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetDataCore(); + for (TIdxToPropertyMap::iterator theIter = m_PropertyMap.begin(), end = m_PropertyMap.end(); + theIter != end; ++theIter) { + const SPropertyDefinition &theDefinition(theProperties[theIter->first]); + qt3dsdm::Qt3DSDMPropertyHandle theProperty = theIter->second; + // Sometimes it is possible to have dirty properties that no longer exist, e.g. + // when undoing standard material -> custom material change. We just ignore changes + // to such properties. + if (theDataCore->IsProperty(theProperty)) { + Option<qt3dsdm::SValue> theValueOpt = + inContext.m_Reader.GetInstancePropertyValue(GetInstanceHandle(), theProperty); + if (theValueOpt.hasValue()) { + qt3dsdm::SValue &theValue(*theValueOpt); + switch (qt3dsdm::GetValueType(theValue)) { + case qt3dsdm::DataModelDataType::Long: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSI32) { + theItem.SetPropertyValue(theDefinition, + qt3dsdm::get<qt3ds::QT3DSI32>(theValue)); + } else { + QT3DS_ASSERT(false); + } + break; + case qt3dsdm::DataModelDataType::Bool: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool) { + theItem.SetPropertyValue(theDefinition, qt3dsdm::get<bool>(theValue)); + } else { + QT3DS_ASSERT(false); + } + break; + case qt3dsdm::DataModelDataType::Float: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSF32) { + theItem.SetPropertyValue(theDefinition, qt3dsdm::get<float>(theValue)); + } else { + QT3DS_ASSERT(false); + } + break; + case qt3dsdm::DataModelDataType::Float2: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSVec2) { + theItem.SetPropertyValue( + theDefinition, ToRenderType(qt3dsdm::get<qt3dsdm::SFloat2>(theValue))); + } else { + QT3DS_ASSERT(false); + } + break; + case qt3dsdm::DataModelDataType::Float3: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSVec3) { + theItem.SetPropertyValue( + theDefinition, ToRenderType(qt3dsdm::get<qt3dsdm::SFloat3>(theValue))); + } else { + QT3DS_ASSERT(false); + } + break; + case qt3dsdm::DataModelDataType::Float4: + if (theDefinition.m_DataType + == qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4) { + theItem.SetPropertyValue( + theDefinition, ToRenderType(qt3dsdm::get<qt3dsdm::SFloat4>(theValue))); + } else { + QT3DS_ASSERT(false); + } + break; + // Could be either an enum or a texture. + case qt3dsdm::DataModelDataType::String: { + qt3dsdm::TDataStrPtr theData = qt3dsdm::get<qt3dsdm::TDataStrPtr>(theValue); + if (theData) { + eastl::string theStr; + qt3ds::render::ConvertWideUTF(theData->GetData(), 0, theStr); + eastl::string theWorkspace; + theItem.SetPropertyValue( + theDefinition, theStr.c_str(), + inContext.m_Doc.GetCore()->getProjectFile() + .getProjectPath().toLocal8Bit().constData(), + theWorkspace, inContext.m_Context.GetStringTable()); + } + } break; + default: + QT3DS_ASSERT(false); + } + } + } + } + } + + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} +}; + +struct SEffectTranslator : public SDynamicObjectTranslator +{ + // TODO - move this map to inContext and have it looked up by name. + IEffectSystem *m_EffectSystem; + + SEffectTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc, + SEffect &inEffect) + : SDynamicObjectTranslator(inInstance, inAlloc, inEffect) + , m_EffectSystem(nullptr) + { + } + void PushTranslation(STranslation &inContext) override + { + m_EffectSystem = &inContext.m_Context.GetEffectSystem(); + SDynamicObjectTranslator::PushTranslation(inContext); + } + + void SetActive(bool inActive) override + { + SEffect &theItem = static_cast<SEffect &>(GetGraphObject()); + if (m_EffectSystem) + theItem.SetActive(inActive, *m_EffectSystem); + else + theItem.m_Flags.SetActive(inActive); + } + + void ResetEffect() override + { + SEffect &theItem = static_cast<SEffect &>(GetGraphObject()); + if (m_EffectSystem) + theItem.Reset(*m_EffectSystem); + } +}; +struct SCustomMaterialTranslator : public SDynamicObjectTranslator +{ + ICustomMaterialSystem *m_MaterialSystem; + + SCustomMaterialTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc, SCustomMaterial &inMaterial) + : SDynamicObjectTranslator(inInstance, inAlloc, inMaterial) + , m_MaterialSystem(nullptr) + { + } + + void PushTranslation(STranslation &inContext) override + { + SDynamicObjectTranslator::PushTranslation(inContext); + SCustomMaterial &theItem = static_cast<SCustomMaterial &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_CUSTOM_MATERIAL_PROPERTIES + + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theItem.m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theItem.m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theItem.m_Lightmaps.m_LightmapShadow); + } + + void SetActive(bool inActive) override + { + if (m_MaterialSystem) { + SCustomMaterial &theItem = static_cast<SCustomMaterial &>(GetGraphObject()); + if (inActive != theItem.m_Flags.IsActive()) { + theItem.m_Flags.SetActive(inActive); + m_MaterialSystem->OnMaterialActivationChange(theItem, inActive); + } + } + } +}; +struct SReferencedMaterialTranslator : public SGraphObjectTranslator +{ + SReferencedMaterialTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SReferencedMaterial)()) + { + } + void PushTranslation(STranslation &inContext) override + { + SGraphObjectTranslator::PushTranslation(inContext); + SReferencedMaterial &theItem = static_cast<SReferencedMaterial &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + ITERATE_QT3DS_RENDER_REFERENCED_MATERIAL_PROPERTIES + + theItem.m_Dirty.SetDirty(); + if (theItem.m_ReferencedMaterial == &theItem) { + qCCritical(qt3ds::INVALID_OPERATION, + "Referenced material is referencing itself."); + } else if (theItem.m_ReferencedMaterial + && theItem.m_ReferencedMaterial->m_Type == GraphObjectTypes::DefaultMaterial) { + SDefaultMaterial *theDefaultItem = + static_cast<SDefaultMaterial *>(theItem.m_ReferencedMaterial); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theDefaultItem->m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theDefaultItem->m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theDefaultItem->m_Lightmaps.m_LightmapShadow); + } else if (theItem.m_ReferencedMaterial + && theItem.m_ReferencedMaterial->m_Type == GraphObjectTypes::CustomMaterial) { + SCustomMaterial *theDefaultItem = + static_cast<SCustomMaterial *>(theItem.m_ReferencedMaterial); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapIndirect, + theDefaultItem->m_Lightmaps.m_LightmapIndirect); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapRadiosity, + theDefaultItem->m_Lightmaps.m_LightmapRadiosity); + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Lightmaps.m_LightmapShadow, + theDefaultItem->m_Lightmaps.m_LightmapShadow); + } + } + + void AppendChild(SGraphObject &) override {} + + void ClearChildren() override {} + + void SetActive(bool /*inActive*/) override {} +}; +using qt3ds::render::SRenderPlugin; +using qt3ds::render::SRenderPropertyValueUpdate; +using qt3ds::render::IRenderPluginClass; +using qt3ds::render::SRenderPluginPropertyDeclaration; +struct SRenderPluginPropertyUpdateFactory +{ + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, float value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, qt3ds::QT3DSI32 value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, bool value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &) + { + ioUpdates.push_back(SRenderPropertyValueUpdate(theDec.m_Name, value)); + } + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, qt3dsdm::TDataStrPtr value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &, + qt3ds::foundation::IStringTable &strTable) + { + if (value) { + ioUpdates.push_back( + SRenderPropertyValueUpdate(theDec.m_Name, strTable.RegisterStr(value->GetData()))); + } + } + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, qt3dsdm::SStringRef value, + const SRenderPluginPropertyDeclaration &theDec, IRenderPluginClass &, + qt3ds::foundation::IStringTable &strTable) + { + ioUpdates.push_back( + SRenderPropertyValueUpdate(theDec.m_Name, strTable.RegisterStr(value.m_Id))); + } + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, + const qt3dsdm::SFloat2 &value, const SRenderPluginPropertyDeclaration &theDec, + IRenderPluginClass &inClass) + { + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset).first, value.m_Floats[0])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 1).first, value.m_Floats[1])); + } + + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, + const qt3dsdm::SFloat3 &value, const SRenderPluginPropertyDeclaration &theDec, + IRenderPluginClass &inClass) + { + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset).first, value.m_Floats[0])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 1).first, value.m_Floats[1])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 2).first, value.m_Floats[2])); + } + + static void Add(eastl::vector<SRenderPropertyValueUpdate> &ioUpdates, + const qt3dsdm::SFloat4 &value, const SRenderPluginPropertyDeclaration &theDec, + IRenderPluginClass &inClass) + { + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset).first, value.m_Floats[0])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 1).first, value.m_Floats[1])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 2).first, value.m_Floats[2])); + ioUpdates.push_back(SRenderPropertyValueUpdate( + inClass.GetPropertyValueInfo(theDec.m_StartOffset + 3).first, value.m_Floats[3])); + } +}; +struct SRenderPluginTranslator : public SGraphObjectTranslator +{ + eastl::vector<SRenderPropertyValueUpdate> m_PropertyUpdates; + + SRenderPluginTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SRenderPlugin)()) + { + } + + void PushTranslation(STranslation &inContext) override + { + SRenderPlugin &theItem = static_cast<SRenderPlugin &>(GetGraphObject()); + // First, get the instance via resolving the source path. + Qt3DSDMPropertyHandle sourcepath = + inContext.m_Reader.FindProperty(GetInstanceHandle(), L"sourcepath"); + Option<SValue> theSourcePath = + inContext.m_Reader.GetInstancePropertyValue(GetInstanceHandle(), sourcepath); + qt3dsdm::TDataStrPtr theData = theSourcePath->getData<qt3dsdm::TDataStrPtr>(); + if (!theData) + return; + + Q3DStudio::CFilePath theFullPath = inContext.m_Doc.GetResolvedPathToDoc(theData->GetData()); + qt3ds::foundation::IStringTable &theStrTable = inContext.m_Context.GetStringTable(); + theItem.m_PluginPath = theStrTable.RegisterStr(theFullPath.toCString()); + qt3ds::render::IRenderPluginInstance *theInstance = + inContext.m_Context.GetRenderPluginManager().GetOrCreateRenderPluginInstance( + theItem.m_PluginPath, &theItem); + + // Couldn't load the instance, so we can't render the instance. + if (theInstance == nullptr) + return; + // Grab the instance's parent and get the properties that are specific to just that + // instance. + TInstanceHandleList derivationParents; + std::shared_ptr<IDataCore> theDataCore = + inContext.m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetDataCore(); + theDataCore->GetInstanceParents(GetInstanceHandle(), derivationParents); + if (derivationParents.size() == 0) + return; + TPropertyHandleList theSpecificProperties; + theDataCore->GetInstanceProperties(derivationParents[0], theSpecificProperties); + eastl::string propStem; + eastl::string propname; + m_PropertyUpdates.clear(); + qt3ds::render::IRenderPluginClass &theClass = theInstance->GetPluginClass(); + using qt3ds::render::SRenderPluginPropertyDeclaration; + if (theClass.GetRegisteredProperties().size() == 0) { + for (size_t idx = 0, end = theSpecificProperties.size(); idx < end; ++idx) { + Qt3DSDMPropertyDefinition theProperty = + theDataCore->GetProperty(theSpecificProperties[idx]); + qt3dsdm::AdditionalMetaDataType::Value theMetaType = + inContext.m_StudioSystem.GetActionMetaData()->GetAdditionalMetaDataType( + GetInstanceHandle(), theSpecificProperties[idx]); + CRegisteredString thePropName(theStrTable.RegisterStr(theProperty.m_Name.c_str())); + switch (theProperty.m_Type) { + case DataModelDataType::Float: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Float)); + break; + case DataModelDataType::Float2: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Vector2)); + break; + case DataModelDataType::Float3: + if (theMetaType != AdditionalMetaDataType::Color) { + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Vector3)); + } else { + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Color)); + } + break; + case DataModelDataType::Float4: + if (theMetaType == AdditionalMetaDataType::Color) { + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Color)); + } + break; + case DataModelDataType::Long: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Long)); + break; + case DataModelDataType::String: + case DataModelDataType::StringRef: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::String)); + break; + case DataModelDataType::Bool: + theClass.RegisterProperty(SRenderPluginPropertyDeclaration( + thePropName, qt3ds::render::SRenderPluginPropertyTypes::Boolean)); + break; + default: + // Unsupported plugin property. + QT3DS_ASSERT(false); + break; + } + } + } + for (size_t idx = 0, end = theSpecificProperties.size(); idx < end; ++idx) { + Option<SValue> thePropValueOpt = inContext.m_Reader.GetInstancePropertyValue( + GetInstanceHandle(), theSpecificProperties[idx]); + if (thePropValueOpt.hasValue()) { + SValue &thePropValue = thePropValueOpt.getValue(); + Qt3DSDMPropertyDefinition theProperty = + theDataCore->GetProperty(theSpecificProperties[idx]); + SRenderPluginPropertyDeclaration theDeclaration(theClass.GetPropertyDeclaration( + theStrTable.RegisterStr(theProperty.m_Name.c_str()))); + + switch (thePropValue.getType()) { + case DataModelDataType::None: + QT3DS_ASSERT(false); + break; + case DataModelDataType::Float: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData<float>(), theDeclaration, theClass); + break; + case DataModelDataType::Float2: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData<SFloat2>(), + theDeclaration, theClass); + break; + case DataModelDataType::Float3: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData<SFloat3>(), + theDeclaration, theClass); + break; + case DataModelDataType::Float4: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData<SFloat4>(), + theDeclaration, theClass); + break; + case DataModelDataType::Long: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData<qt3ds::QT3DSI32>(), theDeclaration, theClass); + break; + case DataModelDataType::String: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData<TDataStrPtr>(), + theDeclaration, theClass, theStrTable); + break; + case DataModelDataType::Bool: + SRenderPluginPropertyUpdateFactory::Add( + m_PropertyUpdates, thePropValue.getData<bool>(), theDeclaration, theClass); + break; + case DataModelDataType::StringRef: + SRenderPluginPropertyUpdateFactory::Add(m_PropertyUpdates, + thePropValue.getData<SStringRef>(), + theDeclaration, theClass, theStrTable); + break; + default: + QT3DS_ASSERT(false); + break; + } + } + } + theInstance->Update(NVConstDataRef<SRenderPropertyValueUpdate>(m_PropertyUpdates.data(), + m_PropertyUpdates.size())); + } + void AppendChild(SGraphObject &) override {} + void ClearChildren() override {} + void SetActive(bool inActive) override + { + SRenderPlugin &theItem = static_cast<SRenderPlugin &>(GetGraphObject()); + theItem.m_Flags.SetActive(inActive); + } +}; + +struct SAliasTranslator : public SGraphObjectTranslator +{ + SGraphObjectTranslator *m_ReferenceTree; + Qt3DSDMInstanceHandle m_ReferencedInstance; + SAliasTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, qt3ds::NVAllocatorCallback &inAlloc) + : SGraphObjectTranslator(inInstance, *QT3DS_NEW(inAlloc, SNode)()) + , m_ReferenceTree(nullptr) + { + } + void RecurseAndCreateTranslators(STranslation &inContext, + qt3dsdm::Qt3DSDMInstanceHandle inInstance) + { + for (QT3DSI32 idx = 0, end = inContext.m_AssetGraph.GetChildCount(inInstance); idx < end; + ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theChild = inContext.m_AssetGraph.GetChild(inInstance, idx); + inContext.GetOrCreateTranslator(theChild, m_InstanceHandle); + RecurseAndCreateTranslators(inContext, theChild); + } + } + void PushTranslation(STranslation &inContext) override + { + STranslatorDataModelParser theParser(inContext, GetInstanceHandle()); + Option<SObjectRefType> theData = theParser.GetPropertyValue<SObjectRefType>( + inContext.m_ObjectDefinitions.m_Alias.m_ReferencedNode); + m_ReferencedInstance = Qt3DSDMInstanceHandle(); + m_ReferenceTree = nullptr; + ((SNode *)m_GraphObject)->m_Flags.SetDirty(true); + if (theData.hasValue()) { + m_ReferencedInstance = + inContext.m_Reader.GetInstanceForObjectRef(GetInstanceHandle(), *theData); + if (inContext.m_Reader.IsInstance(m_ReferencedInstance)) { + m_ReferenceTree = + inContext.GetOrCreateTranslator(m_ReferencedInstance, m_InstanceHandle); + if (m_ReferenceTree + && !GraphObjectTypes::IsNodeType(m_ReferenceTree->GetGraphObject().m_Type)) { + QT3DS_ASSERT(false); + m_ReferenceTree = nullptr; + m_ReferencedInstance = Qt3DSDMInstanceHandle(); + } else { + RecurseAndCreateTranslators(inContext, m_ReferencedInstance); + } + } + } + } + + void AfterRenderGraphIsBuilt(STranslation &inContext) override + { + SNode &theItem = static_cast<SNode &>(GetGraphObject()); + STranslatorDataModelParser theParser(inContext, m_InstanceHandle); + ITERATE_QT3DS_RENDER_NODE_PROPERTIES + theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_BoneId, + theItem.m_SkeletonId); + bool ignoresParent = false; + if (theParser.ParseProperty(inContext.m_ObjectDefinitions.m_Node.m_IgnoresParent, + ignoresParent)) + theItem.m_Flags.SetIgnoreParentTransform(ignoresParent); + theItem.m_Flags.SetDirty(true); + } + void AppendChild(SGraphObject &inObject) override + { + if (m_ReferenceTree) + m_ReferenceTree->AppendChild(inObject); + } + void ClearChildren() override + { + if (m_ReferenceTree) + m_ReferenceTree->ClearChildren(); + } + void SetActive(bool inActive) override + { + SNode &theItem = static_cast<SNode &>(GetGraphObject()); + theItem.m_Flags.SetActive(inActive); + } + SGraphObject &GetGraphObject() override + { + if (m_ReferenceTree) + return *m_ReferenceTree->m_GraphObject; + return *m_GraphObject; + } + qt3dsdm::Qt3DSDMInstanceHandle GetSceneGraphInstanceHandle() override + { + if (m_ReferencedInstance.Valid()) + return m_ReferencedInstance; + return m_InstanceHandle; + } + Qt3DSDMInstanceHandle GetInstanceHandle() override { return m_InstanceHandle; } + + SGraphObject &GetNonAliasedGraphObject() override { return *m_GraphObject; } +}; +} + +void SGraphObjectTranslator::PushTranslation(STranslation &inTranslatorContext) +{ + Q3DStudio::CString theId = inTranslatorContext.m_Reader.GetFileId(GetInstanceHandle()); + if (theId.size()) + GetGraphObject().m_Id = + inTranslatorContext.m_Context.GetStringTable().RegisterStr(theId.c_str()); +} + +bool STranslation::IncludeNode(const SNode &inNode) +{ + SGraphObjectTranslator *theTranslator = inNode.m_UserData.DynamicCast<SGraphObjectTranslator>(); + if (theTranslator + && m_Doc.GetDocumentReader().IsCurrentlyActive(theTranslator->GetInstanceHandle())) + return true; + return false; +} + +void STranslation::ReleaseEffect(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + if (m_Reader.IsInstance(inInstance) == false) + return; + + qt3dsdm::ComposerObjectTypes::Enum theType = m_ObjectDefinitions.GetType(inInstance); + qt3dsdm::Qt3DSDMInstanceHandle theParentClass = m_Reader.GetFirstBaseClass(inInstance); + + if (theType == NULL && theParentClass.Valid()) + theType = m_ObjectDefinitions.GetType(theParentClass); + + if (theType == qt3dsdm::ComposerObjectTypes::Effect) { + IEffectSystem &theSystem = m_Context.GetEffectSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_Context.GetStringTable().RegisterStr(theInstanceName); + + if (theSystem.IsEffectRegistered(theNameStr)) { + TInstanceToTranslatorMap::iterator theTranslatorList = + m_TranslatorMap.find(inInstance); + if (theTranslatorList != m_TranslatorMap.end()) + m_TranslatorMap.erase(theTranslatorList); + theSystem.SetEffectRequiresCompilation(theNameStr, true); + } + } + } +} + +SGraphObjectTranslator *STranslation::CreateTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + SGraphObjectTranslator *theNewTranslator = nullptr; + qt3dsdm::ComposerObjectTypes::Enum theType = m_ObjectDefinitions.GetType(inInstance); + qt3dsdm::Qt3DSDMInstanceHandle theParentClass = m_Reader.GetFirstBaseClass(inInstance); + if (theType == NULL && theParentClass.Valid()) + theType = m_ObjectDefinitions.GetType(theParentClass); + + // For the subset of possible instances, pick out the valid translators. + switch (theType) { + case qt3dsdm::ComposerObjectTypes::Group: + case qt3dsdm::ComposerObjectTypes::Component: + case qt3dsdm::ComposerObjectTypes::Node: + theNewTranslator = QT3DS_NEW(m_Allocator, SNodeTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Scene: + theNewTranslator = QT3DS_NEW(m_Allocator, SSceneTranslator)(inInstance, m_Allocator); + m_Scene = static_cast<SScene *>(&theNewTranslator->GetGraphObject()); + m_Scene->m_Presentation = &m_Presentation; + break; + case qt3dsdm::ComposerObjectTypes::Layer: + theNewTranslator = QT3DS_NEW(m_Allocator, SLayerTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Light: + theNewTranslator = QT3DS_NEW(m_Allocator, SLightTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Camera: + theNewTranslator = QT3DS_NEW(m_Allocator, SCameraTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Model: + theNewTranslator = QT3DS_NEW(m_Allocator, SModelTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Image: + theNewTranslator = QT3DS_NEW(m_Allocator, SImageTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Text: + theNewTranslator = QT3DS_NEW(m_Allocator, STextTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Material: + theNewTranslator = QT3DS_NEW(m_Allocator, SDefaultMaterialTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::ReferencedMaterial: + theNewTranslator = + QT3DS_NEW(m_Allocator, SReferencedMaterialTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Alias: + theNewTranslator = QT3DS_NEW(m_Allocator, SAliasTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Path: + theNewTranslator = QT3DS_NEW(m_Allocator, SPathTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::SubPath: + theNewTranslator = QT3DS_NEW(m_Allocator, SPathSubPathTranslator)(inInstance, m_Allocator); + break; + case qt3dsdm::ComposerObjectTypes::Effect: { + IEffectSystem &theSystem = m_Context.GetEffectSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_Context.GetStringTable().RegisterStr(theInstanceName); + + if (theSystem.IsEffectRegistered(theNameStr) + && theSystem.DoesEffectRequireCompilation(theNameStr)) { + theSystem.UnregisterEffect(theNameStr); + } + + if (!theSystem.IsEffectRegistered(theNameStr)) { + // We assume the effect has already been registered and such. + qt3dsdm::IMetaData &theMetaData(*m_StudioSystem.GetActionMetaData()); + Q3DStudio::CString theInstancePath = m_Reader.GetSourcePath(theParentClass); + Option<qt3dsdm::SMetaDataEffect> theMetaEffect = + theMetaData.GetEffectBySourcePath( + m_Context.GetStringTable().GetNarrowStr(theInstancePath)); + if (theMetaEffect.hasValue()) { + qt3ds::render::IUIPLoader::CreateEffectClassFromMetaEffect( + theNameStr, m_Context.GetFoundation(), theSystem, theMetaEffect, + m_Context.GetStringTable()); + theSystem.SetEffectRequiresCompilation(theNameStr, true); + } + } + + if (theSystem.IsEffectRegistered(theNameStr)) { + theNewTranslator = QT3DS_NEW(m_Allocator, SEffectTranslator)( + inInstance, m_Allocator, + *theSystem.CreateEffectInstance(theNameStr, m_Allocator)); + } + } + } + break; + case qt3dsdm::ComposerObjectTypes::CustomMaterial: { + ICustomMaterialSystem &theSystem = m_Context.GetCustomMaterialSystem(); + if (theParentClass.Valid()) { + Q3DStudio::CString theInstanceName = m_Reader.GetName(theParentClass); + CRegisteredString theNameStr = + m_Context.GetStringTable().RegisterStr(theInstanceName); + if (!theSystem.IsMaterialRegistered(theNameStr)) { + // We assume the effect has already been registered and such. + qt3dsdm::IMetaData &theMetaData(*m_StudioSystem.GetActionMetaData()); + Q3DStudio::CString theInstancePath = m_Reader.GetSourcePath(theParentClass); + Option<qt3dsdm::SMetaDataCustomMaterial> theMaterialData = + theMetaData.GetMaterialBySourcePath( + m_Context.GetStringTable().GetNarrowStr(theInstancePath)); + if (theMaterialData.hasValue()) { + qt3ds::render::IUIPLoader::CreateMaterialClassFromMetaMaterial( + theNameStr, m_Context.GetFoundation(), theSystem, theMaterialData, + m_Context.GetStringTable()); + } + } + if (theSystem.IsMaterialRegistered(theNameStr)) { + theNewTranslator = QT3DS_NEW(m_Allocator, SCustomMaterialTranslator)( + inInstance, m_Allocator, + *theSystem.CreateCustomMaterial(theNameStr, m_Allocator)); + static_cast<SCustomMaterialTranslator *>(theNewTranslator)->m_MaterialSystem = + &theSystem; + } + } + } + break; + case qt3dsdm::ComposerObjectTypes::RenderPlugin: { + theNewTranslator = QT3DS_NEW(m_Allocator, SRenderPluginTranslator)(inInstance, m_Allocator); + } + break; + default: + break; + } + + return theNewTranslator; +} + +bool CompareTranslator(const STranslation::THandleTranslatorPair &first, + const STranslation::THandleTranslatorPair &second) +{ + return first.first == second.first; +} + +struct STranslatorPredicate +{ + Qt3DSDMInstanceHandle m_Instance; + STranslatorPredicate(Qt3DSDMInstanceHandle &ins) + : m_Instance(ins) + { + } + bool operator()(const STranslation::THandleTranslatorPair &first) const + { + return first.first == m_Instance; + } +}; + +Option<STranslation::THandleTranslatorPair> +FindTranslator(STranslation::THandleTranslatorPairList &inList, + Qt3DSDMInstanceHandle inInstance = Qt3DSDMInstanceHandle()) +{ + STranslation::THandleTranslatorPairList::iterator iter = + eastl::find_if(inList.begin(), inList.end(), STranslatorPredicate(inInstance)); + if (iter != inList.end()) + return *iter; + return Empty(); +} + +SGraphObjectTranslator *STranslation::GetOrCreateTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + return GetOrCreateTranslator(inInstance, Qt3DSDMInstanceHandle()); +} + +SGraphObjectTranslator * +STranslation::GetOrCreateTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3dsdm::Qt3DSDMInstanceHandle inAliasInstance) +{ + TInstanceToTranslatorMap::iterator theTranslatorList = + m_TranslatorMap.insert(eastl::make_pair(inInstance, THandleTranslatorPairList())).first; + THandleTranslatorPairList &theList = theTranslatorList->second; + Option<STranslation::THandleTranslatorPair> theExistingTranslator = + FindTranslator(theList, inAliasInstance); + + if (theExistingTranslator.hasValue()) { + return theExistingTranslator->second; + } + if (m_Reader.IsInstance(inInstance) == false) + return nullptr; + + SGraphObjectTranslator *theNewTranslator = CreateTranslator(inInstance); + if (theNewTranslator != nullptr) { + theNewTranslator->m_AliasInstanceHandle = inAliasInstance; + m_DirtySet.insert(*theNewTranslator); + theList.push_back(THandleTranslatorPair(inAliasInstance, theNewTranslator)); + } + + return theNewTranslator; +} + +STranslation::THandleTranslatorPairList & +STranslation::GetTranslatorsForInstance(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + return m_TranslatorMap.insert(eastl::make_pair(inInstance, THandleTranslatorPairList())) + .first->second; +} + +qt3dsdm::Qt3DSDMInstanceHandle STranslation::GetAnchorPoint(QT3DSU32 inAnchorIndex) +{ + SGraphObjectTranslator *thePathTranslator = + static_cast<SGraphObjectTranslator *>(m_PathWidget->GetNode().m_UserData.m_UserData); + if (thePathTranslator == nullptr) + return qt3dsdm::Qt3DSDMInstanceHandle(); + qt3dsdm::Qt3DSDMInstanceHandle thePathHandle = thePathTranslator->GetInstanceHandle(); + QT3DSU32 theAnchorIndex = 0; + for (QT3DSI32 idx = 0, end = m_AssetGraph.GetChildCount(thePathHandle); idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theChildInstance = m_AssetGraph.GetChild(thePathHandle, idx); + if (m_Doc.GetDocumentReader().GetObjectTypeName(theChildInstance) == L"SubPath") { + QT3DSI32 numAnchors = m_AssetGraph.GetChildCount(theChildInstance); + QT3DSU32 endIndex = theAnchorIndex + (QT3DSU32)numAnchors; + if (endIndex > inAnchorIndex) { + return m_AssetGraph.GetChild(theChildInstance, inAnchorIndex - theAnchorIndex); + } else + theAnchorIndex = endIndex; + } + } + return qt3dsdm::Qt3DSDMInstanceHandle(); +} + +qt3dsdm::Qt3DSDMInstanceHandle STranslation::GetAnchorPoint(SPathPick &inPick) +{ + return GetAnchorPoint(inPick.m_AnchorIndex); +} + +namespace qt3ds { +namespace studio { + struct SEditCameraLayerTranslator : public SLayerTranslator + { + SEditCameraLayerTranslator(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3ds::NVAllocatorCallback &inAlloc) + : SLayerTranslator(inInstance, inAlloc) + { + } + void PushTranslation(STranslation &) override + { + SLayer &theItem = static_cast<SLayer &>(GetGraphObject()); + theItem.m_Flags.SetActive(true); + } + void AppendChild(SGraphObject &inChild) override + { + if (GraphObjectTypes::IsNodeType(inChild.m_Type)) { + SNodeTranslator::AppendChild(inChild); + } + } + }; +} +} + +STranslation::STranslation(IStudioRenderer &inRenderer, IQt3DSRenderContext &inContext) + : m_Renderer(inRenderer) + , m_Context(inContext) + , m_Doc(*g_StudioApp.GetCore()->GetDoc()) + , m_Reader(m_Doc.GetDocumentReader()) + , m_ObjectDefinitions( + m_Doc.GetStudioSystem()->GetClientDataModelBridge()->GetObjectDefinitions()) + , m_StudioSystem(*m_Doc.GetStudioSystem()) + , m_FullSystem(*m_Doc.GetStudioSystem()->GetFullSystem()) + , m_AssetGraph(*m_Doc.GetAssetGraph()) + , m_Allocator(inContext.GetRenderContext().GetFoundation()) + , m_TranslatorMap(inContext.GetAllocator(), "STranslation::m_TranslatorMap") + , m_DirtySet(inContext.GetAllocator(), "STranslation::m_DirtySet") + , m_Scene(nullptr) + , m_SignalConnections(inContext.GetAllocator(), "STranslation::m_SignalConnections") + , m_ComponentSecondsDepth(0) + , m_KeyRepeat(0) + , m_EditCameraEnabled(false) + , m_EditLightEnabled(false) + , m_Viewport(0, 0) + , m_EditCameraLayerTranslator(nullptr) + , m_PixelBuffer(inContext.GetAllocator(), "STranslation::m_PixelBuffer") + , m_editModeCamerasAndLights(inContext.GetAllocator(), + "STranslation::m_editModeCamerasAndLights") + , m_GuideAllocator(inContext.GetAllocator(), "STranslation::m_GuideAllocator") +{ + m_EditCamera.m_Flags.SetActive(true); + m_EditLight.m_Flags.SetActive(true); + qt3dsdm::Qt3DSDMInstanceHandle theScene = m_AssetGraph.GetRoot(0); + m_GraphIterator.ClearResults(); + m_AssetGraph.GetDepthFirst(m_GraphIterator, theScene); + for (; !m_GraphIterator.IsDone(); ++m_GraphIterator) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance(m_GraphIterator.GetCurrent()); + GetOrCreateTranslator(theInstance); + } + qt3dsdm::IStudioFullSystemSignalProvider *theProvider = m_FullSystem.GetSignalProvider(); + m_SignalConnections.push_back( + theProvider->ConnectInstanceCreated(std::bind(&STranslation::DoMarkDirty, + this, std::placeholders::_1))); + m_SignalConnections.push_back(theProvider->ConnectInstanceDeleted( + std::bind(&STranslation::ReleaseTranslation, this, std::placeholders::_1))); + m_SignalConnections.push_back( + theProvider->ConnectInstancePropertyValue(std::bind(&STranslation::DoMarkDirty, + this, std::placeholders::_1))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildAdded( + std::bind(&STranslation::MarkGraphInstanceDirty, this, std::placeholders::_1, + std::placeholders::_2))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildMoved( + std::bind(&STranslation::MarkGraphInstanceDirty, this, std::placeholders::_1, + std::placeholders::_2))); + m_SignalConnections.push_back(m_AssetGraph.ConnectChildRemoved( + std::bind(&STranslation::MarkGraphInstanceDirty, this, std::placeholders::_1, + std::placeholders::_2))); + m_SignalConnections.push_back(theProvider->ConnectBeginComponentSeconds( + std::bind(&STranslation::MarkBeginComponentSeconds, this, std::placeholders::_1))); + m_SignalConnections.push_back(theProvider->ConnectComponentSeconds( + std::bind(&STranslation::MarkComponentSeconds, this, std::placeholders::_1))); + + ::CColor color = CStudioPreferences::GetRulerBackgroundColor(); // Rectangles under tick marks + m_rectColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetRulerTickColor(); // Tick marks + m_lineColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideColor(); + m_guideColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideSelectedColor(); + m_selectedGuideColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideFillColor(); // Not sure what this is used for + m_guideFillColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); + color = CStudioPreferences::GetGuideFillSelectedColor(); // Not sure what this is used for + m_selectedGuideFillColor = QT3DSVec4(color.GetRed() / 255.f, + color.GetGreen() / 255.f, + color.GetBlue() / 255.f, + 1.f); +} + +void STranslation::BuildRenderGraph(SGraphObjectTranslator &inParent, bool scenePreviewPass, + Qt3DSDMInstanceHandle inAliasHandle) +{ + SGraphObjectTranslator &theParentTranslator(inParent); + theParentTranslator.ClearChildren(); + if (m_EditCameraEnabled && !scenePreviewPass) { + const auto objectType = theParentTranslator.GetGraphObject().m_Type; + if (objectType == GraphObjectTypes::Layer) { + theParentTranslator.AppendChild(m_EditCamera); + if (m_EditLightEnabled) { + m_EditLight.m_Parent = &m_EditCamera; + m_EditCamera.m_FirstChild = &m_EditLight; + } else { + m_EditCamera.m_FirstChild = nullptr; + m_EditLight.m_Parent = nullptr; + } + } else if (objectType == GraphObjectTypes::Light) { + m_editModeCamerasAndLights.push_back(&inParent); + } else if (objectType == GraphObjectTypes::Camera) { + m_editModeCamerasAndLights.push_back(&inParent); + } + } + + // Alias handles propagate down the scene graph. + if (inParent.GetInstanceHandle() != inParent.GetSceneGraphInstanceHandle()) + inAliasHandle = inParent.GetInstanceHandle(); + for (long idx = 0, end = m_AssetGraph.GetChildCount(inParent.GetSceneGraphInstanceHandle()); + idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theChild( + m_AssetGraph.GetChild(inParent.GetSceneGraphInstanceHandle(), idx)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theChild, inAliasHandle); + if (theTranslator == nullptr) + continue; + + // We we have edit cameras active, we only render the active layer and we remove any cameras + // in the active layer. Furthermore if our edit light is active, then we also remove any + // active lights in the layer. + if (m_EditCameraEnabled && !scenePreviewPass) { + if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Layer) { + if (theChild == m_Doc.GetActiveLayer()) { + if (m_EditCameraLayerTranslator != nullptr + && m_EditCameraLayerTranslator->GetInstanceHandle() != theChild) { + QT3DS_FREE(m_Allocator, m_EditCameraLayerTranslator); + m_EditCameraLayerTranslator = nullptr; + } + if (!m_EditCameraLayerTranslator) { + m_EditCameraLayerTranslator = + QT3DS_NEW(m_Allocator, SEditCameraLayerTranslator)(theChild, + m_Allocator); + } + theTranslator = m_EditCameraLayerTranslator; + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + BuildRenderGraph(*m_EditCameraLayerTranslator, scenePreviewPass); + } + } else { + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + BuildRenderGraph(theChild, scenePreviewPass, inAliasHandle); + + if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Effect) + theTranslator->SetActive(false); + else if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Camera) + theTranslator->SetActive(false); + else if (theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Light + && m_EditLightEnabled == true) + theTranslator->SetActive(false); + else + theTranslator->SetActive(m_Reader.IsCurrentlyActive(theChild)); + } + } else // Else build the graph and it will be an exact copy of the asset graph. + { + theParentTranslator.AppendChild(theTranslator->GetGraphObject()); + if (m_Reader.IsCurrentlyActive(theChild)) { + BuildRenderGraph(theChild, scenePreviewPass, inAliasHandle); + theTranslator->SetActive(true); + } else { + theTranslator->SetActive(false); + DeactivateScan(*theTranslator, inAliasHandle); + } + } + } + if (GraphObjectTypes::Layer == theParentTranslator.GetGraphObject().m_Type) + m_Context.GetRenderer().ChildrenUpdated( + static_cast<SLayer &>(theParentTranslator.GetGraphObject())); + + // Allow certain nodes to override their children. + theParentTranslator.AfterRenderGraphIsBuilt(*this); +} + +void STranslation::DeactivateScan(SGraphObjectTranslator &inParent, + Qt3DSDMInstanceHandle inAliasHandle) +{ + // Alias handles propagate down the scene graph. + if (inParent.GetInstanceHandle() != inParent.GetSceneGraphInstanceHandle()) + inAliasHandle = inParent.GetInstanceHandle(); + for (long idx = 0, end = m_AssetGraph.GetChildCount(inParent.GetSceneGraphInstanceHandle()); + idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theChild( + m_AssetGraph.GetChild(inParent.GetSceneGraphInstanceHandle(), idx)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theChild, inAliasHandle); + if (theTranslator == nullptr) + continue; + theTranslator->SetActive(false); + DeactivateScan(*theTranslator, inAliasHandle); + } +} + +// We build the render graph every time we render. This may seem wasteful +void STranslation::BuildRenderGraph(qt3dsdm::Qt3DSDMInstanceHandle inParent, bool scenePreviewPass, + Qt3DSDMInstanceHandle inAliasHandle) +{ + SGraphObjectTranslator *theParentTranslator = GetOrCreateTranslator(inParent, inAliasHandle); + if (theParentTranslator == nullptr) + return; + if (m_Reader.IsCurrentlyActive(inParent) == false) { + theParentTranslator->SetActive(false); + return; + } + BuildRenderGraph(*theParentTranslator, scenePreviewPass, inAliasHandle); +} + +void STranslation::ReleaseTranslation(Q3DStudio::TIdentifier inInstance) +{ + m_TranslatorMap.erase(inInstance); +} + +void STranslation::MarkDirty(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + // Anchor points are not handled individually. + if (m_Reader.GetObjectTypeName(inInstance) == L"PathAnchorPoint") + inInstance = m_AssetGraph.GetParent(inInstance); + GetOrCreateTranslator(inInstance); + + THandleTranslatorPairList &theTranslators = GetTranslatorsForInstance(inInstance); + for (size_t idx = 0, end = theTranslators.size(); idx < end; ++idx) { + m_DirtySet.insert(*theTranslators[(eastl::allocator::size_type)idx].second); + // Reset effect when effect parameters change, as with certain corner cases + // some effects would accumulate ~infinitely and result would not reflect + // actual parameter setting unless reset (f.ex corona, other blur types) + m_DirtySet.back()->ResetEffect(); + } + RequestRender(); +} + +QT3DSVec2 STranslation::GetPreviewViewportDimensions() const +{ + CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); + QSize thePresSize = theSettings->getPresentationSize(); + return QT3DSVec2(thePresSize.width(), thePresSize.height()); +} + +qt3ds::QT3DSVec2 STranslation::GetOverlayPreviewDimensions() const +{ + QT3DSVec2 ret(0.0f); + if (hasRoomForOverlayPreview()) { + CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); + QSize thePresSize = theSettings->getPresentationSize(); + ret = QT3DSVec2(thePresSize.width(), thePresSize.height()); + + const float aspect = ret.x / ret.y; + if (aspect > 1.0) { + ret.x = m_overlayPreviewSize > ret.x ? ret.x : m_overlayPreviewSize; + ret.y = ret.x / aspect; + } else { + ret.y = m_overlayPreviewSize > ret.y ? ret.y : m_overlayPreviewSize; + ret.x = ret.y * aspect; + } + } + return ret; +} + +void STranslation::PreRender(bool scenePreviewPass) +{ + // Run through the entire asset graph and mark active or inactive if we have an + // associated render representation. + // If we cache all the components and some of their state then we don't have to do this + // but for now it is more stable to run through the graph. + // There is always one root, the scene. + TIdentifier theRoot = m_AssetGraph.GetRoot(0); + if (!scenePreviewPass) + m_editModeCamerasAndLights.clear(); + ClearDirtySet(); + m_EditLightEnabled = CStudioPreferences::editModeLightingEnabled(); + BuildRenderGraph(theRoot, scenePreviewPass); + QT3DSVec2 theViewportDims(GetViewportDimensions()); + if (scenePreviewPass) { + m_Context.SetScaleMode(qt3ds::render::ScaleModes::FitSelected); + theViewportDims = GetPreviewViewportDimensions(); + } else { + m_Context.SetScaleMode(qt3ds::render::ScaleModes::ExactSize); + } + + static const QT3DSVec4 matteColor(CStudioPreferences::matteColor().redF(), + CStudioPreferences::matteColor().greenF(), + CStudioPreferences::matteColor().blueF(), 1.0f); + m_Context.SetMatteColor(matteColor); + // Ensure the camera points where it should + if (m_EditCameraEnabled && !scenePreviewPass) { + m_EditCameraInfo.ApplyToCamera(m_EditCamera, theViewportDims); + m_EditLight.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); + } + + if (m_Scene) { + CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); + QSize thePresSize = theSettings->getPresentationSize(); + // The presentation sizes are used for when we have to render a layer offscreen. + // If their width and height isn't set, then they use the presentation dimensions. + m_Presentation.m_PresentationDimensions + = QT3DSVec2((QT3DSF32)thePresSize.width(), (QT3DSF32)thePresSize.height()); + m_Context.SetWindowDimensions( + QSize((QT3DSU32)theViewportDims.x, (QT3DSU32)theViewportDims.y)); + m_Context.SetPresentationDimensions( + QSize((QT3DSU32)m_Presentation.m_PresentationDimensions.x, + (QT3DSU32)m_Presentation.m_PresentationDimensions.y)); + + // set if we draw geometry in wireframe mode + m_Context.SetWireframeMode(CStudioPreferences::IsWireframeModeOn()); + + if (m_EditCameraEnabled && !scenePreviewPass) { + m_Presentation.m_PresentationDimensions = theViewportDims; + m_Context.SetPresentationDimensions( + QSize((QT3DSU32)theViewportDims.x, (QT3DSU32)theViewportDims.y)); + m_Context.SetSceneColor(QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f)); + } else { + + TIdentifier theRoot = m_AssetGraph.GetRoot(0); + SGraphObjectTranslator *theSceneTranslator = GetOrCreateTranslator(theRoot); + if (theSceneTranslator) { + SScene &theScene = static_cast<SScene &>(theSceneTranslator->GetGraphObject()); + if (scenePreviewPass) { + if (theScene.m_UseClearColor) + m_Context.SetMatteColor(theScene.m_ClearColor); + else + m_Context.SetMatteColor(QT3DSVec4(0.0f, 0.0f, 0.0f, 1.0f)); + } else { + if (theScene.m_UseClearColor) + m_Context.SetSceneColor(theScene.m_ClearColor); + else + m_Context.SetSceneColor(QT3DSVec4(QT3DSVec3(0.0f), 1.0f)); + } + } + } + } + if (m_EditCameraEnabled == false && g_StudioApp.IsAuthorZoom()) { + if (m_Presentation.m_PresentationDimensions.x > theViewportDims.x + || m_Presentation.m_PresentationDimensions.y > theViewportDims.y) { + m_Context.SetScaleMode(qt3ds::render::ScaleModes::FitSelected); + } + } +} + +static void CreatePixelRect(STranslation &inTranslation, QT3DSF32 left, QT3DSF32 right, QT3DSF32 bottom, + QT3DSF32 top, QT3DSVec4 color) +{ + SPGRect *theRect = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGRect)(); + theRect->m_Left = left; + theRect->m_Right = right; + theRect->m_Top = top; + theRect->m_Bottom = bottom; + theRect->m_FillColor = color; + inTranslation.m_GuideContainer.push_back(theRect); +} + +static void CreatePixelVertLine(STranslation &inTranslation, QT3DSF32 inXPos, QT3DSF32 inBottom, + QT3DSF32 inTop, QT3DSVec4 color) +{ + SPGVertLine *theLine = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGVertLine)(); + theLine->m_X = inXPos; + theLine->m_Bottom = inBottom; + theLine->m_Top = inTop; + theLine->m_LineColor = color; + inTranslation.m_GuideContainer.push_back(theLine); +} + +static void CreatePixelHorzLine(STranslation &inTranslation, QT3DSF32 inYPos, QT3DSF32 inLeft, + QT3DSF32 inRight, QT3DSVec4 color) +{ + SPGHorzLine *theLine = QT3DS_NEW(inTranslation.m_GuideAllocator, SPGHorzLine)(); + theLine->m_Y = inYPos; + theLine->m_Left = inLeft; + theLine->m_Right = inRight; + theLine->m_LineColor = color; + inTranslation.m_GuideContainer.push_back(theLine); +} + +static void CreateTopBottomTickMarks(STranslation &inTranslation, QT3DSF32 posX, QT3DSF32 innerBottom, + QT3DSF32 innerTop, QT3DSF32 outerBottom, QT3DSF32 outerTop, + QT3DSF32 lineHeight, QT3DSVec4 lineColor) +{ + CreatePixelVertLine(inTranslation, posX, innerBottom - lineHeight, innerBottom, lineColor); + CreatePixelVertLine(inTranslation, posX, innerTop, innerTop + lineHeight, lineColor); +} + +static void DrawTickMarksOnHorizontalRects(STranslation &inTranslation, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 innerBottom, QT3DSF32 innerTop, + QT3DSF32 outerBottom, QT3DSF32 outerTop, QT3DSVec4 lineColor) +{ + QT3DSF32 centerPosX = floor(innerLeft + (innerRight - innerLeft) / 2.0f + .5f); + CreateTopBottomTickMarks(inTranslation, centerPosX, innerBottom, innerTop, outerBottom, + outerTop, 15, lineColor); + for (QT3DSU32 incrementor = 10; + (centerPosX + incrementor) < innerRight && (centerPosX - incrementor) > innerLeft; + incrementor += 10) { + QT3DSF32 rightEdge = centerPosX + incrementor; + QT3DSF32 leftEdge = centerPosX - incrementor; + QT3DSF32 lineHeight = 0; + if (incrementor % 100 == 0) + lineHeight = 11; + else if (incrementor % 20) + lineHeight = 4; + else + lineHeight = 2; + + if (rightEdge < innerRight) + CreateTopBottomTickMarks(inTranslation, rightEdge, innerBottom, innerTop, outerBottom, + outerTop, lineHeight, lineColor); + if (leftEdge > innerLeft) + CreateTopBottomTickMarks(inTranslation, leftEdge, innerBottom, innerTop, outerBottom, + outerTop, lineHeight, lineColor); + } +} + +static void CreateLeftRightTickMarks(STranslation &inTranslation, QT3DSF32 inYPos, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 outerLeft, QT3DSF32 outerRight, + QT3DSF32 lineLength, QT3DSVec4 lineColor) +{ + CreatePixelHorzLine(inTranslation, inYPos, innerLeft - lineLength, innerLeft, lineColor); + CreatePixelHorzLine(inTranslation, inYPos, innerRight, innerRight + lineLength, lineColor); +} + +static void DrawTickMarksOnVerticalRects(STranslation &inTranslation, QT3DSF32 innerLeft, + QT3DSF32 innerRight, QT3DSF32 innerBottom, QT3DSF32 innerTop, + QT3DSF32 outerLeft, QT3DSF32 outerRight, QT3DSVec4 lineColor) +{ + QT3DSF32 centerPosY = floor(innerBottom + (innerTop - innerBottom) / 2.0f + .5f); + CreateLeftRightTickMarks(inTranslation, centerPosY, innerLeft, innerRight, outerLeft, + outerRight, 15, lineColor); + for (QT3DSU32 incrementor = 10; + (centerPosY + incrementor) < innerTop && (centerPosY - incrementor) > innerBottom; + incrementor += 10) { + QT3DSF32 topEdge = centerPosY + incrementor; + QT3DSF32 bottomEdge = centerPosY - incrementor; + QT3DSF32 lineHeight = 0; + if (incrementor % 100 == 0) + lineHeight = 11; + else if (incrementor % 20) + lineHeight = 4; + else + lineHeight = 2; + + if (topEdge < innerTop) + CreateLeftRightTickMarks(inTranslation, topEdge, innerLeft, innerRight, outerLeft, + outerRight, lineHeight, lineColor); + if (bottomEdge > innerBottom) + CreateLeftRightTickMarks(inTranslation, bottomEdge, innerLeft, innerRight, outerLeft, + outerRight, lineHeight, lineColor); + } +} + +class IGuideElementFactory +{ +protected: + virtual ~IGuideElementFactory() {} +public: + virtual void CreateLine(QT3DSF32 inPos) = 0; + virtual void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) = 0; +}; + +static void CreateGuide(IGuideElementFactory &inFactory, QT3DSF32 inPos, QT3DSF32 inWidth) +{ + QT3DSF32 halfWidth = inWidth / 2.0f; + QT3DSF32 leftLine = floor(inPos + 1.0f - halfWidth); + inFactory.CreateLine(leftLine); + // Then we are done if not enough width + if (inWidth < 2.0f) + return; + + QT3DSF32 rightLine = leftLine + inWidth - 1; + inFactory.CreateLine(rightLine); + + if (inWidth < 3.0f) + return; + QT3DSF32 rectStart = leftLine + 1; + QT3DSF32 rectStop = rectStart + inWidth - 2.0f; + inFactory.CreateRect(rectStart, rectStop); +} + +struct SHorizontalGuideFactory : public IGuideElementFactory +{ + STranslation &m_Translation; + QT3DSF32 m_Start; + QT3DSF32 m_Stop; + QT3DSVec4 m_LineColor; + QT3DSVec4 m_FillColor; + SHorizontalGuideFactory(STranslation &trans, QT3DSF32 start, QT3DSF32 stop, QT3DSVec4 lineColor, + QT3DSVec4 fillColor) + : m_Translation(trans) + , m_Start(start) + , m_Stop(stop) + , m_LineColor(lineColor) + , m_FillColor(fillColor) + { + } + void CreateLine(QT3DSF32 inPos) override + { + CreatePixelHorzLine(m_Translation, inPos, m_Start, m_Stop, m_LineColor); + } + + void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) override + { + CreatePixelRect(m_Translation, m_Start, m_Stop, inPosMin, inPosMax, m_FillColor); + } +}; + +struct SVerticalGuideFactory : public IGuideElementFactory +{ + STranslation &m_Translation; + QT3DSF32 m_Start; + QT3DSF32 m_Stop; + QT3DSVec4 m_LineColor; + QT3DSVec4 m_FillColor; + SVerticalGuideFactory(STranslation &trans, QT3DSF32 start, QT3DSF32 stop, QT3DSVec4 lineColor, + QT3DSVec4 fillColor) + : m_Translation(trans) + , m_Start(start) + , m_Stop(stop) + , m_LineColor(lineColor) + , m_FillColor(fillColor) + { + } + void CreateLine(QT3DSF32 inPos) override + { + CreatePixelVertLine(m_Translation, inPos, m_Start, m_Stop, m_LineColor); + } + + void CreateRect(QT3DSF32 inPosMin, QT3DSF32 inPosMax) override + { + CreatePixelRect(m_Translation, inPosMin, inPosMax, m_Start, m_Stop, m_FillColor); + } +}; + +qt3ds::render::NVRenderRect STranslation::GetPreviewViewport() const +{ + QT3DSVec2 vp = GetPreviewViewportDimensions(); + return qt3ds::render::NVRenderRect(0, 0, vp.x, vp.y); +} + +qt3ds::render::NVRenderRect STranslation::GetOverlayPreviewViewport() const +{ + QT3DSVec2 vp = GetOverlayPreviewDimensions(); + return qt3ds::render::NVRenderRect(0, 0, vp.x, vp.y); +} + +bool STranslation::hasRoomForOverlayPreview() const +{ + QT3DSVec2 vp(GetViewportDimensions()); + return vp.x > m_overlayPreviewSize && vp.y > m_overlayPreviewSize; +} + +void STranslation::Render(int inWidgetId, bool inDrawGuides, bool scenePreviewPass, + bool overlayPreview) +{ + // For now, we just render. + // Next step will be to get the bounding boxes and such setup. + // but we will want a custom renderer to do that. + if (m_Scene) { + // Note that begin frame is called before we allocate the bounding box and axis widgets so + // that we can take advantage of the renderer's per-frame-allocator. + m_Context.BeginFrame(true); + + qt3dsdm::TInstanceHandleList theHandles = m_Doc.GetSelectedValue().GetSelectedInstances(); + + if (scenePreviewPass) { + qt3ds::render::NVRenderContext &renderContext(m_Context.GetRenderContext()); + QT3DSVec2 previewDims(GetPreviewViewportDimensions()); + if (m_previewFboDimensions != previewDims) { + m_previewFboDimensions = previewDims; + if (m_previewFbo) + m_Context.GetResourceManager().Release(*m_previewFbo); + if (m_previewRenderBuffer) + m_Context.GetResourceManager().Release(*m_previewRenderBuffer); + if (m_previewTexture) + m_Context.GetResourceManager().Release(*m_previewTexture); + m_previewFbo = nullptr; + m_previewRenderBuffer = nullptr; + m_previewTexture = nullptr; + } + if (!m_previewFbo) + m_previewFbo = m_Context.GetResourceManager().AllocateFrameBuffer(); + if (!m_previewTexture) { + m_previewTexture = renderContext.CreateTexture2D(); + m_previewTexture->SetTextureData(qt3ds::foundation::NVDataRef<qt3ds::QT3DSU8>(), + 0, previewDims.x, previewDims.y, + qt3ds::render::NVRenderTextureFormats::RGBA8); + m_previewFbo->Attach( + qt3ds::render::NVRenderFrameBufferAttachments::Color0, + qt3ds::render::NVRenderTextureOrRenderBuffer(*m_previewTexture)); + } + if (!m_previewRenderBuffer) { + m_previewRenderBuffer = m_Context.GetResourceManager().AllocateRenderBuffer( + previewDims.x, previewDims.y, + qt3ds::render::NVRenderRenderBufferFormats::Depth24); + m_previewFbo->Attach( + qt3ds::render::NVRenderFrameBufferAttachments::Depth, + qt3ds::render::NVRenderTextureOrRenderBuffer(*m_previewRenderBuffer)); + } + renderContext.SetRenderTarget(m_previewFbo); + } else { + // Render the bounding boxes and extra widgets. + // This is called *before* the render because these sort of appendages need to be added + // to the layer renderables. + + // Don't show the bounding box or pivot for the component we are *in* the component + SGraphObjectTranslator *theTranslator = nullptr; + long theToolMode = g_StudioApp.GetToolMode(); + int theCameraToolMode = m_EditCameraEnabled + ? (theToolMode & STUDIO_CAMERATOOL_MASK) : 0; + bool shouldDisplayWidget = false; + if (theCameraToolMode == 0) { + switch (theToolMode) { + default: + break; + case STUDIO_TOOLMODE_MOVE: + case STUDIO_TOOLMODE_ROTATE: + case STUDIO_TOOLMODE_SCALE: + shouldDisplayWidget = true; + break; + }; + } + + bool selectedPath = false; + + for (size_t selectedIdx = 0, selectedEnd = theHandles.size(); selectedIdx < selectedEnd; + ++selectedIdx) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance = theHandles[selectedIdx]; + if (theInstance + != m_Doc.GetDocumentReader().GetComponentForSlide(m_Doc.GetActiveSlide())) { + if (m_Doc.GetDocumentReader().GetObjectTypeName(theInstance) + == L"PathAnchorPoint") { + theInstance = m_AssetGraph.GetParent(m_AssetGraph.GetParent(theInstance)); + shouldDisplayWidget = false; + } + theTranslator = GetOrCreateTranslator(theInstance); + // Get the tool mode right now. + if (theTranslator) { + GraphObjectTypes::Enum theType(theTranslator->GetGraphObject().m_Type); + if (CStudioPreferences::IsBoundingBoxesOn()) { + switch (theType) { + case GraphObjectTypes::Node: + DrawGroupBoundingBoxes(*theTranslator); + break; + case GraphObjectTypes::Text: + case GraphObjectTypes::Model: + case GraphObjectTypes::Layer: + case GraphObjectTypes::Light: + case GraphObjectTypes::Path: + DrawNonGroupBoundingBoxes(*theTranslator); + break; + default: + break; + } + } + + // Don't draw the axis if there is a widget. + if (CStudioPreferences::ShouldDisplayPivotPoint()) { + switch (theTranslator->GetGraphObject().m_Type) { + case GraphObjectTypes::Node: + case GraphObjectTypes::Text: + case GraphObjectTypes::Model: + drawPivot(*theTranslator); + break; + default: + break; + } + } + + if (theType == GraphObjectTypes::Path && selectedPath == false) { + selectedPath = true; + if (!m_PathWidget) { + m_PathWidget = qt3ds::widgets::IPathWidget::CreatePathWidget( + m_Context.GetAllocator(), m_Context); + } + m_PathWidget->SetNode( + static_cast<SNode &>(theTranslator->GetGraphObject())); + m_Context.GetRenderer().AddRenderWidget(*m_PathWidget); + } + } + } + } + + if (theHandles.size() > 1) + theTranslator = nullptr; + + qt3ds::widgets::IStudioWidget *theNextWidget(nullptr); + if (theTranslator + && GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) + && theTranslator->GetGraphObject().m_Type != GraphObjectTypes::Layer) { + + qt3ds::render::SNode &theNode( + static_cast<qt3ds::render::SNode &>(theTranslator->GetGraphObject())); + const GraphObjectTypes::Enum type = theTranslator->GetGraphObject().m_Type; + + // Don't draw widgets for non-visible nodes + bool isActive = theNode.m_Flags.IsActive(); + // Light and camera nodes are never active, so check from doc + if (type == GraphObjectTypes::Camera || type == GraphObjectTypes::Light) + isActive = m_Reader.IsCurrentlyActive(theHandles[0]); + shouldDisplayWidget = shouldDisplayWidget && isActive; + + SCamera *theRenderCamera = m_Context.GetRenderer().GetCameraForNode(theNode); + bool isActiveCamera = theRenderCamera == (static_cast<SCamera *>(&theNode)); + if (shouldDisplayWidget && !isActiveCamera + && ((type == GraphObjectTypes::Camera && m_EditCameraEnabled) + || type != GraphObjectTypes::Camera)) { + switch (theToolMode) { + default: + QT3DS_ASSERT(false); + break; + case STUDIO_TOOLMODE_MOVE: + // Render translation widget + if (!m_TranslationWidget) { + m_TranslationWidget + = qt3ds::widgets::IStudioWidget::CreateTranslationWidget( + m_Context.GetAllocator()); + } + theNextWidget = m_TranslationWidget.mPtr; + break; + case STUDIO_TOOLMODE_ROTATE: + if (!m_RotationWidget) { + m_RotationWidget = qt3ds::widgets::IStudioWidget::CreateRotationWidget( + m_Context.GetAllocator()); + } + theNextWidget = m_RotationWidget.mPtr; + break; + + case STUDIO_TOOLMODE_SCALE: + if (!m_ScaleWidget) { + m_ScaleWidget = qt3ds::widgets::IStudioWidget::CreateScaleWidget( + m_Context.GetAllocator()); + } + theNextWidget = m_ScaleWidget.mPtr; + break; + } + + if (theNextWidget) { + SNode &node = static_cast<SNode &>(theTranslator->GetGraphObject()); + theNextWidget->SetNode(node); + m_Context.GetRenderer().AddRenderWidget(*theNextWidget); + } + } + } + if (m_LastRenderedWidget.mPtr && m_LastRenderedWidget.mPtr != theNextWidget) + ResetWidgets(); + + m_LastRenderedWidget = theNextWidget; + if (m_LastRenderedWidget) { + m_LastRenderedWidget->SetSubComponentId(inWidgetId); + switch (g_StudioApp.GetManipulationMode()) { + case StudioManipulationModes::Local: + m_LastRenderedWidget->SetRenderWidgetMode( + qt3ds::render::RenderWidgetModes::Local); + break; + case StudioManipulationModes::Global: + m_LastRenderedWidget->SetRenderWidgetMode( + qt3ds::render::RenderWidgetModes::Global); + break; + default: + QT3DS_ASSERT(false); + break; + } + } + } + Option<NVRenderRect> viewport = m_Context.GetRenderContext().GetViewport(); + if (scenePreviewPass) { + m_Context.GetRenderContext().SetViewport(GetPreviewViewport()); + m_Context.SetSceneColor(Option<QT3DSVec4>()); + } + + m_Scene->PrepareForRender(scenePreviewPass ? GetPreviewViewportDimensions() + : GetViewportDimensions(), m_Context); + + m_Context.RunRenderTasks(); + + if (!scenePreviewPass && m_EditCameraEnabled) { + if (m_GradientWidget == nullptr) + m_GradientWidget = qt3ds::widgets::SGradientWidget + ::CreateGradientWidget(m_Context.GetAllocator()); + // render gradient background + SNode *node = GetEditCameraLayer(); + m_GradientWidget->SetNode(*node); + m_GradientWidget->Render(m_Context.GetRenderWidgetContext(), + m_Context.GetRenderContext(), + m_EditCameraInfo.IsOrthographic()); + } + + m_Scene->Render(scenePreviewPass + ? GetPreviewViewportDimensions() + : GetViewportDimensions(), m_Context, SScene::DoNotClear); + + if (!scenePreviewPass && m_editModeCamerasAndLights.size() > 0) { + if (!m_VisualAidWidget) { + m_VisualAidWidget = qt3ds::widgets::SVisualAidWidget + ::CreateVisualAidWidget(m_Context.GetAllocator()); + } + for (SGraphObjectTranslator *translator : m_editModeCamerasAndLights) { + SGraphObject &object = translator->GetGraphObject(); + qt3dsdm::Qt3DSDMInstanceHandle handle = translator->GetInstanceHandle(); + m_VisualAidWidget->setSelected(false); + + for (int j = 0; j < theHandles.size(); ++j) { + if (handle == theHandles[j]) { + m_VisualAidWidget->setSelected(true); + break; + } + } + + if (object.m_Type == GraphObjectTypes::Camera) { + if (m_InnerRect.isNull()) { + // this happens when the initial view is not the camera view + NVRenderRect thePresentationViewport = m_Context.GetPresentationViewport(); + m_InnerRect.m_Left = thePresentationViewport.m_X; + m_InnerRect.m_Right = thePresentationViewport.m_X + + thePresentationViewport.m_Width; + m_InnerRect.m_Bottom = thePresentationViewport.m_Y; + m_InnerRect.m_Top = thePresentationViewport.m_Y + + thePresentationViewport.m_Height; + } + + QT3DSVec2 dim = QT3DSVec2(m_InnerRect.m_Right - m_InnerRect.m_Left, + m_InnerRect.m_Top - m_InnerRect.m_Bottom); + NVRenderRectF theViewport(0, 0, dim.x, dim.y); + static_cast<SCamera *>(&object)->CalculateGlobalVariables(theViewport, dim); + } + m_VisualAidWidget->SetNode(static_cast<SNode *>(&object)); + m_VisualAidWidget->Render(m_Context.GetRenderWidgetContext(), + m_Context.GetRenderContext()); + } + } + + if (inDrawGuides && !m_EditCameraEnabled && !g_StudioApp.IsAuthorZoom()) { + m_GuideContainer.clear(); + // Figure out the matte area. + NVRenderRect theContextViewport = m_Context.GetContextViewport(); + NVRenderRect thePresentationViewport = m_Context.GetPresentationViewport(); + m_Context.GetRenderContext().SetViewport(theContextViewport); + QT3DSI32 innerLeft = thePresentationViewport.m_X; + QT3DSI32 innerRight = thePresentationViewport.m_X + thePresentationViewport.m_Width; + QT3DSI32 innerBottom = thePresentationViewport.m_Y; + QT3DSI32 innerTop = thePresentationViewport.m_Y + thePresentationViewport.m_Height; + + QT3DSI32 outerLeft = innerLeft - 16; + QT3DSI32 outerRight = innerRight + 16; + QT3DSI32 outerBottom = innerBottom - 16; + QT3DSI32 outerTop = innerTop + 16; + // Retain the rects for picking purposes. + m_InnerRect = SRulerRect(innerLeft, innerTop, innerRight, innerBottom); + m_OuterRect = SRulerRect(outerLeft, outerTop, outerRight, outerBottom); + + // Draw tick marks around the presentation + CreatePixelRect(*this, (QT3DSF32)outerLeft, (QT3DSF32)innerLeft, (QT3DSF32)innerBottom, + (QT3DSF32)innerTop, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerRight, (QT3DSF32)outerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, (QT3DSF32)outerBottom, + (QT3DSF32)innerBottom, m_rectColor); + CreatePixelRect(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, (QT3DSF32)innerTop, + (QT3DSF32)outerTop, m_rectColor); + DrawTickMarksOnHorizontalRects(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + (QT3DSF32)outerBottom, (QT3DSF32)outerTop, m_lineColor); + DrawTickMarksOnVerticalRects(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + (QT3DSF32)outerLeft, (QT3DSF32)outerRight, m_lineColor); + qt3dsdm::TGuideHandleList theGuides = m_Doc.GetDocumentReader().GetGuides(); + qt3dsdm::Qt3DSDMGuideHandle theSelectedGuide; + Q3DStudio::SSelectedValue theSelection = m_Doc.GetSelectedValue(); + if (theSelection.getType() == Q3DStudio::SelectedValueTypes::Guide) + theSelectedGuide = theSelection.getData<qt3dsdm::Qt3DSDMGuideHandle>(); + + // Draw guides + for (size_t guideIdx = 0, guideEnd = theGuides.size(); guideIdx < guideEnd; + ++guideIdx) { + qt3dsdm::SGuideInfo theInfo = + m_Doc.GetDocumentReader().GetGuideInfo(theGuides[guideIdx]); + bool isGuideSelected = theGuides[guideIdx] == theSelectedGuide; + QT3DSVec4 theColor = isGuideSelected ? m_selectedGuideColor : m_guideColor; + QT3DSVec4 theFillColor = isGuideSelected ? m_selectedGuideFillColor + : m_guideFillColor; + switch (theInfo.m_Direction) { + case qt3dsdm::GuideDirections::Horizontal: { + SHorizontalGuideFactory theFactory(*this, (QT3DSF32)innerLeft, (QT3DSF32)innerRight, + theColor, theFillColor); + CreateGuide(theFactory, (QT3DSF32)m_InnerRect.m_Bottom + theInfo.m_Position, + (QT3DSF32)theInfo.m_Width); + } break; + case qt3dsdm::GuideDirections::Vertical: { + SVerticalGuideFactory theFactory(*this, (QT3DSF32)innerBottom, (QT3DSF32)innerTop, + theColor, theFillColor); + CreateGuide(theFactory, (QT3DSF32)m_InnerRect.m_Left + theInfo.m_Position, + (QT3DSF32)theInfo.m_Width); + } break; + default: + QT3DS_ASSERT(false); + break; + } + } + m_Context.GetPixelGraphicsRenderer().Render( + qt3ds::foundation::toDataRef(m_GuideContainer.data(), m_GuideContainer.size())); + + m_GuideContainer.clear(); + m_GuideAllocator.reset(); + } + + if (!scenePreviewPass && m_previewTexture) { + if (overlayPreview) { + // Draw the overlay framebuffer + qt3ds::render::NVRenderContext &renderContext(m_Context.GetRenderContext()); + renderContext.SetViewport(GetOverlayPreviewViewport()); + qt3ds::render::SCamera camera; + camera.MarkDirty(qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty); + camera.m_Flags.SetOrthographic(true); + QT3DSVec2 previewDims(GetOverlayPreviewDimensions()); + camera.CalculateGlobalVariables( + render::NVRenderRectF(0, 0, previewDims.x, previewDims.y), previewDims); + QT3DSMat44 theVP; + camera.CalculateViewProjectionMatrix(theVP); + renderContext.SetCullingEnabled(false); + renderContext.SetBlendingEnabled(false); + renderContext.SetDepthTestEnabled(false); + renderContext.SetDepthWriteEnabled(false); + m_Context.GetRenderer().RenderQuad(previewDims, theVP, *m_previewTexture); + } else { + // Hack: For some reason, the m_previewTexture is only valid later if it is + // actually drawn somewhere during the main render pass, so draw a dummy quad + m_Context.GetRenderContext().SetViewport(NVRenderRect(0, 0, 0, 0)); + m_Context.GetRenderer().RenderQuad(QT3DSVec2(0.0f), QT3DSMat44(), + *m_previewTexture); + } + } + + if (scenePreviewPass) + m_Context.GetRenderContext().SetRenderTarget(nullptr); + + m_Context.EndFrame(); + m_Context.GetRenderContext().SetViewport(viewport); + QT3DSVec2 theViewportDims(GetViewportDimensions()); + m_Context.SetWindowDimensions(QSize((QT3DSU32)theViewportDims.x, + (QT3DSU32)theViewportDims.y)); + CStudioProjectSettings *theSettings = m_Doc.GetCore()->GetStudioProjectSettings(); + QSize thePresSize = theSettings->getPresentationSize(); + m_Presentation.m_PresentationDimensions = + QT3DSVec2((QT3DSF32)thePresSize.width(), (QT3DSF32)thePresSize.height()); + + if (m_ZoomRender.hasValue()) { + RenderZoomRender(*m_ZoomRender); + m_ZoomRender = Empty(); + } + + // Render the pick buffer, useful for debugging why a widget wasn't hit. + /* + if ( m_PickBuffer ) + { + qt3ds::render::NVRenderContext& theRenderContext( m_Context.GetRenderContext() ); + qt3ds::render::STextureDetails thePickDetails = m_PickBuffer->GetTextureDetails(); + theRenderContext.SetViewport( qt3ds::render::NVRenderRect( 0, 0, thePickDetails.m_Width, + thePickDetails.m_Height ) ); + qt3ds::render::SCamera theCamera; + theCamera.MarkDirty( qt3ds::render::NodeTransformDirtyFlag::TransformIsDirty ); + theCamera.m_Flags.SetOrthographic( true ); + QT3DSVec2 theDimensions( (QT3DSF32)thePickDetails.m_Width, (QT3DSF32)thePickDetails.m_Height ); + theCamera.CalculateGlobalVariables( render::NVRenderRectF( 0, 0, theDimensions.x, + theDimensions.y ), theDimensions ); + QT3DSMat44 theVP; + theCamera.CalculateViewProjectionMatrix( theVP ); + theRenderContext.SetCullingEnabled( false ); + theRenderContext.SetBlendingEnabled( false ); + theRenderContext.SetDepthTestEnabled( false ); + theRenderContext.SetDepthWriteEnabled( false ); + m_Context.GetRenderer().RenderQuad( theDimensions, theVP, *m_PickBuffer ); + }*/ + } +} + +void STranslation::ResetWidgets() +{ + if (m_ScaleWidget) + m_ScaleWidget->SetAxisScale(QT3DSVec3(1, 1, 1)); + if (m_RotationWidget) + m_RotationWidget->ClearRotationEdges(); + m_CumulativeRotation = 0.0f; +} + +void STranslation::DoPrepareForDrag(SNode *inSelectedNode) +{ + if (inSelectedNode == nullptr) + return; + + m_MouseDownNode = *inSelectedNode; + m_MouseDownParentGlobalTransformInverse = Empty(); + m_MouseDownParentRotationInverse = Empty(); + m_MouseDownGlobalRotation = Empty(); + // Orphan this node manually since it is a straight copy + m_MouseDownNode.m_Parent = nullptr; + m_MouseDownNode.m_FirstChild = nullptr; + m_MouseDownNode.m_NextSibling = nullptr; + SCamera *theCamera = m_Context.GetRenderer().GetCameraForNode(*inSelectedNode); + m_CumulativeRotation = 0.0f; + if (theCamera == nullptr) + return; + m_MouseDownCamera = *theCamera; + m_LastPathDragValue = Empty(); +} + +void STranslation::EndDrag() +{ + ResetWidgets(); +} + +bool STranslation::IsPathWidgetActive() +{ + qt3dsdm::TInstanceHandleList theHandles = m_Doc.GetSelectedValue().GetSelectedInstances(); + for (size_t selectedIdx = 0, selectedEnd = theHandles.size(); selectedIdx < selectedEnd; + ++selectedIdx) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance(theHandles[selectedIdx]); + if (m_Doc.GetDocumentReader().GetObjectTypeName(theInstance) == L"PathAnchorPoint") + theInstance = m_AssetGraph.GetParent(m_AssetGraph.GetParent(theInstance)); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(theInstance); + if (theTranslator && theTranslator->GetGraphObject().m_Type == GraphObjectTypes::Path) + return true; + } + return false; +} + +inline qt3ds::render::SLayer *GetLayerForNode(const qt3ds::render::SNode &inNode) +{ + SNode *theNode; + // empty loop intentional + for (theNode = const_cast<SNode *>(&inNode); + theNode && theNode->m_Type != GraphObjectTypes::Layer; theNode = theNode->m_Parent) { + } + if (theNode && theNode->m_Type == GraphObjectTypes::Layer) + return static_cast<SLayer *>(theNode); + return nullptr; +} + +void STranslation::RenderZoomRender(SZoomRender &inRender) +{ + SLayer *theLayer(inRender.m_Layer); + CPt thePoint(inRender.m_Point); + if (theLayer) { + qt3ds::render::IQt3DSRenderer &theRenderer(m_Context.GetRenderer()); + Option<qt3ds::render::SLayerPickSetup> thePickSetup( + theRenderer.GetLayerPickSetup(*theLayer, QT3DSVec2((QT3DSF32)thePoint.x, (QT3DSF32)thePoint.y), + QSize(16, 16))); + if (thePickSetup.hasValue()) { + qt3ds::render::NVRenderContext &theRenderContext(m_Context.GetRenderContext()); + theRenderContext.SetViewport(qt3ds::render::NVRenderRect(0, 0, 100, 100)); + theRenderContext.SetScissorRect(qt3ds::render::NVRenderRect(0, 0, 100, 100)); + theRenderContext.SetDepthWriteEnabled(true); + theRenderContext.SetScissorTestEnabled(true); + theRenderContext.SetClearColor(QT3DSVec4(.2f, .2f, .2f, 0.0f)); + theRenderContext.Clear(qt3ds::render::NVRenderClearFlags( + qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); + theRenderer.RunLayerRender(*theLayer, thePickSetup->m_ViewProjection); + theRenderContext.SetScissorTestEnabled(false); + } + } +} + +void STranslation::DrawBoundingBox(SNode &inNode, QT3DSVec3 inColor) +{ + qt3ds::NVBounds3 theBounds = inNode.GetBounds(m_Context.GetBufferManager(), + m_Context.GetPathManager(), true, this); + qt3ds::render::IRenderWidget &theBBoxWidget = qt3ds::render::IRenderWidget::CreateBoundingBoxWidget( + inNode, theBounds, inColor, m_Context.GetRenderer().GetPerFrameAllocator()); + m_Context.GetRenderer().AddRenderWidget(theBBoxWidget); +} + +void STranslation::drawPivot(SGraphObjectTranslator &inTranslator) +{ + if (GraphObjectTypes::IsNodeType(inTranslator.GetGraphObject().m_Type)) { + qt3ds::render::IRenderWidget &theAxisWidget = qt3ds::render::IRenderWidget::CreateAxisWidget( + static_cast<SNode &>(inTranslator.GetGraphObject()), + m_Context.GetRenderer().GetPerFrameAllocator()); + m_Context.GetRenderer().AddRenderWidget(theAxisWidget); + } else { + QT3DS_ASSERT(false); + } +} + +void STranslation::SetViewport(qt3ds::QT3DSF32 inWidth, qt3ds::QT3DSF32 inHeight) +{ + m_Viewport = QT3DSVec2(inWidth, inHeight); + if (m_EditCameraEnabled) { + // Update inner rect as it is used to calculate camera frustrum for visual aid widget + QSize theSize = g_StudioApp.GetCore()->GetStudioProjectSettings()->getPresentationSize(); + m_InnerRect.m_Top = 0; + m_InnerRect.m_Bottom = theSize.height(); + m_InnerRect.m_Left = 0; + m_InnerRect.m_Right = theSize.width(); + } +} + +Option<QT3DSU32> STranslation::PickWidget(CPt inMouseCoords, TranslationSelectMode::Enum, + qt3ds::widgets::IStudioWidgetBase &inWidget) +{ + SNode &theNode = inWidget.GetNode(); + SGraphObjectTranslator *theWidgetTranslator = + theNode.m_UserData.DynamicCast<SGraphObjectTranslator>(); + SLayer *theLayer = GetLayerForNode(theNode); + if (theLayer && theWidgetTranslator) { + Option<qt3ds::render::SLayerPickSetup> thePickSetup( + m_Context.GetRenderer().GetLayerPickSetup( + *theLayer, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y), + QSize(4, 4))); + if (thePickSetup.hasValue()) { + qt3ds::render::NVRenderContext &theContext(m_Context.GetRenderContext()); + qt3ds::render::NVRenderContextScopedProperty<qt3ds::render::NVRenderFrameBuffer *> + __currentrt(theContext, &qt3ds::render::NVRenderContext::GetRenderTarget, + &qt3ds::render::NVRenderContext::SetRenderTarget); + qt3ds::render::NVRenderFrameBuffer *theFBO = + m_Context.GetResourceManager().AllocateFrameBuffer(); + const QT3DSU32 fboDims = 8; + if (!m_PickBuffer) { + m_PickBuffer = theContext.CreateTexture2D(); + m_PickBuffer->SetTextureData(qt3ds::foundation::NVDataRef<qt3ds::QT3DSU8>(), 0, fboDims, + fboDims, + qt3ds::render::NVRenderTextureFormats::LuminanceAlpha8); + } + qt3ds::render::NVRenderRenderBuffer *theRenderBuffer = + m_Context.GetResourceManager().AllocateRenderBuffer( + fboDims, fboDims, qt3ds::render::NVRenderRenderBufferFormats::Depth16); + theFBO->Attach(qt3ds::render::NVRenderFrameBufferAttachments::Color0, + qt3ds::render::NVRenderTextureOrRenderBuffer(*m_PickBuffer)); + theFBO->Attach(qt3ds::render::NVRenderFrameBufferAttachments::Depth, + qt3ds::render::NVRenderTextureOrRenderBuffer(*theRenderBuffer)); + qt3ds::render::NVRenderRect theViewport(0, 0, fboDims, fboDims); + theContext.SetViewport(theViewport); + theContext.SetDepthWriteEnabled(true); + theContext.SetDepthTestEnabled(true); + theContext.SetScissorTestEnabled(false); + theContext.SetBlendingEnabled(false); + theContext.SetClearColor(QT3DSVec4(0, 0, 0, 0)); + theContext.Clear(qt3ds::render::NVRenderClearFlags( + qt3ds::render::NVRenderClearValues::Color | qt3ds::render::NVRenderClearValues::Depth)); + inWidget.RenderPick(thePickSetup->m_ProjectionPreMultiply, theContext, + QSize(4, 4)); + // Now read the pixels back. + m_PixelBuffer.resize(fboDims * fboDims * 3); + theContext.ReadPixels(theViewport, qt3ds::render::NVRenderReadPixelFormats::RGB8, + m_PixelBuffer); + m_Context.GetResourceManager().Release(*theFBO); + m_Context.GetResourceManager().Release(*theRenderBuffer); + eastl::hash_map<QT3DSU32, QT3DSU32> tallies; + QT3DSU32 numPixels = fboDims * fboDims; + for (QT3DSU32 idx = 0; idx < numPixels; ++idx) { + qt3ds::QT3DSU16 theChannelAmount = + m_PixelBuffer[idx * 3] + (m_PixelBuffer[idx * 3 + 1] << 8); + if (theChannelAmount) + tallies.insert(eastl::make_pair(theChannelAmount, (QT3DSU32)0)).first->second += 1; + } + QT3DSU32 tallyMaxTally = 0; + QT3DSU32 tallyMaxIdx = 0; + for (eastl::hash_map<QT3DSU32, QT3DSU32>::iterator iter = tallies.begin(), + end = tallies.end(); + iter != end; ++iter) { + if (iter->second > tallyMaxTally) { + tallyMaxTally = iter->second; + tallyMaxIdx = iter->first; + } + } + if (tallyMaxIdx > 0) { + return tallyMaxIdx; + } + } + } + return Empty(); +} + +SStudioPickValue STranslation::Pick(CPt inMouseCoords, TranslationSelectMode::Enum inSelectMode, + bool ignoreWidgets) +{ + bool requestRender = false; + + if (!ignoreWidgets) { + if (m_Doc.GetDocumentReader().AreGuidesEditable()) { + qt3dsdm::TGuideHandleList theGuides = m_Doc.GetDocumentReader().GetGuides(); + CPt renderSpacePt(inMouseCoords.x - (long)m_InnerRect.m_Left, + (long)GetViewportDimensions().y - inMouseCoords.y + - (long)m_InnerRect.m_Bottom); + for (size_t guideIdx = 0, guideEnd = theGuides.size(); + guideIdx < guideEnd; ++guideIdx) { + qt3dsdm::SGuideInfo theGuideInfo = + m_Doc.GetDocumentReader().GetGuideInfo(theGuides[guideIdx]); + float width = (theGuideInfo.m_Width / 2.0f) + 2.0f; + switch (theGuideInfo.m_Direction) { + case qt3dsdm::GuideDirections::Horizontal: + if (fabs((float)renderSpacePt.y - theGuideInfo.m_Position) <= width) + return theGuides[guideIdx]; + break; + case qt3dsdm::GuideDirections::Vertical: + if (fabs((float)renderSpacePt.x - theGuideInfo.m_Position) <= width) + return theGuides[guideIdx]; + break; + default: + break; + } + } + } + if (IsPathWidgetActive()) { + Option<QT3DSU32> picked = PickWidget(inMouseCoords, inSelectMode, *m_PathWidget); + if (picked.hasValue()) { + RequestRender(); + DoPrepareForDrag(&m_PathWidget->GetNode()); + return m_PathWidget->PickIndexToPickValue(*picked); + } + } + // Pick against the widget first if possible. + if (m_LastRenderedWidget && (m_LastRenderedWidget->GetNode().m_Flags.IsActive() + || m_LastRenderedWidget->GetNode().m_Type + == GraphObjectTypes::Light + || m_LastRenderedWidget->GetNode().m_Type + == GraphObjectTypes::Camera)) { + Option<QT3DSU32> picked = PickWidget(inMouseCoords, inSelectMode, + *m_LastRenderedWidget); + if (picked.hasValue()) { + RequestRender(); + DoPrepareForDrag(&m_LastRenderedWidget->GetNode()); + return m_LastRenderedWidget->PickIndexToPickValue(*picked); + } + } + } + // Pick against Lights and Cameras + // This doesn't use the color picker or renderer pick + float lastDist = 99999999999999.0f; + int lastIndex = -1; + for (int i = 0; i < int(m_editModeCamerasAndLights.size()); ++i) { + const QT3DSVec2 mouseCoords((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y); + float dist; + SGraphObject &object = m_editModeCamerasAndLights[i]->GetGraphObject(); + m_VisualAidWidget->SetNode(static_cast<SNode *>(&object)); + if (m_VisualAidWidget->pick(m_Context.GetRenderer().GetRenderWidgetContext(), + dist, GetViewportDimensions(), mouseCoords)) { + if (dist < lastDist) { + lastDist = dist; + lastIndex = i; + } + } + } + + if (m_Scene && m_Scene->m_FirstChild) { + qt3ds::render::Qt3DSRenderPickResult thePickResult = + m_Context.GetRenderer().Pick(*m_Scene->m_FirstChild, GetViewportDimensions(), + QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y)); + if (thePickResult.m_HitObject) { + const SGraphObject &theObject = *thePickResult.m_HitObject; + + // check hit distance to cameras and lights + if (lastIndex != -1 && thePickResult.m_CameraDistanceSq > lastDist * lastDist) { + DoPrepareForDrag(static_cast<SNode *>( + &(m_editModeCamerasAndLights[lastIndex]->GetGraphObject()))); + return m_editModeCamerasAndLights[lastIndex]->GetInstanceHandle(); + } + + if (theObject.m_Type == GraphObjectTypes::Model + || theObject.m_Type == GraphObjectTypes::Text + || theObject.m_Type == GraphObjectTypes::Path) { + const SNode &theTranslatorModel(static_cast<const SNode &>(theObject)); + SGraphObjectTranslator *theTranslator = + theTranslatorModel.m_UserData.DynamicCast<SGraphObjectTranslator>(); + const SNode *theModelPtr = &theTranslatorModel; + if (theTranslator->GetPossiblyAliasedInstanceHandle() + != theTranslator->GetInstanceHandle()) { + theTranslator = + GetOrCreateTranslator(theTranslator->GetPossiblyAliasedInstanceHandle()); + theModelPtr = + static_cast<const SNode *>(&theTranslator->GetNonAliasedGraphObject()); + } + Qt3DSDMInstanceHandle theActiveComponent = + m_Reader.GetComponentForSlide(m_Doc.GetActiveSlide()); + if (inSelectMode == TranslationSelectMode::Group) { + // Bounce up the hierarchy till one of two conditions are met + // the parent is a layer or the our component is the active component + // but the parent's is not. + while (theTranslator && GraphObjectTypes::IsNodeType( + theTranslator->GetGraphObject().m_Type)) { + SNode *myNode = static_cast<SNode *>(&theTranslator->GetGraphObject()); + if (myNode->m_Parent == nullptr) { + theTranslator = nullptr; + break; + } + SNode *parentNode = myNode->m_Parent; + SGraphObjectTranslator *theParentTranslator = + parentNode->m_UserData.DynamicCast<SGraphObjectTranslator>(); + Qt3DSDMInstanceHandle myComponent = + m_Reader.GetAssociatedComponent(theTranslator->GetInstanceHandle()); + Qt3DSDMInstanceHandle myParentComponent = m_Reader.GetAssociatedComponent( + theParentTranslator->GetInstanceHandle()); + if (parentNode->m_Type == GraphObjectTypes::Layer) { + if (myParentComponent != theActiveComponent) + theTranslator = nullptr; + break; + } + if (myComponent == theActiveComponent + && myParentComponent != theActiveComponent) + break; + theTranslator = theParentTranslator; + } + } else { + // Bounce up until we get into the active component and then stop. + while (inSelectMode == TranslationSelectMode::Single && theTranslator + && GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) + && m_Reader.GetAssociatedComponent(theTranslator->GetInstanceHandle()) + != theActiveComponent) { + SNode *theNode = static_cast<SNode *>(&theTranslator->GetGraphObject()); + theNode = theNode->m_Parent; + if (theNode && theNode->m_Type != GraphObjectTypes::Layer) + theTranslator = + theNode->m_UserData.DynamicCast<SGraphObjectTranslator>(); + else + theTranslator = nullptr; + } + } + + if (theTranslator) { + QT3DS_ASSERT(GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type)); + DoPrepareForDrag(static_cast<SNode *>(&theTranslator->GetGraphObject())); + return theTranslator->GetInstanceHandle(); + } + } + } + if (requestRender) + RequestRender(); + } + + if (lastIndex != -1) { + DoPrepareForDrag(static_cast<SNode *>( + &(m_editModeCamerasAndLights[lastIndex]->GetGraphObject()))); + return m_editModeCamerasAndLights[lastIndex]->GetInstanceHandle(); + } + + return SStudioPickValue(); +} + +qt3ds::foundation::Option<qt3dsdm::SGuideInfo> STranslation::PickRulers(CPt inMouseCoords) +{ + CPt renderSpacePt(inMouseCoords.x, (long)GetViewportDimensions().y - inMouseCoords.y); + // If mouse is inside outer rect but outside inner rect. + if (m_OuterRect.Contains(renderSpacePt.x, renderSpacePt.y) + && !m_InnerRect.Contains(renderSpacePt.x, renderSpacePt.y)) { + std::shared_ptr<qt3dsdm::IGuideSystem> theGuideSystem = + m_StudioSystem.GetFullSystem()->GetCoreSystem()->GetGuideSystem(); + if (renderSpacePt.x >= m_InnerRect.m_Left && renderSpacePt.x <= m_InnerRect.m_Right) { + return qt3dsdm::SGuideInfo((QT3DSF32)renderSpacePt.y - (QT3DSF32)m_InnerRect.m_Bottom, + qt3dsdm::GuideDirections::Horizontal); + } else if (renderSpacePt.y >= m_InnerRect.m_Bottom + && renderSpacePt.y <= m_InnerRect.m_Top) { + return qt3dsdm::SGuideInfo((QT3DSF32)renderSpacePt.x - (QT3DSF32)m_InnerRect.m_Left, + qt3dsdm::GuideDirections::Vertical); + } + } + return qt3ds::foundation::Option<qt3dsdm::SGuideInfo>(); +} + +QT3DSVec3 STranslation::GetIntendedPosition(qt3dsdm::Qt3DSDMInstanceHandle inInstance, CPt inPos) +{ + ClearDirtySet(); + SGraphObjectTranslator *theTranslator = GetOrCreateTranslator(inInstance); + if (theTranslator == nullptr) + return QT3DSVec3(0, 0, 0); + if (GraphObjectTypes::IsNodeType(theTranslator->GetGraphObject().m_Type) == false) + return QT3DSVec3(0, 0, 0); + SNode *theNode = static_cast<SNode *>(&theTranslator->GetGraphObject()); + SCamera *theCamera = m_Context.GetRenderer().GetCameraForNode(*theNode); + { + // Get the node's parent + Qt3DSDMInstanceHandle theParent = m_AssetGraph.GetParent(inInstance); + SGraphObjectTranslator *theParentTranslator = GetOrCreateTranslator(theParent); + if (theParentTranslator + && GraphObjectTypes::IsNodeType(theParentTranslator->GetGraphObject().m_Type)) + theCamera = m_Context.GetRenderer().GetCameraForNode( + *static_cast<SNode *>(&theParentTranslator->GetGraphObject())); + } + if (theCamera == nullptr) + return QT3DSVec3(0, 0, 0); + + QT3DSVec3 theGlobalPos(theNode->GetGlobalPos()); + return m_Context.GetRenderer().UnprojectToPosition(*theCamera, theGlobalPos, + QT3DSVec2((QT3DSF32)inPos.x, (QT3DSF32)inPos.y)); +} + +static void CheckLockToAxis(QT3DSF32 &inXDistance, QT3DSF32 &inYDistance, bool inLockToAxis) +{ + if (inLockToAxis) { + if (fabs(inXDistance) > fabs(inYDistance)) + inYDistance = 0; + else + inXDistance = 0; + } +} + +void STranslation::ApplyPositionalChange(QT3DSVec3 inDiff, SNode &inNode, + CUpdateableDocumentEditor &inEditor) +{ + if (m_MouseDownParentGlobalTransformInverse.isEmpty()) { + if (inNode.m_Parent) + m_MouseDownParentGlobalTransformInverse = + inNode.m_Parent->m_GlobalTransform.getInverse(); + else + m_MouseDownParentGlobalTransformInverse = QT3DSMat44::createIdentity(); + } + QT3DSMat44 theGlobalTransform = m_MouseDownNode.m_GlobalTransform; + QT3DSMat44 theNewLocalTransform = + m_MouseDownParentGlobalTransformInverse.getValue() * theGlobalTransform; + QT3DSVec3 theOldPos = theNewLocalTransform.column3.getXYZ(); + theOldPos.z *= -1; + + theGlobalTransform.column3 += QT3DSVec4(inDiff, 0.0f); + theNewLocalTransform = m_MouseDownParentGlobalTransformInverse.getValue() * theGlobalTransform; + QT3DSVec3 thePos = theNewLocalTransform.column3.getXYZ(); + thePos.z *= -1; + + QT3DSVec3 theDiff = thePos - theOldPos; + + SetPosition(m_MouseDownNode.m_Position + theDiff, inEditor); +} + +void STranslation::TranslateSelectedInstanceAlongCameraDirection( + CPt inOriginalCoords, CPt inMouseCoords, CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_Context.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + QT3DSF32 theYDistance = QT3DSF32(inMouseCoords.y - inOriginalCoords.y); + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 2.0f; + QT3DSF32 theDistanceMultiplier = 1.0f + theYDistance * theMouseMultiplier; + QT3DSVec3 theCameraDir = m_MouseDownCamera.GetDirection(); + + QT3DSVec3 theDiff = theCameraDir * theDistanceMultiplier; + ApplyPositionalChange(theDiff, *theNode, inEditor); +} + +void STranslation::TranslateSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor, bool inLockToAxis) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + qt3ds::render::IQt3DSRenderer &theRenderer(m_Context.GetRenderer()); + + QT3DSF32 theXDistance = QT3DSF32(inMouseCoords.x - inOriginalCoords.x); + QT3DSF32 theYDistance = QT3DSF32(inMouseCoords.y - inOriginalCoords.y); + if (fabs(theXDistance) == 0 && fabs(theYDistance) == 0) + return; + + CheckLockToAxis(theXDistance, theYDistance, inLockToAxis); + + inMouseCoords.x = inOriginalCoords.x + (long)theXDistance; + inMouseCoords.y = inOriginalCoords.y + (long)theYDistance; + QT3DSVec3 theNodeGlobal = m_MouseDownNode.GetGlobalPos(); + QT3DSVec3 theOriginalPos = theRenderer.UnprojectToPosition( + *theNode, theNodeGlobal, QT3DSVec2((QT3DSF32)inOriginalCoords.x, (QT3DSF32)inOriginalCoords.y)); + QT3DSVec3 theNewPos = theRenderer.UnprojectToPosition( + *theNode, theNodeGlobal, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y)); + + QT3DSVec3 theDiff = theNewPos - theOriginalPos; + ApplyPositionalChange(theDiff, *theNode, inEditor); +} + +void STranslation::ScaleSelectedInstanceZ(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + + // Scale scales uniformly and responds to mouse Y only. + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 40.0f; + QT3DSF32 theScaleMultiplier = 1.0f + theYDistance * theMouseMultiplier; + + SetScale(QT3DSVec3(m_MouseDownNode.m_Scale.x, m_MouseDownNode.m_Scale.y, + m_MouseDownNode.m_Scale.z * theScaleMultiplier), + inEditor); +} + +void STranslation::ScaleSelectedInstance(CPt inOriginalCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + + // Scale scales uniformly and responds to mouse Y only. + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (fabs(theYDistance) == 0) + return; + + QT3DSF32 theMouseMultiplier = 1.0f / 40.0f; + QT3DSF32 theScaleMultiplier = 1.0f + theYDistance * theMouseMultiplier; + + SetScale(m_MouseDownNode.m_Scale * theScaleMultiplier, inEditor); +} + +void STranslation::CalculateNodeGlobalRotation(SNode &inNode) +{ + if (inNode.m_Parent) + CalculateNodeGlobalRotation(*inNode.m_Parent); + if (m_MouseDownParentRotationInverse.isEmpty()) { + m_MouseDownParentRotationInverse = QT3DSMat33::createIdentity(); + m_MouseDownGlobalRotation = QT3DSMat33::createIdentity(); + } + + QT3DSMat44 localRotation; + inNode.CalculateRotationMatrix(localRotation); + if (inNode.m_Flags.IsLeftHanded()) + SNode::FlipCoordinateSystem(localRotation); + QT3DSMat33 theRotation; + SNode::GetMatrixUpper3x3(theRotation, localRotation); + + m_MouseDownParentRotationInverse = m_MouseDownGlobalRotation; + m_MouseDownGlobalRotation = m_MouseDownGlobalRotation.getValue() * theRotation; +} + +void STranslation::ApplyRotationToSelectedInstance(const QT3DSQuat &inFinalRotation, SNode &inNode, + CUpdateableDocumentEditor &inEditor, + bool inIsMouseRelative) +{ + if (m_MouseDownParentRotationInverse.isEmpty()) { + CalculateNodeGlobalRotation(inNode); + m_MouseDownParentRotationInverse = m_MouseDownParentRotationInverse->getInverse(); + } + QT3DSMat33 theRotationMatrix(inFinalRotation); + + QT3DSMat33 theFinalGlobal = theRotationMatrix * m_MouseDownGlobalRotation.getValue(); + QT3DSMat33 theLocalGlobal = m_MouseDownParentRotationInverse.getValue() * theFinalGlobal; + QT3DSVec3 theRotations = inNode.GetRotationVectorFromRotationMatrix(theLocalGlobal); + theRotations = qt3ds::render::SRotationHelper::ToNearestAngle(inNode.m_Rotation, theRotations, + inNode.m_RotationOrder); + SetRotation(theRotations, inEditor); + // Trackball rotation is relative to the previous mouse position. + // Rotation manipulator rotation is relative to only the original mouse down position + // so inIsMouseRelative is false for rotations that are relative to the original mouse down + // position. + if (inIsMouseRelative) + m_MouseDownGlobalRotation = theFinalGlobal; +} + +void STranslation::RotateSelectedInstanceAboutCameraDirectionVector( + CPt inPreviousMouseCoords, CPt inMouseCoords, CUpdateableDocumentEditor &inEditor) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_Context.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + + QT3DSVec3 theDirection = m_MouseDownCamera.GetDirection(); + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inPreviousMouseCoords.y; + QT3DSQuat theYRotation(-1.0f * theYDistance * g_RotationScaleFactor, theDirection); + + ApplyRotationToSelectedInstance(theYRotation, *theNode, inEditor); +} + +// This method never feels right to me. It is difficult to apply it to a single axis (of course for +// that you can use the inspector palette). +void STranslation::RotateSelectedInstance(CPt inOriginalCoords, CPt inPreviousCoords, + CPt inMouseCoords, CUpdateableDocumentEditor &inEditor, + bool inLockToAxis) +{ + SNode *theNode = GetSelectedNode(); + if (theNode == nullptr) + return; + SCamera *theCamera = m_Context.GetRenderer().GetCameraForNode(*theNode); + if (theCamera == nullptr) + return; + // We want to do a similar translation to what we did below but we need to calculate the + // parent's global rotation without scale included. + + QT3DSF32 theXDistance = (QT3DSF32)inMouseCoords.x - (QT3DSF32)inPreviousCoords.x; + QT3DSF32 theYDistance = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inPreviousCoords.y; + bool xIsZero = fabs(theXDistance) < .001f; + bool yIsZero = fabs(theYDistance) < .001f; + if (xIsZero && yIsZero) + return; + + if (inLockToAxis) { + QT3DSF32 originalDistX = (QT3DSF32)inMouseCoords.x - (QT3DSF32)inOriginalCoords.x; + QT3DSF32 originalDistY = (QT3DSF32)inMouseCoords.y - (QT3DSF32)inOriginalCoords.y; + if (inLockToAxis) { + if (fabs(originalDistX) > fabs(originalDistY)) + theYDistance = 0; + else + theXDistance = 0; + } + } + + QT3DSVec3 theXAxis = m_MouseDownCamera.m_GlobalTransform.column0.getXYZ(); + QT3DSVec3 theYAxis = m_MouseDownCamera.m_GlobalTransform.column1.getXYZ(); + + QT3DSVec3 theFinalAxis = theXDistance * theYAxis + theYDistance * theXAxis; + QT3DSF32 theTotalDistance = theFinalAxis.normalize(); + QT3DSQuat theRotation(theTotalDistance * g_RotationScaleFactor / 2.0f, theFinalAxis); + + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor); +} + +inline void NiceAdd(QT3DSF32 &ioValue, QT3DSF32 inIncrement) +{ + QT3DSF32 temp = ioValue + inIncrement; + // Round to nearest .5 + QT3DSF32 sign = temp >= 0 ? 1.0f : -1.0f; + QT3DSU32 largerValue = (QT3DSU32)(fabs(temp * 10.0f)); + + QT3DSU32 leftover = largerValue % 10; + // Round down to zero + largerValue -= leftover; + if (leftover < 2) + leftover = 0; + else if (leftover > 7) { + leftover = 0; + largerValue += 10; + } else + leftover = 5; + largerValue += leftover; + + ioValue = sign * (QT3DSF32)largerValue / 10.0f; +} + +static inline QT3DSVec3 GetAxis(QT3DSU32 inIndex, QT3DSMat33 &inMatrix) +{ + QT3DSVec3 retval(0, 0, 0); + switch (inIndex) { + case 0: + retval = inMatrix.column0; + break; + case 1: + retval = inMatrix.column1; + break; + case 2: + retval = inMatrix.column2; + break; + default: + QT3DS_ASSERT(false); + break; + } + retval.normalize(); + return retval; +} + +inline Option<QT3DSF32> GetScaleAlongAxis(const QT3DSVec3 &inAxis, const QT3DSVec3 &inObjToOriginal, + const QT3DSVec3 &inObjToCurrent) +{ + QT3DSF32 lhs = inAxis.dot(inObjToCurrent); + QT3DSF32 rhs = inAxis.dot(inObjToOriginal); + if (fabs(rhs) > .001f) + return lhs / rhs; + return Empty(); +} + +// Make a nice rotation from the incoming rotation +static inline QT3DSF32 MakeNiceRotation(QT3DSF32 inAngle) +{ + TODEG(inAngle); + inAngle *= 10.0f; + QT3DSF32 sign = inAngle > 0.0f ? 1.0f : -1.0f; + // Attempt to ensure angle is prtty clean + QT3DSU32 clampedAngle = (QT3DSU32)(fabs(inAngle) + .5f); + QT3DSU32 leftover = clampedAngle % 10; + clampedAngle -= leftover; + if (leftover <= 2) + leftover = 0; + else if (leftover <= 7) + leftover = 5; + else + leftover = 10; + clampedAngle += leftover; + QT3DSF32 retval = (QT3DSF32)clampedAngle; + retval = (retval * sign) / 10.0f; + TORAD(retval); + return retval; +} + +static inline QT3DSF32 ShortestAngleDifference(QT3DSF32 inCumulative, QT3DSF32 inNewTotal) +{ + QT3DSF32 diff = qt3ds::render::SRotationHelper::ToMinimalAngle(inNewTotal - inCumulative); + return inCumulative + diff; +} + +Option<SDragPreparationResult> +STranslation::PrepareWidgetDrag(qt3ds::widgets::StudioWidgetComponentIds::Enum inComponentId, + qt3ds::widgets::StudioWidgetTypes::Enum inWidgetId, + qt3ds::render::RenderWidgetModes::Enum inWidgetMode, SNode &inNode, + CPt inOriginalCoords, CPt inPreviousMouseCoords, CPt inMouseCoords) +{ + SDragPreparationResult retval; + retval.m_ComponentId = inComponentId; + retval.m_WidgetType = inWidgetId; + retval.m_WidgetMode = inWidgetMode; + qt3ds::render::IQt3DSRenderer &theRenderer(m_Context.GetRenderer()); + retval.m_Renderer = &theRenderer; + retval.m_Node = &inNode; + retval.m_Layer = GetLayerForNode(inNode); + retval.m_Camera = theRenderer.GetCameraForNode(inNode); + QSize theUnsignedDimensions(m_Context.GetWindowDimensions()); + QT3DSVec2 theWindowDimensions((QT3DSF32)theUnsignedDimensions.width(), + (QT3DSF32)theUnsignedDimensions.height()); + if (retval.m_Camera == nullptr || retval.m_Layer == nullptr) + return Empty(); + + SCamera &theCamera(*retval.m_Camera); + SLayer &theLayer(*retval.m_Layer); + QT3DSVec2 theLayerOriginalCoords = m_Context.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inOriginalCoords.x, (QT3DSF32)inOriginalCoords.y), + theWindowDimensions, true); + + QT3DSVec2 theLayerMouseCoords = m_Context.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inMouseCoords.x, (QT3DSF32)inMouseCoords.y), + theWindowDimensions, true); + + QT3DSVec2 thePreviousLayerMouseCoords = m_Context.GetRenderer().GetLayerMouseCoords( + *retval.m_Layer, QT3DSVec2((QT3DSF32)inPreviousMouseCoords.x, (QT3DSF32)inPreviousMouseCoords.y), + theWindowDimensions, true); + QT3DSMat44 theGlobalTransform(QT3DSMat44::createIdentity()); + if (inWidgetMode == qt3ds::render::RenderWidgetModes::Local) { + theGlobalTransform = m_MouseDownNode.m_GlobalTransform; + } + retval.m_GlobalTransform = theGlobalTransform; + QT3DSMat33 theNormalMat(theGlobalTransform.column0.getXYZ(), theGlobalTransform.column1.getXYZ(), + theGlobalTransform.column2.getXYZ()); + theNormalMat = theNormalMat.getInverse().getTranspose(); + retval.m_NormalMatrix = theNormalMat; + qt3ds::render::NVRenderRectF theLayerRect(theRenderer.GetLayerRect(theLayer)); + SRay theOriginalRay = + theCamera.Unproject(theLayerOriginalCoords, theLayerRect, theWindowDimensions); + SRay theCurrentRay = + theCamera.Unproject(theLayerMouseCoords, theLayerRect, theWindowDimensions); + SRay thePreviousRay = + theCamera.Unproject(thePreviousLayerMouseCoords, theLayerRect, theWindowDimensions); + retval.m_OriginalRay = theOriginalRay; + retval.m_CurrentRay = theCurrentRay; + retval.m_PreviousRay = thePreviousRay; + QT3DSVec3 theAxis; + QT3DSVec3 thePlaneNormal; + bool isPlane = false; + QT3DSVec3 globalPos = inNode.GetGlobalPivot(); + QT3DSVec3 camGlobalPos = theCamera.GetGlobalPos(); + QT3DSVec3 theCamDirection; + retval.m_GlobalPos = globalPos; + retval.m_CameraGlobalPos = camGlobalPos; + if (theCamera.m_Flags.IsOrthographic()) + theCamDirection = theCamera.GetDirection(); + else { + theCamDirection = globalPos - camGlobalPos; + // The normal will be normalized below. + } + theCamDirection.normalize(); + retval.m_CameraDirection = theCamDirection; + retval.m_AxisIndex = 0; + switch (inComponentId) { + default: + QT3DS_ASSERT(false); + break; + case qt3ds::widgets::StudioWidgetComponentIds::XAxis: + theAxis = QT3DSVec3(1, 0, 0); + break; + case qt3ds::widgets::StudioWidgetComponentIds::YAxis: + theAxis = QT3DSVec3(0, 1, 0); + retval.m_AxisIndex = 1; + break; + case qt3ds::widgets::StudioWidgetComponentIds::ZAxis: + theAxis = QT3DSVec3(0, 0, -1); + retval.m_AxisIndex = 2; + break; + case qt3ds::widgets::StudioWidgetComponentIds::XPlane: + thePlaneNormal = QT3DSVec3(1, 0, 0); + isPlane = true; + break; + case qt3ds::widgets::StudioWidgetComponentIds::YPlane: + thePlaneNormal = QT3DSVec3(0, 1, 0); + isPlane = true; + break; + case qt3ds::widgets::StudioWidgetComponentIds::ZPlane: + thePlaneNormal = QT3DSVec3(0, 0, -1); + isPlane = true; + break; + case qt3ds::widgets::StudioWidgetComponentIds::CameraPlane: { + isPlane = true; + thePlaneNormal = theCamDirection; + } break; + } + retval.m_IsPlane = isPlane; + if (inWidgetId == qt3ds::widgets::StudioWidgetTypes::Rotation) { + if (isPlane == false) { + theAxis = theNormalMat.transform(theAxis); + theAxis.normalize(); + thePlaneNormal = theAxis; + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * thePlaneNormal.dot(globalPos)); + } else { + if (inComponentId != qt3ds::widgets::StudioWidgetComponentIds::CameraPlane) { + thePlaneNormal = theNormalMat.transform(thePlaneNormal); + } + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * (thePlaneNormal.dot(globalPos))); + } + } else { + if (isPlane == false) { + theAxis = theNormalMat.transform(theAxis); + theAxis.normalize(); + QT3DSVec3 theCameraToObj = globalPos - camGlobalPos; + QT3DSVec3 theTemp = theAxis.cross(theOriginalRay.m_Direction); + // When the axis is parallel to the camera, we can't drag meaningfully + if (theTemp.magnitudeSquared() < .05f) { + // Attempt to find a better axis by moving the object back towards the camera. + QT3DSF32 theSign = theCameraToObj.dot(theCamDirection) > 0.0 ? -1.0f : 1.0f; + QT3DSF32 theDistance = theCameraToObj.dot(theCamDirection); + QT3DSVec3 thePoint = globalPos + (theDistance * theSign) * theAxis; + // Check if we actually moved to right direction + QT3DSVec3 theNewCameraToObj = thePoint - camGlobalPos; + QT3DSF32 theNewDistance = theNewCameraToObj.dot(theCamDirection); + if (theNewDistance > theDistance) + thePoint = globalPos - (theDistance * theSign) * theAxis; + + QT3DSVec3 theNewDir = thePoint - camGlobalPos; + theNewDir.normalize(); + theTemp = theAxis.cross(theNewDir); + // Attempt again to find a better cross + if (theTemp.magnitudeSquared() < .05f) + return Empty(); + } + thePlaneNormal = theTemp.cross(theAxis); + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * thePlaneNormal.dot(globalPos)); + } else { + thePlaneNormal = theNormalMat.transform(thePlaneNormal); + thePlaneNormal.normalize(); + retval.m_Plane = qt3ds::NVPlane(thePlaneNormal, -1.0f * (thePlaneNormal.dot(globalPos))); + } + } + retval.m_Axis = theAxis; + retval.m_OriginalPlaneCoords = theOriginalRay.Intersect(retval.m_Plane); + retval.m_CurrentPlaneCoords = theCurrentRay.Intersect(retval.m_Plane); + retval.m_PreviousPlaneCoords = thePreviousRay.Intersect(retval.m_Plane); + return retval; +} + +void STranslation::PerformWidgetDrag(int inWidgetSubComponent, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + if (inWidgetSubComponent == 0 || m_LastRenderedWidget == nullptr) { + QT3DS_ASSERT(false); + return; + } + Option<SDragPreparationResult> thePrepResult(PrepareWidgetDrag( + static_cast<qt3ds::widgets::StudioWidgetComponentIds::Enum>(inWidgetSubComponent), + m_LastRenderedWidget->GetWidgetType(), m_LastRenderedWidget->GetRenderWidgetMode(), + m_LastRenderedWidget->GetNode(), inOriginalCoords, inPreviousMouseCoords, inMouseCoords)); + if (!thePrepResult.hasValue()) + return; + + Option<QT3DSVec3> theOriginalPlaneCoords(thePrepResult->m_OriginalPlaneCoords); + Option<QT3DSVec3> theCurrentPlaneCoords(thePrepResult->m_CurrentPlaneCoords); + QT3DSVec3 globalPos(thePrepResult->m_GlobalPos); + bool isPlane(thePrepResult->m_IsPlane); + QT3DSVec3 theAxis(thePrepResult->m_Axis); + QT3DSU32 axisIndex(thePrepResult->m_AxisIndex); + SNode *theNode(thePrepResult->m_Node); + SRay theCurrentRay(thePrepResult->m_CurrentRay); + SRay theOriginalRay(thePrepResult->m_OriginalRay); + QT3DSVec3 thePlaneNormal(thePrepResult->m_Plane.n); + QT3DSVec3 theCamDirection(thePrepResult->m_CameraDirection); + QT3DSVec3 camGlobalPos(thePrepResult->m_CameraGlobalPos); + + switch (m_LastRenderedWidget->GetWidgetType()) { + default: + QT3DS_ASSERT(false); + return; + case qt3ds::widgets::StudioWidgetTypes::Scale: { + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 objToOriginal = globalPos - *theOriginalPlaneCoords; + QT3DSVec3 objToCurrent = globalPos - *theCurrentPlaneCoords; + QT3DSVec3 theScaleMultiplier(1, 1, 1); + if (!isPlane) { + // Ensure that we only have a scale vector in the direction of the axis. + objToOriginal = theAxis * (theAxis.dot(objToOriginal)); + objToCurrent = theAxis * (theAxis.dot(objToCurrent)); + QT3DSF32 objToOriginalDot = theAxis.dot(objToOriginal); + if (fabs(objToOriginalDot) > .001f) + theScaleMultiplier[axisIndex] = + theAxis.dot(objToCurrent) / theAxis.dot(objToOriginal); + else + theScaleMultiplier[axisIndex] = 0.0f; + } + + QT3DSMat33 theNodeAxisMatrix(theNode->m_GlobalTransform.column0.getXYZ(), + theNode->m_GlobalTransform.column1.getXYZ(), + theNode->m_GlobalTransform.column2.getXYZ()); + theNodeAxisMatrix = theNodeAxisMatrix.getInverse().getTranspose(); + QT3DSVec3 &theLocalXAxis(theNodeAxisMatrix.column0); + QT3DSVec3 &theLocalYAxis(theNodeAxisMatrix.column1); + QT3DSVec3 &theLocalZAxis(theNodeAxisMatrix.column2); + theLocalXAxis.normalize(); + theLocalYAxis.normalize(); + theLocalZAxis.normalize(); + + Option<QT3DSF32> theXScale = GetScaleAlongAxis(theLocalXAxis, objToOriginal, objToCurrent); + Option<QT3DSF32> theYScale = GetScaleAlongAxis(theLocalYAxis, objToOriginal, objToCurrent); + Option<QT3DSF32> theZScale = GetScaleAlongAxis(theLocalZAxis, objToOriginal, objToCurrent); + QT3DSVec3 theScale = m_MouseDownNode.m_Scale; + if (theXScale.isEmpty() && theYScale.isEmpty() && theZScale.isEmpty()) { + theScale = QT3DSVec3(0, 0, 0); + } else { + if (theXScale.hasValue()) + theScale.x *= *theXScale; + if (theYScale.hasValue()) + theScale.y *= *theYScale; + if (theZScale.hasValue()) + theScale.z *= *theZScale; + } + m_LastRenderedWidget->SetAxisScale(theScaleMultiplier); + SetScale(theScale, inEditor); + } + } break; + case qt3ds::widgets::StudioWidgetTypes::Rotation: { + QT3DSF32 theIntersectionCosine = theOriginalRay.m_Direction.dot(thePlaneNormal); + QT3DSVec3 objToPrevious; + QT3DSVec3 objToCurrent; + if (fabs(theIntersectionCosine) > .08f) { + if (!theOriginalPlaneCoords.hasValue() || !theCurrentPlaneCoords.hasValue()) + return; + objToPrevious = globalPos - *theOriginalPlaneCoords; + objToCurrent = globalPos - *theCurrentPlaneCoords; + objToPrevious.normalize(); + QT3DSF32 lineLen = objToCurrent.normalize(); + + if (!thePrepResult->m_Camera->m_Flags.IsOrthographic()) { + // Flip object vector if coords are behind camera to get the correct angle + QT3DSVec3 camToCurrent = camGlobalPos - *theCurrentPlaneCoords; + if (camToCurrent.dot(theCamDirection) >= 0.0f) { + objToCurrent = -objToCurrent; + // Negative line length seems counterintuitive, but since the end point is + // behind the camera, it results in correct line when rendered + lineLen = -lineLen; + } + } + + QT3DSF32 cosAngle = objToPrevious.dot(objToCurrent); + QT3DSVec3 theCrossProd = objToPrevious.cross(objToCurrent); + QT3DSF32 theCrossPlaneDot = theCrossProd.dot(thePlaneNormal); + QT3DSF32 angleSign = theCrossPlaneDot >= 0.0f ? 1.0f : -1.0f; + QT3DSF32 angleRad = acos(cosAngle) * angleSign; + angleRad = MakeNiceRotation(angleRad); + QT3DSQuat theRotation(angleRad, thePlaneNormal); + + m_CumulativeRotation = ShortestAngleDifference(m_CumulativeRotation, angleRad); + m_LastRenderedWidget->SetRotationEdges(-1.0f * objToPrevious, thePlaneNormal, + m_CumulativeRotation, lineLen); + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor, false); + } + // In this case we are viewing the plane of rotation pretty much dead on, so we need to + // assume the camera and the object are both in the plane of rotation. In this case we + // *sort* of need to do trackball rotation but force it to one plane of rotation. + else { + // Setup a plane 600 units away from the camera and have the gadget run from there. + + // This keeps rotation consistent. + QT3DSVec3 thePlaneSpot = theCamDirection * -600.0f + camGlobalPos; + qt3ds::NVPlane theCameraPlaneAtObject(theCamDirection, + -1.0f * (theCamDirection.dot(thePlaneSpot))); + theCurrentPlaneCoords = theCurrentRay.Intersect(theCameraPlaneAtObject); + theOriginalPlaneCoords = theOriginalRay.Intersect(theCameraPlaneAtObject); + QT3DSVec3 theChangeVector = *theOriginalPlaneCoords - *theCurrentPlaneCoords; + // Remove any component of the change vector that doesn't lie in the plane. + theChangeVector = + theChangeVector - theChangeVector.dot(thePlaneNormal) * thePlaneNormal; + QT3DSF32 theDistance = theChangeVector.normalize(); + // We want about 90* per 200 units in imaginary 600-units-from-camera space. + QT3DSF32 theScaleFactor = 1.0f / 200.0f; + if (thePrepResult->m_Camera->m_Flags.IsOrthographic()) + theScaleFactor = 1.0f / 100.0f; + + QT3DSF32 theDeg = 90.0f * theDistance * theScaleFactor; + // Check the sign of the angle. + QT3DSVec3 theCurrentIsectDir = camGlobalPos - *theCurrentPlaneCoords; + QT3DSVec3 thePreviousIsectDir = camGlobalPos - *theOriginalPlaneCoords; + QT3DSVec3 theCrossProd = theCurrentIsectDir.cross(thePreviousIsectDir); + QT3DSF32 theAngleSign = theCrossProd.dot(thePlaneNormal) > 0.0f ? 1.0f : -1.0f; + theDeg *= theAngleSign; + QT3DSF32 theRad(theDeg); + TORAD(theRad); + theRad = MakeNiceRotation(theRad); + QT3DSQuat theRotation(theRad, thePlaneNormal); + ApplyRotationToSelectedInstance(theRotation, *theNode, inEditor, false); + } + } break; + case qt3ds::widgets::StudioWidgetTypes::Translation: { + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 theDiff = *theCurrentPlaneCoords - *theOriginalPlaneCoords; + if (isPlane) { + ApplyPositionalChange(theDiff, *theNode, inEditor); + } else { + QT3DSVec3 theMovement = theAxis * theAxis.dot(theDiff); + ApplyPositionalChange(theMovement, *theNode, inEditor); + } + } + } break; + } +} + +static float RoundToNearest(float inValue, float inMin, float inMax, float inRound) +{ + float half = (inMin + inMax) / 2.0f; + inValue -= half; + inValue = inRound * floor(inValue / inRound + .5f); + inValue += half; + inValue -= inMin; + return inValue; +} + +void STranslation::PerformGuideDrag(Qt3DSDMGuideHandle inGuide, CPt inPoint, + CUpdateableDocumentEditor &inEditor) +{ + qt3dsdm::SGuideInfo theInfo = m_Doc.GetDocumentReader().GetGuideInfo(inGuide); + CPt renderSpacePt(inPoint.x, (long)GetViewportDimensions().y - inPoint.y); + switch (theInfo.m_Direction) { + case qt3dsdm::GuideDirections::Horizontal: + theInfo.m_Position = RoundToNearest((float)renderSpacePt.y, (float)m_InnerRect.m_Bottom, + (float)m_InnerRect.m_Top, 10.0f); + break; + case qt3dsdm::GuideDirections::Vertical: + theInfo.m_Position = RoundToNearest((float)renderSpacePt.x, (float)m_InnerRect.m_Left, + (float)m_InnerRect.m_Right, 10.0f); + break; + default: + QT3DS_ASSERT(FALSE); + break; + break; + } + inEditor.EnsureEditor(QObject::tr("Drag Guide"), __FILE__, __LINE__).UpdateGuide(inGuide, + theInfo); + inEditor.FireImmediateRefresh(qt3dsdm::Qt3DSDMInstanceHandle()); +} + +void STranslation::CheckGuideInPresentationRect(Qt3DSDMGuideHandle inGuide, + CUpdateableDocumentEditor &inEditor) +{ + qt3dsdm::SGuideInfo theInfo = m_Doc.GetDocumentReader().GetGuideInfo(inGuide); + bool inPresentation = false; + QT3DSF32 presHeight = (QT3DSF32)m_InnerRect.m_Top - (QT3DSF32)m_InnerRect.m_Bottom; + QT3DSF32 presWidth = (QT3DSF32)m_InnerRect.m_Right - (QT3DSF32)m_InnerRect.m_Left; + switch (theInfo.m_Direction) { + case qt3dsdm::GuideDirections::Horizontal: + inPresentation = 0.0f <= theInfo.m_Position && presHeight >= theInfo.m_Position; + break; + case qt3dsdm::GuideDirections::Vertical: + inPresentation = 0.0f <= theInfo.m_Position && presWidth >= theInfo.m_Position; + break; + default: + break; + } + + if (!inPresentation) + inEditor.EnsureEditor(QObject::tr("Delete Guide"), __FILE__, __LINE__).DeleteGuide(inGuide); +} + +void STranslation::PerformPathDrag(qt3ds::studio::SPathPick &inPathPick, CPt inOriginalCoords, + CPt inPreviousMouseCoords, CPt inMouseCoords, + CUpdateableDocumentEditor &inEditor) +{ + Option<SDragPreparationResult> thePrepResult(PrepareWidgetDrag( + qt3ds::widgets::StudioWidgetComponentIds::ZPlane, + qt3ds::widgets::StudioWidgetTypes::Translation, qt3ds::render::RenderWidgetModes::Local, + m_PathWidget->GetNode(), inOriginalCoords, inPreviousMouseCoords, inMouseCoords)); + if (!thePrepResult.hasValue()) + return; + + Option<QT3DSVec3> theOriginalPlaneCoords(thePrepResult->m_OriginalPlaneCoords); + Option<QT3DSVec3> theCurrentPlaneCoords(thePrepResult->m_CurrentPlaneCoords); + Option<QT3DSVec3> thePreviousPlaneCoords(thePrepResult->m_PreviousPlaneCoords); + if (theOriginalPlaneCoords.hasValue() && theCurrentPlaneCoords.hasValue()) { + QT3DSVec3 theGlobalDiff = *theCurrentPlaneCoords - *theOriginalPlaneCoords; + QT3DSMat44 theGlobalInverse = thePrepResult->m_GlobalTransform.getInverse(); + QT3DSVec3 theCurrentPos = theGlobalInverse.transform(*theCurrentPlaneCoords); + QT3DSVec3 theOldPos = theGlobalInverse.transform(*theOriginalPlaneCoords); + QT3DSVec3 theDiff = theCurrentPos - theOldPos; + // Now find the anchor point; nontrivial. + SPathTranslator *theTranslator = + reinterpret_cast<SPathTranslator *>(thePrepResult->m_Node->m_UserData.m_UserData); + qt3dsdm::Qt3DSDMInstanceHandle thePathHandle = theTranslator->GetInstanceHandle(); + qt3dsdm::Qt3DSDMInstanceHandle theAnchorHandle = GetAnchorPoint(inPathPick); + + if (theAnchorHandle.Valid()) { + qt3dsdm::Qt3DSDMPropertyHandle thePosProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_Position.m_Property; + qt3dsdm::Qt3DSDMPropertyHandle theAngleProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingAngle.m_Property; + qt3dsdm::Qt3DSDMPropertyHandle theIncomingDistanceProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_IncomingDistance.m_Property; + qt3dsdm::Qt3DSDMPropertyHandle theOutgoingDistanceProperty = + m_ObjectDefinitions.m_PathAnchorPoint.m_OutgoingDistance.m_Property; + + IDocumentReader &theReader(m_Doc.GetDocumentReader()); + SFloat2 anchorPos = + *theReader.GetTypedInstancePropertyValue<SFloat2>(theAnchorHandle, thePosProperty); + QT3DSVec2 anchorPosVec = QT3DSVec2(anchorPos[0], anchorPos[1]); + if (m_LastPathDragValue.hasValue() == false) { + SPathAnchorDragInitialValue initialValue; + initialValue.m_Position = anchorPosVec; + initialValue.m_IncomingAngle = theReader.GetTypedInstancePropertyValue<float>( + theAnchorHandle, theAngleProperty); + initialValue.m_IncomingDistance = theReader.GetTypedInstancePropertyValue<float>( + theAnchorHandle, theIncomingDistanceProperty); + initialValue.m_OutgoingDistance = theReader.GetTypedInstancePropertyValue<float>( + theAnchorHandle, theOutgoingDistanceProperty); + m_LastPathDragValue = initialValue; + } + SPathAnchorDragInitialValue &lastValue(*m_LastPathDragValue); + QT3DSVec2 theCurrentValue; + switch (inPathPick.m_Property) { + case SPathPick::Anchor: + theCurrentValue = lastValue.m_Position; + break; + case SPathPick::IncomingControl: + theCurrentValue = qt3ds::render::IPathManagerCore::GetControlPointFromAngleDistance( + lastValue.m_Position, lastValue.m_IncomingAngle, lastValue.m_IncomingDistance); + break; + case SPathPick::OutgoingControl: + theCurrentValue = qt3ds::render::IPathManagerCore::GetControlPointFromAngleDistance( + lastValue.m_Position, lastValue.m_IncomingAngle + 180.0f, + lastValue.m_OutgoingDistance); + break; + default: + QT3DS_ASSERT(false); + break; + } + theCurrentValue[0] += theDiff.x; + theCurrentValue[1] += theDiff.y; + Q3DStudio::IDocumentEditor &theEditor = inEditor.EnsureEditor( + QObject::tr("Anchor Point Drag"), __FILE__, __LINE__); + switch (inPathPick.m_Property) { + case SPathPick::Anchor: + theEditor.SetInstancePropertyValue(theAnchorHandle, thePosProperty, + SFloat2(theCurrentValue.x, theCurrentValue.y)); + break; + case SPathPick::IncomingControl: { + QT3DSVec2 angleDistance = + qt3ds::render::IPathManagerCore::GetAngleDistanceFromControlPoint( + anchorPosVec, theCurrentValue); + float angleDiff = angleDistance.x - lastValue.m_IncomingAngle; + float minimalDiff = + qRadiansToDegrees(qt3ds::render::SRotationHelper::ToMinimalAngle( + qDegreesToRadians(angleDiff))); + float newAngle = lastValue.m_IncomingAngle + minimalDiff; + theEditor.SetInstancePropertyValue(theAnchorHandle, theAngleProperty, newAngle); + theEditor.SetInstancePropertyValue(theAnchorHandle, theIncomingDistanceProperty, + angleDistance.y); + } break; + case SPathPick::OutgoingControl: { + QT3DSVec2 angleDistance = + qt3ds::render::IPathManagerCore::GetAngleDistanceFromControlPoint( + anchorPosVec, theCurrentValue); + angleDistance.x += 180.0f; + float angleDiff = angleDistance.x - lastValue.m_IncomingAngle; + float minimalDiff = + qRadiansToDegrees(qt3ds::render::SRotationHelper::ToMinimalAngle( + qDegreesToRadians(angleDiff))); + float newAngle = lastValue.m_IncomingAngle + minimalDiff; + theEditor.SetInstancePropertyValue(theAnchorHandle, theAngleProperty, newAngle); + theEditor.SetInstancePropertyValue(theAnchorHandle, theOutgoingDistanceProperty, + angleDistance.y); + } break; + } + + inEditor.FireImmediateRefresh(m_AssetGraph.GetParent(theAnchorHandle)); + } + } +} + +SNode *STranslation::GetEditCameraLayer() +{ + if (m_EditCameraLayerTranslator) + return static_cast<SNode *>(&m_EditCameraLayerTranslator->GetGraphObject()); + return nullptr; +} + +PickTargetAreas::Enum STranslation::GetPickArea(CPt inPoint) +{ + qt3ds::render::NVRenderRectF displayViewport = m_Context.GetDisplayViewport(); + QT3DSVec2 thePickPoint((QT3DSF32)inPoint.x, + m_Context.GetWindowDimensions().height() - (QT3DSF32)inPoint.y); + QT3DSF32 left = displayViewport.m_X; + QT3DSF32 right = displayViewport.m_X + displayViewport.m_Width; + QT3DSF32 top = displayViewport.m_Y + displayViewport.m_Height; + QT3DSF32 bottom = displayViewport.m_Y; + if (thePickPoint.x < left || thePickPoint.x > right || thePickPoint.y < bottom + || thePickPoint.y > top) + return PickTargetAreas::Matte; + return PickTargetAreas::Presentation; +} |