Browse Source

Replace render interface functions PushTransform and PopTransform with SetTransform

Michael Ragazzon 6 years ago
parent
commit
b6739b4684

+ 1 - 0
Include/RmlUi/Core/ElementInstancer.h

@@ -32,6 +32,7 @@
 #include "Traits.h"
 #include "Traits.h"
 #include "XMLParser.h"
 #include "XMLParser.h"
 #include "Header.h"
 #include "Header.h"
+#include "Element.h"
 
 
 namespace Rml {
 namespace Rml {
 namespace Core {
 namespace Core {

+ 4 - 8
Include/RmlUi/Core/ElementUtilities.h

@@ -132,15 +132,11 @@ public:
 	/// @param anchor[in] Defines which corner or edge the border is to be positioned relative to.
 	/// @param anchor[in] Defines which corner or edge the border is to be positioned relative to.
 	static bool PositionElement(Element* element, const Vector2f& offset, PositionAnchor anchor);
 	static bool PositionElement(Element* element, const Vector2f& offset, PositionAnchor anchor);
 
 
-	/// Applies an element's `perspective' and `transform' properties.
+	/// Applies an element's accumulated transform matrix, determined from its and ancestor's `perspective' and `transform' properties.
+	/// Note: All calls to RenderInterface::SetTransform must go through here.
 	/// @param[in] element		The element whose transform to apply.
 	/// @param[in] element		The element whose transform to apply.
-	/// @param[in] apply		Whether to apply (true) or unapply (false) the transform.
-	/// @return true if the element has a transform and it could be applied.
-	static bool ApplyTransform(Element &element, bool apply = true);
-	/// Unapplies an element's `perspective' and `transform' properties.
-	/// @param[in] element		The element whose transform to unapply.
-	/// @return true if the element has a transform and it could be unapplied.
-	static bool UnapplyTransform(Element &element);
+	/// @return true if a render interface is available to set the transform.
+	static bool ApplyTransform(Element &element);
 };
 };
 
 
 }
 }

+ 4 - 7
Include/RmlUi/Core/RenderInterface.h

@@ -107,13 +107,10 @@ public:
 	/// @param texture The texture handle to release.
 	/// @param texture The texture handle to release.
 	virtual void ReleaseTexture(TextureHandle texture);
 	virtual void ReleaseTexture(TextureHandle texture);
 
 
-	/// Called by RmlUi when it wants to set the current transform matrix to a new matrix.
-	/// @param[in] transform The new transform to apply.
-	virtual void PushTransform(const Matrix4f& transform);
-	/// Called by RmlUi when it wants to revert the latest transform change.
-	/// @param[in] transform This is the transform to unapply.
-	///            It always equals the argument of the latest call to PushTransform().
-	virtual void PopTransform(const Matrix4f& transform);
+	/// Called by RmlUi when it wants the renderer to use a new transform matrix.
+	/// If no transform applies to the current element, nullptr is submitted. Then it expects the renderer to use an identity matrix or otherwise omit the multiplication with the transform.
+	/// @param[in] transform The new transform to apply, or nullptr if no transform applies to the current element.
+	virtual void SetTransform(const Matrix4f* transform);
 
 
 	/// Get the context currently being rendered. This is only valid during RenderGeometry,
 	/// Get the context currently being rendered. This is only valid during RenderGeometry,
 	/// CompileGeometry, RenderCompiledGeometry, EnableScissorRegion and SetScissorRegion.
 	/// CompileGeometry, RenderCompiledGeometry, EnableScissorRegion and SetScissorRegion.

+ 2 - 2
Include/RmlUi/Core/TransformState.h

@@ -59,13 +59,13 @@ private:
 	mutable bool have_inverse_transform = false;
 	mutable bool have_inverse_transform = false;
 	mutable bool dirty_inverse_transform = false;
 	mutable bool dirty_inverse_transform = false;
 
 
-	// The transform combines all local transform and perspective properties of the owning element and all ancestors.
+	// The accumulated transform matrix combines all transform and perspective properties of the owning element and all ancestors.
 	Matrix4f transform;
 	Matrix4f transform;
 
 
 	// Local perspective which applies to children of the owning element.
 	// Local perspective which applies to children of the owning element.
 	Matrix4f local_perspective;
 	Matrix4f local_perspective;
 
 
