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 "XMLParser.h"
 #include "Header.h"
+#include "Element.h"
 
 namespace Rml {
 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.
 	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] 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.
 	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,
 	/// 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 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;
 
 	// Local perspective which applies to children of the owning element.
 	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;
 };
 

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

@@ -56,7 +56,6 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 	width: 200px;
 	height: 200px;
 	margin: 75px auto;
-	border: none;
 	background-color: #a003;
 }
 
@@ -74,7 +73,6 @@ scrollbarvertical sliderbar:hover,scrollbarvertical sliderbar:active
 	position: absolute;
 	width: 100px;
 	height: 100px;
-	border: none;
 	line-height: 100px;
 	font-size: 60px;
 	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
 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
 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)
 	{
 		perspective = distance;
+
+		if (document && perspective > 0)
+		{
+			std::stringstream s;
+			s << "perspective(" << perspective << "px) ";
+			document->SetProperty("transform", s.str().c_str());
+		}
 	}
 
 	void SetRotation(float degrees)

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

@@ -66,10 +66,7 @@ public:
 	void ReleaseTexture(Rml::Core::TextureHandle texture_handle) override;
 
 	/// 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
 	void SetViewport(int width, int height) override;
@@ -82,7 +79,7 @@ public:
 protected:
 	int m_width;
 	int m_height;
-	int m_transforms;
+	bool m_transform_enabled;
 	void *m_rmlui_context;
 	
 #if defined(RMLUI_PLATFORM_MACOSX)

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

@@ -33,7 +33,7 @@
 
 #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)
 {
 	if (enable) {
-		if (m_transforms <= 0) {
+		if (!m_transform_enabled) {
 			glEnable(GL_SCISSOR_TEST);
 			glDisable(GL_STENCIL_TEST);
 		} else {
@@ -113,7 +113,7 @@ void ShellRenderInterfaceOpenGL::EnableScissorRegion(bool enable)
 // Called by RmlUi when it wants to change the scissor region.		
 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);
 	} else {
 		// 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.
-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.
 	for (; i < stacking_context.size(); ++i)
 		stacking_context[i]->Render();
-
-	// Unapply our transform
-	ElementUtilities::UnapplyTransform(*this);
 }
 
 // Clones this element, returning a new, unparented element.
@@ -2451,7 +2448,7 @@ void Element::UpdateTransformState()
 
 	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.
 		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;
 }
 
-// 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();
 	if (!render_interface)
 		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;
 }
 
-// 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.
-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>
-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;
-	if (rad_to_deg) multiplier = 180.f / Math::RMLUI_PI;
 	String tmp;
 	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))
 			result += tmp;
+
 		if (!unit.empty() && (!only_unit_on_last_value || (i == N - 1)))
 			result += unit;
-		if (i != N - 1) result += ", ";
+
+		if (i < N - 1)
+			result += ", ";
 	}
 	result += ")";
 	return result;
 }
 
 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 = "(";
-	for (size_t i = 0; i < N; i++) {
+	for (size_t i = 0; i < N; i++) 
+	{
 		result += p.values[i].ToString();
-		if (i != N - 1) result += ", ";
+		if (i != N - 1) 
+			result += ", ";
 	}
 	result += ")";
 	return result;

+ 0 - 3
Source/Debugger/ElementInfo.cpp

@@ -218,7 +218,6 @@ void ElementInfo::RenderHoverElement()
 				1
 			);
 		}
-		Core::ElementUtilities::UnapplyTransform(*hover_element);
 	}
 }
 
@@ -244,8 +243,6 @@ void ElementInfo::RenderSourceElement()
 			// 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));
 		}
-
-		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)
 						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:
 - 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 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.
 
 
@@ -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 'top' and 'bottom' from z-index property.
 - 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.