diff options
18 files changed, 391 insertions, 6 deletions
diff --git a/res/DataModelMetadata/en-us/MetaData.xml b/res/DataModelMetadata/en-us/MetaData.xml index 99a5254..b1085d4 100644 --- a/res/DataModelMetadata/en-us/MetaData.xml +++ b/res/DataModelMetadata/en-us/MetaData.xml @@ -307,6 +307,16 @@ <ShowIfEqual property="vertfields" value="Top/Bottom"/> <ShowIfEqual property="vertfields" value="Height/Bottom"/> </Property> + <Property name="dynamicresize" formalName="Dynamic Resize" description="Resize the layer dynamically\nbased on the content" type="Boolean" default="False" category="Size" /> + <Property name="dynamicpadding" formalName="Padding" description="Pad the resized layer to prevent constant\nresizing when small changes are made." min="0" default="0" animatable="False" category="Size"> + <ShowIfEqual property="dynamicresize" value="True"/> + </Property> + <Property name="dynamicpaddingunits" formalName="Padding Units" description="Padding is percent of overall\nwidth or absolute pixels" list="percent:pixels" default="percent" category="Size"> + <ShowIfEqual property="dynamicresize" value="True"/> + </Property> + <Property name="dynamiccombine" formalName="Combine Bounds" description="Combine layer object bounds for faster\ncalculation, but lower accuracy." type="Boolean" default="False" category="Size"> + <ShowIfEqual property="dynamicresize" value="True"/> + </Property> <!-- Ambient Occlusion --> <Property name="aoenabled" formalName="Ambient Occlusion" description="Use ambient occlusion" type="Boolean" default="False" category="Ambient Occlusion"> diff --git a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp index 53fed0c..3aacdec 100644 --- a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp +++ b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp @@ -244,6 +244,10 @@ struct DataConstructor<SObjectRefType> #define QT3DS_WCHAR_T_innertess L"innertess" #define QT3DS_WCHAR_T_scalemode L"scalemode" #define QT3DS_WCHAR_T_scaleanchor L"scaleanchor" +#define QT3DS_WCHAR_T_dynamicresize L"dynamicresize" +#define QT3DS_WCHAR_T_dynamicpaddingunits L"dynamicpaddingunits" +#define QT3DS_WCHAR_T_dynamicpadding L"dynamicpadding" +#define QT3DS_WCHAR_T_dynamiccombine L"dynamiccombine" #define QT3DS_WCHAR_T_horzfields L"horzfields" #define QT3DS_WCHAR_T_left L"left" #define QT3DS_WCHAR_T_leftunits L"leftunits" diff --git a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h index 0770d19..e8bd139 100644 --- a/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h +++ b/src/dm/systems/Qt3DSDMComposerTypeDefinitions.h @@ -208,6 +208,10 @@ class IPropertySystem; HANDLE_COMPOSER_PROPERTY_DUPLICATE(backgroundcolor, m_BackgroundColor, SFloat4, \ SFloat4(0, 0, 0, 1)) \ HANDLE_COMPOSER_PROPERTY(blendtype, m_BlendType, TDataStrPtr, L"Normal") \ + HANDLE_COMPOSER_PROPERTY(dynamicresize, m_DynamicResize, bool, false) \ + HANDLE_COMPOSER_PROPERTY(dynamicpaddingunits, m_DynamicPaddingUnits, TDataStrPtr, L"percent") \ + HANDLE_COMPOSER_PROPERTY(dynamicpadding, m_DynamicPadding, float, 0) \ + HANDLE_COMPOSER_PROPERTY(dynamiccombine, m_DynamicCombine, bool, false) \ HANDLE_COMPOSER_PROPERTY(horzfields, m_HorizontalFieldValues, TDataStrPtr, L"Left/Width") \ HANDLE_COMPOSER_PROPERTY(left, m_Left, float, 0) \ HANDLE_COMPOSER_PROPERTY(leftunits, m_LeftUnits, TDataStrPtr, L"percent") \ diff --git a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp index f416d66..5c33eba 100644 --- a/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp +++ b/src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp @@ -505,6 +505,10 @@ struct SRuntimePropertyParser #define Layer_BlendType ATTRIBUTE_BLENDTYPE #define Layer_ProgressiveAAMode ATTRIBUTE_PROGRESSIVEAA #define Layer_MultisampleAAMode ATTRIBUTE_MULTISAMPLEAA +#define Layer_DynamicResize ATTRIBUTE_DYNAMICRESIZE +#define Layer_DynamicPaddingUnits ATTRIBUTE_DYNAMICPADDINGUNITS +#define Layer_DynamicPadding ATTRIBUTE_DYNAMICPADDING +#define Layer_DynamicCombine ATTRIBUTE_DYNAMICCOMBINE #define Layer_HorizontalFieldValues ATTRIBUTE_HORZFIELDS #define Layer_Left ATTRIBUTE_LEFT #define Layer_LeftUnits ATTRIBUTE_LEFTUNITS diff --git a/src/runtime/Qt3DSAttributeHashes.cpp b/src/runtime/Qt3DSAttributeHashes.cpp index e9ef5d1..f126336 100644 --- a/src/runtime/Qt3DSAttributeHashes.cpp +++ b/src/runtime/Qt3DSAttributeHashes.cpp @@ -184,6 +184,10 @@ const char *GetAttributeString(const EAttribute inAttribute) case ATTRIBUTE_MULTISAMPLEAA: return "multisampleaa"; case ATTRIBUTE_TEMPORALAA: return "temporalaa"; case ATTRIBUTE_BLENDTYPE: return "blendtype"; + case ATTRIBUTE_DYNAMICRESIZE: return "dynamicresize"; + case ATTRIBUTE_DYNAMICPADDINGUNITS: return "dynamicpaddingunits"; + case ATTRIBUTE_DYNAMICPADDING: return "dynamicpadding"; + case ATTRIBUTE_DYNAMICCOMBINE: return "dynamiccombine"; case ATTRIBUTE_HORZFIELDS: return "horzfields"; case ATTRIBUTE_LEFT: return "left"; case ATTRIBUTE_LEFTUNITS: return "leftunits"; diff --git a/src/runtime/Qt3DSAttributeHashes.h b/src/runtime/Qt3DSAttributeHashes.h index 5127d1a..8979ddb 100644 --- a/src/runtime/Qt3DSAttributeHashes.h +++ b/src/runtime/Qt3DSAttributeHashes.h @@ -175,6 +175,10 @@ enum EAttribute { ATTRIBUTE_MULTISAMPLEAA = 0x013D29FD, // multisampleaa ATTRIBUTE_TEMPORALAA = 0x00212AFE, // temporalaa ATTRIBUTE_BLENDTYPE = 0x0035B4F5, // blendtype + ATTRIBUTE_DYNAMICRESIZE = 0x030D218D, // dynamicresize + ATTRIBUTE_DYNAMICPADDINGUNITS = 0x01B34023, // dynamicpaddingunits + ATTRIBUTE_DYNAMICPADDING = 0x00A35EAE, // dynamicpadding + ATTRIBUTE_DYNAMICCOMBINE = 0x02CB0FC0, // dynamiccombine ATTRIBUTE_HORZFIELDS = 0x02B8A818, // horzfields ATTRIBUTE_LEFT = 0x0196B9B9, // left ATTRIBUTE_LEFTUNITS = 0x02F9D2D8, // leftunits diff --git a/src/runtime/Qt3DSAttributeHashes.txt b/src/runtime/Qt3DSAttributeHashes.txt index 882517a..3549132 100644 --- a/src/runtime/Qt3DSAttributeHashes.txt +++ b/src/runtime/Qt3DSAttributeHashes.txt @@ -141,6 +141,10 @@ progressiveaa multisampleaa temporalaa blendtype +dynamicresize +dynamicpaddingunits +dynamicpadding +dynamiccombine horzfields left leftunits diff --git a/src/runtimerender/Qt3DSRenderUIPLoader.cpp b/src/runtimerender/Qt3DSRenderUIPLoader.cpp index 7d3ec0a..9630dc8 100644 --- a/src/runtimerender/Qt3DSRenderUIPLoader.cpp +++ b/src/runtimerender/Qt3DSRenderUIPLoader.cpp @@ -727,6 +727,10 @@ struct SRenderUIPLoader : public IDOMReferenceResolver #define Layer_Size "size" #define Layer_Location "location" #define Layer_TexturePath "sourcepath" +#define Layer_DynamicResize "dynamicresize" +#define Layer_DynamicPaddingUnits "dynamicpaddingunits" +#define Layer_DynamicPadding "dynamicpadding" +#define Layer_DynamicCombine "dynamiccombine" #define Layer_HorizontalFieldValues "horzfields" #define Layer_Left "left" #define Layer_LeftUnits "leftunits" diff --git a/src/runtimerender/Qt3DSRenderUIPSharedTranslation.h b/src/runtimerender/Qt3DSRenderUIPSharedTranslation.h index ca0e5e8..a7e8d4a 100644 --- a/src/runtimerender/Qt3DSRenderUIPSharedTranslation.h +++ b/src/runtimerender/Qt3DSRenderUIPSharedTranslation.h @@ -326,6 +326,10 @@ namespace render { HANDLE_QT3DS_RENDER_ENUM_PROPERTY(Layer, BlendType, Dirty) \ HANDLE_QT3DS_RENDER_ENUM_PROPERTY(Layer, Background, Dirty) \ HANDLE_QT3DS_RENDER_SOURCEPATH_PROPERTY(Layer, TexturePath, Dirty) \ + HANDLE_QT3DS_RENDER_PROPERTY(Layer, DynamicResize, Dirty) \ + HANDLE_QT3DS_RENDER_ENUM_PROPERTY(Layer, DynamicPaddingUnits, Dirty) \ + HANDLE_QT3DS_RENDER_PROPERTY(Layer, DynamicPadding, Dirty) \ + HANDLE_QT3DS_RENDER_PROPERTY(Layer, DynamicCombine, Dirty) \ HANDLE_QT3DS_RENDER_ENUM_PROPERTY(Layer, HorizontalFieldValues, Dirty) \ HANDLE_QT3DS_RENDER_PROPERTY(Layer, Left, Dirty) \ HANDLE_QT3DS_RENDER_ENUM_PROPERTY(Layer, LeftUnits, Dirty) \ diff --git a/src/runtimerender/graphobjects/Qt3DSRenderLayer.cpp b/src/runtimerender/graphobjects/Qt3DSRenderLayer.cpp index be79fba..73957e8 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderLayer.cpp +++ b/src/runtimerender/graphobjects/Qt3DSRenderLayer.cpp @@ -43,6 +43,10 @@ SLayer::SLayer() , m_Background(LayerBackground::Transparent) , m_ClearColor(0.0f) , m_BlendType(LayerBlendTypes::Normal) + , m_DynamicResize(false) + , m_DynamicPadding(0) + , m_DynamicPaddingUnits(LayerUnitTypes::Percent) + , m_DynamicCombine(false) , m_HorizontalFieldValues(HorizontalFieldValues::LeftWidth) , m_Left(0) , m_LeftUnits(LayerUnitTypes::Percent) diff --git a/src/runtimerender/graphobjects/Qt3DSRenderLayer.h b/src/runtimerender/graphobjects/Qt3DSRenderLayer.h index ac9f559..df1523d 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderLayer.h +++ b/src/runtimerender/graphobjects/Qt3DSRenderLayer.h @@ -129,6 +129,11 @@ namespace render { LayerBlendTypes::Enum m_BlendType; + bool m_DynamicResize; + QT3DSF32 m_DynamicPadding; + LayerUnitTypes::Enum m_DynamicPaddingUnits; + bool m_DynamicCombine; + HorizontalFieldValues::Enum m_HorizontalFieldValues; QT3DSF32 m_Left; LayerUnitTypes::Enum m_LeftUnits; diff --git a/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp b/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp index 9d42aa5..b3e557f 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp +++ b/src/runtimerender/graphobjects/Qt3DSRenderNode.cpp @@ -434,7 +434,7 @@ NVBounds3 SNode::GetChildBounds(IBufferManager &inManager, IPathManager &inPathM NVBounds3 retval; retval.setEmpty(); for (SNode *child = m_FirstChild; child != NULL; child = child->m_NextSibling) { - if (inChildFilter == NULL || inChildFilter->IncludeNode(*child)) { + if (inChildFilter == nullptr || inChildFilter->IncludeNode(*child)) { NVBounds3 childBounds; if (child->m_Flags.IsTransformDirty()) child->CalculateLocalTransform(); @@ -449,6 +449,96 @@ NVBounds3 SNode::GetChildBounds(IBufferManager &inManager, IPathManager &inPathM return retval; } +NVBounds3 SNode::GetActiveBounds(IBufferManager &inManager, IPathManager &inPathManager, + bool inIncludeChildren, + IQt3DSRenderNodeFilter *inChildFilter) const +{ + NVBounds3 retval; + retval.setEmpty(); + if (inIncludeChildren) + retval = GetActiveChildBounds(inManager, inPathManager, inChildFilter); + + if (m_Type == GraphObjectTypes::Model) + retval.include(static_cast<const SModel *>(this)->GetModelBounds(inManager)); + else if (m_Type == GraphObjectTypes::Text) + retval.include(static_cast<const SText *>(this)->GetTextBounds()); + else if (m_Type == GraphObjectTypes::Path) + retval.include(inPathManager.GetBounds(*static_cast<const SPath *>(this))); + return retval; +} + +NVBounds3 SNode::GetActiveChildBounds(IBufferManager &inManager, IPathManager &inPathManager, + IQt3DSRenderNodeFilter *inChildFilter) const +{ + NVBounds3 retval; + retval.setEmpty(); + for (SNode *child = m_FirstChild; child != nullptr; child = child->m_NextSibling) { + if (child->m_Flags.IsActive() + && (inChildFilter == nullptr || inChildFilter->IncludeNode(*child))) { + NVBounds3 childBounds; + if (child->m_Flags.IsTransformDirty()) + child->CalculateLocalTransform(); + childBounds = child->GetActiveBounds(inManager, inPathManager); + if (childBounds.isEmpty() == false) { + // Transform the bounds into our local space. + childBounds.transform(child->m_LocalTransform); + retval.include(childBounds); + } + } + } + return retval; +} + +void SNode::GetActiveBoundsList(QVector<QT3DSVec3> &points, IBufferManager &inManager, + IPathManager &inPathManager, + QT3DSMat44 localTransform, + bool inIncludeChildren, + IQt3DSRenderNodeFilter *inChildFilter) const +{ + if (inIncludeChildren) + GetActiveChildBoundsList(points, inManager, inPathManager, localTransform, inChildFilter); + + NVBounds3 bounds; + bounds.setEmpty(); + if (m_Type == GraphObjectTypes::Model) + bounds = static_cast<const SModel *>(this)->GetModelBounds(inManager); + else if (m_Type == GraphObjectTypes::Text) + bounds = static_cast<const SText *>(this)->GetTextBounds(); + else if (m_Type == GraphObjectTypes::Path) + bounds = inPathManager.GetBounds(*static_cast<const SPath *>(this)); + if (!bounds.isEmpty()) { + QT3DSVec3 newPoints[8]; + newPoints[0] = bounds.minimum; + newPoints[1] = QT3DSVec3(bounds.minimum.x, bounds.maximum.y, bounds.minimum.z); + newPoints[2] = QT3DSVec3(bounds.maximum.x, bounds.maximum.y, bounds.minimum.z); + newPoints[3] = QT3DSVec3(bounds.maximum.x, bounds.minimum.y, bounds.minimum.z); + newPoints[4] = QT3DSVec3(bounds.minimum.x, bounds.minimum.y, bounds.maximum.z); + newPoints[5] = QT3DSVec3(bounds.minimum.x, bounds.maximum.y, bounds.maximum.z); + newPoints[6] = QT3DSVec3(bounds.maximum.x, bounds.minimum.y, bounds.maximum.z); + newPoints[7] = bounds.maximum; + for (int i = 0; i < 8; ++i) { + // Transform the bounds into our local space. + points += localTransform.transform(newPoints[i]); + } + } +} + +void SNode::GetActiveChildBoundsList(QVector<QT3DSVec3> &points, IBufferManager &inManager, + IPathManager &inPathManager, + QT3DSMat44 localTransform, + IQt3DSRenderNodeFilter *inChildFilter) const +{ + for (SNode *child = m_FirstChild; child != nullptr; child = child->m_NextSibling) { + if (child->m_Flags.IsActive() + && (inChildFilter == nullptr || inChildFilter->IncludeNode(*child))) { + if (child->m_Flags.IsTransformDirty()) + child->CalculateLocalTransform(); + QT3DSMat44 nextTransform = localTransform * child->m_LocalTransform; + child->GetActiveBoundsList(points, inManager, inPathManager, nextTransform); + } + } +} + QT3DSVec3 SNode::GetGlobalPos() const { return m_GlobalTransform.getPosition(); diff --git a/src/runtimerender/graphobjects/Qt3DSRenderNode.h b/src/runtimerender/graphobjects/Qt3DSRenderNode.h index 751ed27..ea0d481 100644 --- a/src/runtimerender/graphobjects/Qt3DSRenderNode.h +++ b/src/runtimerender/graphobjects/Qt3DSRenderNode.h @@ -271,9 +271,25 @@ namespace render { // Get the bounds of us and our children in our local space. NVBounds3 GetBounds(IBufferManager &inManager, IPathManager &inPathManager, bool inIncludeChildren = true, - IQt3DSRenderNodeFilter *inChildFilter = NULL) const; + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; NVBounds3 GetChildBounds(IBufferManager &inManager, IPathManager &inPathManager, - IQt3DSRenderNodeFilter *inChildFilter = NULL) const; + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; + NVBounds3 GetActiveBounds(IBufferManager &inManager, IPathManager &inPathManager, + bool inIncludeChildren = true, + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; + NVBounds3 GetActiveChildBounds(IBufferManager &inManager, IPathManager &inPathManager, + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; + void GetActiveBoundsList(QVector<QT3DSVec3> &points, + IBufferManager &inManager, + IPathManager &inPathManager, + QT3DSMat44 localTransform = QT3DSMat44::createIdentity(), + bool inIncludeChildren = true, + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; + void GetActiveChildBoundsList(QVector<QT3DSVec3> &points, + IBufferManager &inManager, + IPathManager &inPathManager, + QT3DSMat44 localTransform = QT3DSMat44::createIdentity(), + IQt3DSRenderNodeFilter *inChildFilter = nullptr) const; // Assumes CalculateGlobalVariables has already been called. QT3DSVec3 GetGlobalPos() const; QT3DSVec3 GetGlobalPivot() const; diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp index 62ae506..9f47d47 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp @@ -1410,7 +1410,7 @@ void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn, QT3DS_ASSERT(m_LayerPrepResult->m_Flags.ShouldRenderToTexture()); SLayerRenderPreparationResult &thePrepResult(*m_LayerPrepResult); NVRenderContext &theRenderContext(m_Renderer.GetContext()); - QSize theLayerTextureDimensions = thePrepResult.GetTextureDimensions(); + QSize theLayerTextureDimensions(thePrepResult.GetTextureDimensions()); QSize theLayerOriginalTextureDimensions = theLayerTextureDimensions; NVRenderTextureFormats::Enum DepthTextureFormat = NVRenderTextureFormats::Depth24Stencil8; NVRenderTextureFormats::Enum ColorTextureFormat = NVRenderTextureFormats::RGBA8; @@ -1647,6 +1647,20 @@ void SLayerRenderData::RunRenderPass(TRenderRenderableFunction inRenderFn, hasDepthObjects || thePrepResult.m_Flags.RequiresStencilBuffer(); NVRenderRect theNewViewport(0, 0, theLayerTextureDimensions.width(), theLayerTextureDimensions.height()); + + if (m_Layer.m_DynamicResize && theLayerOriginalTextureDimensions.width() != 0) { + // With dynamic resize the viewport should behave like it just crops the full layer + // So a special viewport has to be calculated that keeps the original object sizes + float ratio = theLayerTextureDimensions.width() + / theLayerOriginalTextureDimensions.width(); + auto originalLayerViewport = thePrepResult.getOriginalLayerToPresentationViewport(); + auto layerViewport = thePrepResult.GetLayerToPresentationViewport(); + theNewViewport = NVRenderRect((-layerViewport.m_X + originalLayerViewport.m_X) * ratio, + (-layerViewport.m_Y + originalLayerViewport.m_Y) * ratio, + originalLayerViewport.m_Width * ratio, + originalLayerViewport.m_Height * ratio); + } + { theRenderContext.SetRenderTarget(theFB); NVRenderContextScopedProperty<NVRenderRect> __viewport( diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp index 49d6468..4fef629 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp @@ -178,9 +178,9 @@ SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewpo m_Viewport.m_Width = NVMax(1.0f, m_Viewport.m_Width); m_Viewport.m_Height = NVMax(1.0f, m_Viewport.m_Height); - // Now force the viewport to be a multiple of four in width and height. This is because + // Now force the viewport to be a multiple of four in width and height. This is because // when rendering to a texture we have to respect this and not forcing it causes scaling issues - // that are noticeable especially in situations where customers are using text and such. + // that are noticeable especially in situations where customers are using text. QT3DSF32 originalWidth = m_Viewport.m_Width; QT3DSF32 originalHeight = m_Viewport.m_Height; @@ -191,6 +191,7 @@ SLayerRenderHelper::SLayerRenderHelper(const NVRenderRectF &inPresentationViewpo m_Viewport.m_X += (originalWidth - m_Viewport.m_Width) / 2.0f; m_Viewport.m_Y += (originalHeight - m_Viewport.m_Height) / 2.0f; + m_originalViewport = m_Viewport; m_Scissor = m_Viewport; m_Scissor.EnsureInBounds(inPresentationScissor); QT3DS_ASSERT(m_Scissor.m_Width >= 0.0f); @@ -341,6 +342,30 @@ bool SLayerRenderHelper::isStereoscopic() const return m_StereoMode != StereoModes::Mono; } +void SLayerRenderHelper::setViewport(const NVRenderRectF &viewport) +{ + m_Viewport = viewport; + m_Viewport.m_Width = NVMax(1.0f, m_Viewport.m_Width); + m_Viewport.m_Height = NVMax(1.0f, m_Viewport.m_Height); + // Now force the viewport to be a multiple of four in width and height. This is because + // when rendering to a texture we have to respect this and not forcing it causes scaling issues + // that are noticeable especially in situations where customers are using text. + QT3DSF32 originalWidth = m_Viewport.m_Width; + QT3DSF32 originalHeight = m_Viewport.m_Height; + + m_Viewport.m_Width = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Width); + m_Viewport.m_Height = (QT3DSF32)ITextRenderer::NextMultipleOf4((QT3DSU32)m_Viewport.m_Height); + + // Now fudge the offsets to account for this slight difference + m_Viewport.m_X += (originalWidth - m_Viewport.m_Width) / 2.0f; + m_Viewport.m_Y += (originalHeight - m_Viewport.m_Height) / 2.0f; +} + +NVRenderRectF SLayerRenderHelper::getOriginalLayerToPresentationViewport() const +{ + return m_originalViewport; +} + void SLayerRenderHelper::copyCameraProperties(SCamera *sourceCamera, SCamera *destinationCamera) { diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h index 19fd3f5..59f4e08 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h @@ -64,6 +64,7 @@ namespace render { SCamera *m_CameraRightEye; bool m_Offscreen; + NVRenderRectF m_originalViewport; NVRenderRectF m_Viewport; NVRenderRectF m_Scissor; @@ -103,8 +104,10 @@ namespace render { QT3DSF32 getEyeSeparation() const { return m_StereoEyeSeparation; } void setEyeSeparation(QT3DSF32 separation) { m_StereoEyeSeparation = separation; } + void setViewport(const NVRenderRectF &viewport); // Does not differ whether offscreen or not, simply states how this layer maps to the // presentation + NVRenderRectF getOriginalLayerToPresentationViewport() const; NVRenderRectF GetLayerToPresentationViewport() const; // Does not differ whether offscreen or not, scissor rect of how this layer maps to // presentation. diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp index 9c1da26..eb098b4 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp @@ -1220,6 +1220,181 @@ namespace render { } }; + void SLayerRenderPreparationData::calculateDynamicLayerSize( + SLayerRenderPreparationResult &prepResult) + { + m_boundPoints.clear(); + if (m_Layer.m_DynamicCombine) { + // Combine all bounds of the layer objects to one spanning the whole active scene + // Only needs 8 projections but has low accuracy + NVBounds3 layerBounds; + layerBounds.setEmpty(); + for (SNode *child = m_Layer.m_FirstChild; child; child = child->m_NextSibling) { + if (child->m_Flags.IsActive()) { + auto &context = m_Renderer.GetQt3DSContext(); + qt3ds::NVBounds3 childBounds = child->GetActiveBounds( + context.GetBufferManager(), context.GetPathManager()); + if (childBounds.isEmpty() == false) { + childBounds.transform(child->m_GlobalTransform); + layerBounds.include(childBounds); + } + } + } + + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.minimum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.minimum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.maximum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.maximum.y, + layerBounds.minimum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.minimum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.minimum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.maximum.x, layerBounds.maximum.y, + layerBounds.maximum.z); + m_boundPoints += QT3DSVec3(layerBounds.minimum.x, layerBounds.maximum.y, + layerBounds.maximum.z); + } else { + // Add 8 points for each active object to the point list + // Provides accurate 2d bounds, but causes a lot of projections for large scenes + for (SNode *child = m_Layer.m_FirstChild; child; child = child->m_NextSibling) { + if (child->m_Flags.IsActive()) { + auto &context = m_Renderer.GetQt3DSContext(); + child->GetActiveBoundsList(m_boundPoints, context.GetBufferManager(), + context.GetPathManager(), child->m_GlobalTransform); + } + } + } + + auto layerViewport = prepResult.GetLayerToPresentationViewport(); + + QT3DSVec2 projectedMinimum(std::numeric_limits<float>::max(), + std::numeric_limits<float>::max()); + QT3DSVec2 projectedMaximum(std::numeric_limits<float>::lowest(), + std::numeric_limits<float>::lowest()); + + for (const auto &point : qAsConst(m_boundPoints)) { + QT3DSVec4 projectedPoint = m_ViewProjection.transform(QT3DSVec4(point, 1.0f)); + projectedPoint.x /= projectedPoint.w; + projectedPoint.y /= projectedPoint.w; + projectedPoint.x += 1.0f; + projectedPoint.y += 1.0f; + projectedPoint.x *= 0.5f; + projectedPoint.y *= 0.5f; + + QT3DSVec2 dims(QT3DSF32(layerViewport.m_Width), + QT3DSF32(layerViewport.m_Height)); + projectedPoint.x *= dims.x; + projectedPoint.y *= dims.y; + projectedPoint.x += layerViewport.m_X; + projectedPoint.y += layerViewport.m_Y; + + if (projectedPoint.x < projectedMinimum.x) + projectedMinimum.x = projectedPoint.x; + if (projectedPoint.y < projectedMinimum.y) + projectedMinimum.y = projectedPoint.y; + if (projectedPoint.x > projectedMaximum.x) + projectedMaximum.x = projectedPoint.x; + if (projectedPoint.y > projectedMaximum.y) + projectedMaximum.y = projectedPoint.y; + } + + float boundsLeft = projectedMinimum.x; + float boundsBottom = projectedMinimum.y; + float boundsWidth = qAbs(projectedMaximum.x - projectedMinimum.x); + float boundsHeight = qAbs(projectedMaximum.y - projectedMinimum.y); + + float paddedBoundsLeft = boundsLeft; + float paddedBoundsBottom = boundsBottom; + float paddedBoundsWidth = boundsWidth; + float paddedBoundsHeight = boundsHeight; + + if (m_Layer.m_DynamicPadding > 0) { + float unpaddedBoundsLeft; + float unpaddedBoundsBottom; + float unpaddedBoundsWidth; + float unpaddedBoundsHeight; + + if (m_Layer.m_DynamicPaddingUnits == LayerUnitTypes::Pixels) { + paddedBoundsLeft = boundsLeft - m_Layer.m_DynamicPadding; + paddedBoundsBottom = boundsBottom - m_Layer.m_DynamicPadding; + paddedBoundsWidth = boundsWidth + m_Layer.m_DynamicPadding * 2; + paddedBoundsHeight = boundsHeight + m_Layer.m_DynamicPadding * 2; + + unpaddedBoundsLeft = boundsLeft + m_Layer.m_DynamicPadding; + unpaddedBoundsBottom = boundsBottom + m_Layer.m_DynamicPadding; + unpaddedBoundsWidth = boundsWidth - m_Layer.m_DynamicPadding * 2; + unpaddedBoundsHeight = boundsHeight - m_Layer.m_DynamicPadding * 2; + } else { + const float leftPadding = boundsWidth * m_Layer.m_DynamicPadding * 0.01f; + const float bottomPadding = boundsHeight * m_Layer.m_DynamicPadding * 0.01f; + const float widthPadding = m_Layer.m_DynamicPadding * 0.02f; + const float heightPadding = m_Layer.m_DynamicPadding * 0.02f; + + paddedBoundsLeft = boundsLeft - leftPadding; + paddedBoundsBottom = boundsBottom - bottomPadding; + paddedBoundsWidth = boundsWidth * (1.0f + widthPadding); + paddedBoundsHeight = boundsHeight * (1.0f + heightPadding); + + unpaddedBoundsLeft = boundsLeft + leftPadding; + unpaddedBoundsBottom = boundsBottom + bottomPadding; + unpaddedBoundsWidth = boundsWidth * (1.0f - widthPadding); + unpaddedBoundsHeight = boundsHeight * (1.0f - heightPadding); + } + + // Both the padded and unpadded bounds are calculated + // Padded provides the upper bound when size has to be recalculated + // Unpadded provides the lower bound + // If the newly calculated bounds fit between the padded and unpadded ones + // use the previous calculations instead + if (m_Layer.m_DynamicPadding == m_lastDynamicPadding + && m_Layer.m_DynamicPaddingUnits == m_lastDynamicPaddingUnits + && m_unpaddedDynamicSize.m_X >= boundsLeft + && m_unpaddedDynamicSize.m_Y >= boundsBottom + && m_unpaddedDynamicSize.m_X + m_unpaddedDynamicSize.m_Width + <= boundsLeft + boundsWidth + && m_unpaddedDynamicSize.m_Y + m_unpaddedDynamicSize.m_Height + <= boundsBottom + boundsHeight + && m_dynamicSize.m_X <= boundsLeft + && m_dynamicSize.m_Y <= boundsBottom + && m_dynamicSize.m_X + m_dynamicSize.m_Width + >= boundsLeft + boundsWidth + && m_dynamicSize.m_Y + m_dynamicSize.m_Height + >= boundsBottom + boundsHeight) { + paddedBoundsLeft = m_dynamicSize.m_X; + paddedBoundsBottom = m_dynamicSize.m_Y; + paddedBoundsWidth = m_dynamicSize.m_Width; + paddedBoundsHeight = m_dynamicSize.m_Height; + } else { + m_unpaddedDynamicSize = NVRenderRectF(unpaddedBoundsLeft, + unpaddedBoundsBottom, + unpaddedBoundsWidth, + unpaddedBoundsHeight); + m_dynamicSize = NVRenderRectF(paddedBoundsLeft, + paddedBoundsBottom, + paddedBoundsWidth, + paddedBoundsHeight); + } + m_lastDynamicPadding = m_Layer.m_DynamicPadding; + m_lastDynamicPaddingUnits = m_Layer.m_DynamicPaddingUnits; + } + + if (paddedBoundsLeft < layerViewport.m_X) + paddedBoundsLeft = layerViewport.m_X; + if (paddedBoundsBottom < layerViewport.m_Y) + paddedBoundsBottom = layerViewport.m_Y; + if (paddedBoundsWidth > layerViewport.m_Width) + paddedBoundsWidth = layerViewport.m_Width; + if (paddedBoundsHeight > layerViewport.m_Height) + paddedBoundsHeight = layerViewport.m_Height; + + prepResult.setViewport(NVRenderRectF(paddedBoundsLeft, paddedBoundsBottom, + paddedBoundsWidth, paddedBoundsHeight)); + } + bool SLayerRenderPreparationData::PrepareForRender(const QSize &inViewportDimensions) { QT3DS_PERF_SCOPED_TIMER(m_Renderer.GetQt3DSContext().GetPerfTimer(), @@ -1497,6 +1672,10 @@ namespace render { QT3DSF32 theTextScaleFactor = 1.0f; if (m_Camera) { m_Camera->CalculateViewProjectionMatrix(m_ViewProjection); + + if (m_Layer.m_DynamicResize) + calculateDynamicLayerSize(thePrepResult); + theTextScaleFactor = m_Camera->GetTextScaleFactor( thePrepResult.GetLayerToPresentationViewport(), thePrepResult.GetPresentationDesignDimensions()); diff --git a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h index 376749e..fd9b86e 100644 --- a/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h +++ b/src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h @@ -267,6 +267,11 @@ namespace render { TRenderableObjectList m_OpaqueObjects; TRenderableObjectList m_TransparentObjects; TRenderableObjectList m_GroupObjects; + QVector<QT3DSVec3> m_boundPoints; + NVRenderRectF m_dynamicSize; + NVRenderRectF m_unpaddedDynamicSize; + float m_lastDynamicPadding = 0; + LayerUnitTypes::Enum m_lastDynamicPaddingUnits = LayerUnitTypes::Percent; // Sorted lists of the rendered objects. There may be other transforms applied so // it is simplest to duplicate the lists. TRenderableObjectList m_RenderedOpaqueObjects; @@ -343,6 +348,8 @@ namespace render { QT3DSF32 inTextScaleFactor, SLayerRenderPreparationResultFlags &ioFlags); + void calculateDynamicLayerSize(SLayerRenderPreparationResult &prepResult); + // returns true if this object will render something different than it rendered the last // time. virtual bool PrepareForRender(const QSize &inViewportDimensions); |