-	// The inverse of the transform mainly for projecting points from screen-space to 2d-space, such as used for picking elements.
+	// The inverse of the transform matrix for projecting points from screen space to the current element's space, such as used for picking elements.
 	mutable Matrix4f inverse_transform;
 	mutable Matrix4f inverse_transform;
 };
 };
 
 

+ 1 - 3
Samples/basic/transform/data/transform.rml

@@ -56,7 +56,6 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 	width: 200px;
 	width: 200px;
 	height: 200px;
 	height: 200px;
 	margin: 75px auto;
 	margin: 75px auto;
-	border: none;
 	background-color: #a003;
 	background-color: #a003;
 }
 }
 
 
@@ -74,7 +73,6 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 	position: absolute;
 	position: absolute;
 	width: 100px;
 	width: 100px;
 	height: 100px;
 	height: 100px;
-	border: none;
 	line-height: 100px;
 	line-height: 100px;
 	font-size: 60px;
 	font-size: 60px;
 	color: white;
 	color: white;
@@ -147,7 +145,7 @@ augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet,
 consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
 consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
 laoreet dolore magna aliquam erat volutpat.</p>
 laoreet dolore magna aliquam erat volutpat.</p>
 
 
-<button style="width: 220px;">A wild button appears!</button>
+<button style="width: 220px; transform: translateZ(-30px);">A wild button appears!</button>
 
 
 <p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
 <p>Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
 lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
 lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure

+ 7 - 0
Samples/basic/transform/src/main.cpp

@@ -62,6 +62,13 @@ public:
 	void SetPerspective(float distance)
 	void SetPerspective(float distance)
 	{
 	{
 		perspective = distance;
 		perspective = distance;
+
+		if (document && perspective > 0)
+		{
+			std::stringstream s;
+			s << "perspective(" << perspective << "px) ";
+			document->SetProperty("transform", s.str().c_str());
+		}
 	}
 	}
 
 
 	void SetRotation(float degrees)
 	void SetRotation(float degrees)

+ 2 - 5
Samples/shell/include/ShellRenderInterfaceOpenGL.h

@@ -66,10 +66,7 @@ public:
 	void ReleaseTexture(Rml::Core::TextureHandle texture_handle) override;
 	void ReleaseTexture(Rml::Core::TextureHandle texture_handle) override;
 
 
 	/// Called by RmlUi when it wants to set the current transform matrix to a new matrix.
 	/// Called by RmlUi when it wants to set the current transform matrix to a new matrix.
-	void PushTransform(const Rml::Core::Matrix4f& transform) override;
-
-	/// Called by RmlUi when it wants to revert the latest transform change.
-	void PopTransform(const Rml::Core::Matrix4f& transform) override;
+	void SetTransform(const Rml::Core::Matrix4f* transform) override;
 
 
 	// ShellRenderInterfaceExtensions
 	// ShellRenderInterfaceExtensions
 	void SetViewport(int width, int height) override;
 	void SetViewport(int width, int height) override;
@@ -82,7 +79,7 @@ public:
 protected:
 protected:
 	int m_width;
 	int m_width;
 	int m_height;
 	int m_height;
-	int m_transforms;
+	bool m_transform_enabled;
 	void *m_rmlui_context;
 	void *m_rmlui_context;
 	
 	
 #if defined(RMLUI_PLATFORM_MACOSX)
 #if defined(RMLUI_PLATFORM_MACOSX)

+ 14 - 17
Samples/shell/src/ShellRenderInterfaceOpenGL.cpp

@@ -33,7 +33,7 @@
 
 
 #define GL_CLAMP_TO_EDGE 0x812F
 #define GL_CLAMP_TO_EDGE 0x812F
 
 
-ShellRenderInterfaceOpenGL::ShellRenderInterfaceOpenGL() : m_width(0), m_height(0), m_transforms(0), m_rmlui_context(nullptr)
+ShellRenderInterfaceOpenGL::ShellRenderInterfaceOpenGL() : m_width(0), m_height(0), m_transform_enabled(false), m_rmlui_context(nullptr)
 {
 {
 
 
 }
 }
