summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJere Tuliniemi <jere.tuliniemi@qt.io>2020-02-18 10:45:57 +0200
committerJere Tuliniemi <jere.tuliniemi@qt.io>2020-02-28 11:20:39 +0200
commitd9986892bf0cccc60c53d42dfc556d37226cf5d2 (patch)
treeebd6403f940544bf8aa1fea7c17bad2fa50cb4ed
parent7cb740b7dc1e7a660eaaab41cff2e4d76a9fd99f (diff)
Add dynamic layer resizing
Add a boolean property to layer that enables dynamic resizing. The screen space bounds of the layer content are calculated and the layer resized to fit the content and exclude empty space. Padding property is also added that pads the resized layer so that minimal changes to the content won't trigger another resize. Padding can be set by pixel amount or by percentage of the size. To provide accurate 2d bounds, each active objects bounds are projected separately to the screen. A boolean property to only project combined bounds is provided but lowers the accuracy while limiting projections to 8. Known issues: - Temporal AA doesn't work with resizing correctly - Temporal AA leaks GPU memory when resizing - Editor picking doesn't work correctly with dynamically resized layers - Render to viewport doesn't yet support resizing Task-number: QT3DS-4030 Change-Id: Ibc727e078129eee15021cc97105b4cdf9a5a3196 Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io> Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Antti Määttä <antti.maatta@qt.io>
-rw-r--r--res/DataModelMetadata/en-us/MetaData.xml10
-rw-r--r--src/dm/systems/Qt3DSDMComposerTypeDefinitions.cpp4
-rw-r--r--src/dm/systems/Qt3DSDMComposerTypeDefinitions.h4
-rw-r--r--src/engine/Qt3DSRenderRuntimeBindingImplTranslation.cpp4
-rw-r--r--src/runtime/Qt3DSAttributeHashes.cpp4
-rw-r--r--src/runtime/Qt3DSAttributeHashes.h4
-rw-r--r--src/runtime/Qt3DSAttributeHashes.txt4
-rw-r--r--src/runtimerender/Qt3DSRenderUIPLoader.cpp4
-rw-r--r--src/runtimerender/Qt3DSRenderUIPSharedTranslation.h4
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderLayer.cpp4
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderLayer.h5
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderNode.cpp92
-rw-r--r--src/runtimerender/graphobjects/Qt3DSRenderNode.h20
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderData.cpp16
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.cpp29
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderHelper.h3
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.cpp179
-rw-r--r--src/runtimerender/rendererimpl/Qt3DSRendererImplLayerRenderPreparationData.h7
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);