@@ -97,7 +97,7 @@ void ShellRenderInterfaceOpenGL::ReleaseCompiledGeometry(Rml::Core::CompiledGeom
 void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable)
 void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable)
 {
 {
 	if (enable) {
 	if (enable) {
-		if (m_transforms <= 0) {
+		if (!m_transform_enabled) {
 			glEnable(GL_SCISSOR_TEST);
 			glEnable(GL_SCISSOR_TEST);
 			glDisable(GL_STENCIL_TEST);
 			glDisable(GL_STENCIL_TEST);
 		} else {
 		} else {
@@ -113,7 +113,7 @@ void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable)
 // Called by RmlUi when it wants to change the scissor region.		
 // Called by RmlUi when it wants to change the scissor region.		
 void ShellRenderInterfaceOpenGL::SetScissorRegion(int x, int y, int width, int height)
 void ShellRenderInterfaceOpenGL::SetScissorRegion(int x, int y, int width, int height)
 {
 {
-	if (m_transforms <= 0) {
+	if (!m_transform_enabled) {
 		glScissor(x, m_height - (y + height), width, height);
 		glScissor(x, m_height - (y + height), width, height);
 	} else {
 	} else {
 		// clear the stencil buffer
 		// clear the stencil buffer
@@ -282,21 +282,18 @@ void ShellRenderInterfaceOpenGL::ReleaseTexture(Rml::Core::TextureHandle texture
 }
 }
 
 
 // Called by RmlUi when it wants to set the current transform matrix to a new matrix.
 // Called by RmlUi when it wants to set the current transform matrix to a new matrix.
-void ShellRenderInterfaceOpenGL::PushTransform(const Rml::Core::Matrix4f& transform)
+void ShellRenderInterfaceOpenGL::SetTransform(const Rml::Core::Matrix4f* transform)
 {
 {
-	glPushMatrix();
-
-	if(std::is_same<Rml::Core::Matrix4f, Rml::Core::ColumnMajorMatrix4f>::value)
-		glLoadMatrixf(transform.data());
-	else if (std::is_same<Rml::Core::Matrix4f, Rml::Core::RowMajorMatrix4f>::value)
-		glLoadMatrixf(transform.Transpose().data());
+	m_transform_enabled = (bool)transform;
 
 
-	++m_transforms;
+	if (transform)
+	{
+		if (std::is_same<Rml::Core::Matrix4f, Rml::Core::ColumnMajorMatrix4f>::value)
+			glLoadMatrixf(transform->data());
+		else if (std::is_same<Rml::Core::Matrix4f, Rml::Core::RowMajorMatrix4f>::value)
+			glLoadMatrixf(transform->Transpose().data());
+	}
+	else
+		glLoadIdentity();
 }
 }
 
 
-// Called by RmlUi when it wants to revert the latest transform change.
-void ShellRenderInterfaceOpenGL::PopTransform(const Rml::Core::Matrix4f& transform)
-{
-	glPopMatrix();
-	--m_transforms;
-}

+ 1 - 4
Source/Core/Element.cpp

@@ -271,9 +271,6 @@ void Element::Render()
 	// Render the rest of the elements in the stacking context.
 	// Render the rest of the elements in the stacking context.
 	for (; i < stacking_context.size(); ++i)
 	for (; i < stacking_context.size(); ++i)
 		stacking_context[i]->Render();
 		stacking_context[i]->Render();
-
-	// Unapply our transform
-	ElementUtilities::UnapplyTransform(*this);
 }
 }
 
 
 // Clones this element, returning a new, unparented element.
 // Clones this element, returning a new, unparented element.
@@ -2451,7 +2448,7 @@ void Element::UpdateTransformState()
 
 
 	if (dirty_transform)
 	if (dirty_transform)
 	{
 	{
-		// We want to find the combined transform of all our ancestors. It is assumed here that the parent transform is already updated,
+		// We want to find the accumulated transform given all our ancestors. It is assumed here that the parent transform is already updated,
 		// so that we only need to consider our local transform and combine it with our parent's transform and perspective matrices.
 		// so that we only need to consider our local transform and combine it with our parent's transform and perspective matrices.
 		bool had_transform = (transform_state && transform_state->GetTransform());
 		bool had_transform = (transform_state && transform_state->GetTransform());
 
 

+ 13 - 16
Source/Core/ElementUtilities.cpp

@@ -347,32 +347,29 @@ bool ElementUtilities::PositionElement(Element* element, const Vector2f& offset,
 	return true;
 	return true;
 }
 }
 
 
-// Applies an element's `perspective' and `transform' properties.
-bool ElementUtilities::ApplyTransform(Element &element, bool apply)
+bool ElementUtilities::ApplyTransform(Element &element)
 {
 {
 	RenderInterface *render_interface = element.GetRenderInterface();
 	RenderInterface *render_interface = element.GetRenderInterface();
 	if (!render_interface)
 	if (!render_interface)
 		return false;
 		return false;
 
 
-	if(auto state = element.GetTransformState())
+	static SmallUnorderedMap<RenderInterface*, const Matrix4f*> previous_matrix;
+
+	const Matrix4f*& old_transform = previous_matrix.emplace(render_interface, nullptr).first->second;
+	const Matrix4f* new_transform = nullptr;
+
+	if (auto state = element.GetTransformState())
+		new_transform = state->GetTransform();
+
+	// Only changed transforms are submitted.
+	if (old_transform != new_transform)
 	{
 	{
-		if(auto transform = state->GetTransform())
-		{
-			if (apply)
-				render_interface->PushTransform(*transform);
-			else
-				render_interface->PopTransform(*transform);
-		}
+		render_interface->SetTransform(new_transform);
+		old_transform = new_transform;
 	}
 	}
 
 
 	return true;
 	return true;
 }
 }
 
 
-// Unapplies an element's `perspective' and `transform' properties.
-bool ElementUtilities::UnapplyTransform(Element &element)
-{
-	return ApplyTransform(element, false);
-}
-
 }
 }
 }
 }

+ 1 - 6
Source/Core/RenderInterface.cpp

@@ -95,12 +95,7 @@ void RenderInterface::ReleaseTexture(TextureHandle RMLUI_UNUSED_PARAMETER(textur
 }
 }
 
 
 // Called by RmlUi when it wants to change the current transform matrix to a new matrix.
 // Called by RmlUi when it wants to change the current transform matrix to a new matrix.
-void RenderInterface::PushTransform(const Matrix4f& transform)
-{
-}
-
-// Called by RmlUi when it wants to revert the latest transform change.
-void RenderInterface::PopTransform(const Matrix4f& transform)
+void RenderInterface::SetTransform(const Matrix4f* transform)
 {
 {
 }
 }
 
 

+ 17 - 7
Source/Core/TransformPrimitive.cpp

@@ -741,28 +741,38 @@ bool Primitive::InterpolateWith(const Primitive & other, float alpha) noexcept
 
 
 
 
 template<size_t N>
 template<size_t N>
-inline String ToString(const Transforms::ResolvedPrimitive<N>& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept {
+static inline String ToString(const Transforms::ResolvedPrimitive<N>& p, String unit, bool rad_to_deg = false, bool only_unit_on_last_value = false) noexcept {
 	float multiplier = 1.0f;
 	float multiplier = 1.0f;
-	if (rad_to_deg) multiplier = 180.f / Math::RMLUI_PI;
 	String tmp;
 	String tmp;
 	String result = "(";
 	String result = "(";
-	for (size_t i = 0; i < N; i++) {
+	for (size_t i = 0; i < N; i++) 
+	{
+		if (only_unit_on_last_value && i < N - 1)
+			multiplier = 1.0f;
+		else if (rad_to_deg) 
+			multiplier = 180.f / Math::RMLUI_PI;
+
 		if (TypeConverter<float, String>::Convert(p.values[i] * multiplier, tmp))
 		if (TypeConverter<float, String>::Convert(p.values[i] * multiplier, tmp))
 			result += tmp;
 			result += tmp;
+
 		if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
 		if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
 			result += unit;
 			result += unit;
-		if (i != N - 1) result += ", ";
+
+		if (i < N - 1)
+			result += ", ";
 	}
 	}
 	result += ")";
 	result += ")";
 	return result;
 	return result;
 }
 }
 
 
 template<size_t N>
 template<size_t N>
-inline String ToString(const Transforms::UnresolvedPrimitive<N> & p) noexcept {
+static inline String ToString(const Transforms::UnresolvedPrimitive<N> & p) noexcept {
 	String result = "(";
 	String result = "(";
-	for (size_t i = 0; i < N; i++) {
+	for (size_t i = 0; i < N; i++) 
+	{
 		result += p.values[i].ToString();
 		result += p.values[i].ToString();
-		if (i != N - 1) result += ", ";
+		if (i != N - 1) 
+			result += ", ";
 	}
 	}
 	result += ")";
 	result += ")";
 	return result;
 	return result;

+ 0 - 3
Source/Debugger/ElementInfo.cpp

@@ -218,7 +218,6 @@ void ElementInfo::RenderHoverElement()
 				1
 				1
 			);
 			);
 		}
 		}
-		Core::ElementUtilities::UnapplyTransform(*hover_element);
 	}
 	}
 }
 }
 
 
@@ -244,8 +243,6 @@ void ElementInfo::RenderSourceElement()
 			// Border area:
 			// Border area:
 			Geometry::RenderBox(source_element->GetAbsoluteOffset(Core::Box::BORDER) + element_box.GetPosition(Core::Box::MARGIN), element_box.GetSize(Core::Box::MARGIN), source_element->GetAbsoluteOffset(Core::Box::BORDER) + element_box.GetPosition(Core::Box::BORDER), element_box.GetSize(Core::Box::BORDER), Core::Colourb(240, 255, 131, 128));
 			Geometry::RenderBox(source_element->GetAbsoluteOffset(Core::Box::BORDER) + element_box.GetPosition(Core::Box::MARGIN), element_box.GetSize(Core::Box::MARGIN), source_element->GetAbsoluteOffset(Core::Box::BORDER) + element_box.GetPosition(Core::Box::BORDER), element_box.GetSize(Core::Box::BORDER), Core::Colourb(240, 255, 131, 128));
 		}
 		}
-
-		Core::ElementUtilities::UnapplyTransform(*source_element);
 	}
 	}
 }
 }
 
 

+ 0 - 2
Source/Debugger/Plugin.cpp

@@ -192,8 +192,6 @@ void Plugin::Render()
 
 
 					for (int j = 0; j < element->GetNumChildren(); ++j)
 					for (int j = 0; j < element->GetNumChildren(); ++j)
 						element_stack.push(element->GetChild(j));
 						element_stack.push(element->GetChild(j));
-					
-					Core::ElementUtilities::UnapplyTransform(*element);
 				}
 				}
 			}
 			}
 		}
 		}

+ 3 - 1
readme.md

@@ -233,9 +233,10 @@ The inner workings of transforms have been completely revised, resulting in incr
 
 
 Some relevant changes for users:
 Some relevant changes for users:
 - Removed the need for users to set the view and projection matrices they use outside the library.
 - Removed the need for users to set the view and projection matrices they use outside the library.
+- Replaced the `PushTransform()` and `PopTransform()` render interface functions with `SetTransform()`, which is only called when the transform matrix needs to change and never called if there are no `transform` properties present.
 - The `perspective` property now applies to the element's children, as in CSS.
 - The `perspective` property now applies to the element's children, as in CSS.
 - The transform function `perspective()` behaves like in CSS. It applies a perspective projection to the current element.
 - The transform function `perspective()` behaves like in CSS. It applies a perspective projection to the current element.
-- Chaining transforms and perspectives now provides more expected results. As opposed to CSS, we don't flatten transforms.
+- Chaining transforms and perspectives now provides more expected results. However, as opposed to CSS we don't flatten transforms.
 - Have a look at the updated transforms sample for some fun with 3d boxes.
 - Have a look at the updated transforms sample for some fun with 3d boxes.
 
 
 
 
@@ -256,6 +257,7 @@ Breaking changes since RmlUi v2.0.
 - Removed RenderInterface::GetPixelsPerInch, instead the pixels per inch value has been fixed to 96 PPI, as per CSS specs. To achieve a scalable user interface, instead use the 'dp' unit.
 - Removed RenderInterface::GetPixelsPerInch, instead the pixels per inch value has been fixed to 96 PPI, as per CSS specs. To achieve a scalable user interface, instead use the 'dp' unit.
 - Removed 'top' and 'bottom' from z-index property.
 - Removed 'top' and 'bottom' from z-index property.
 - See changes to the declaration of decorators and font-effects above.
 - See changes to the declaration of decorators and font-effects above.
+- See changes to the render interface regarding transforms above.
 - Also, see removal of manual reference counting above.
 - Also, see removal of manual reference counting above.