Browse Source

Make font effects handle the opacity property, see #270

Michael Ragazzon 3 years ago
parent
commit
296767d60e

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

@@ -117,6 +117,7 @@ private:
 	bool geometry_dirty;
 	bool geometry_dirty;
 
 
 	Colourb colour;
 	Colourb colour;
+	float opacity;
 
 
 	// The decoration geometry we've generated for this string.
 	// The decoration geometry we've generated for this string.
 	Geometry decoration;
 	Geometry decoration;

+ 4 - 2
Include/RmlUi/Core/FontEngineInterface.h

@@ -117,10 +117,12 @@ public:
 	/// @param[in] font_effects_handle The handle to the prepared font effects for which the geometry should be generated.
 	/// @param[in] font_effects_handle The handle to the prepared font effects for which the geometry should be generated.
 	/// @param[in] string The string to render.
 	/// @param[in] string The string to render.
 	/// @param[in] position The position of the baseline of the first character to render.
 	/// @param[in] position The position of the baseline of the first character to render.
-	/// @param[in] colour The colour to render the text.
+	/// @param[in] colour The colour to render the text. Colour alpha is premultiplied with opacity.
+	/// @param[in] opacity The opacity of the text, should be applied to font effects.
 	/// @param[out] geometry An array of geometries to generate the geometry into.
 	/// @param[out] geometry An array of geometries to generate the geometry into.
 	/// @return The width, in pixels, of the string geometry.
 	/// @return The width, in pixels, of the string geometry.
-	virtual int GenerateString(FontFaceHandle face_handle, FontEffectsHandle font_effects_handle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry);
+	virtual int GenerateString(FontFaceHandle face_handle, FontEffectsHandle font_effects_handle, const String& string, const Vector2f& position,
+		const Colourb& colour, float opacity, GeometryList& geometry);
 
 
 	/// Called by RmlUi to determine if the text geometry is required to be re-generated. Whenever the returned version
 	/// Called by RmlUi to determine if the text geometry is required to be re-generated. Whenever the returned version
 	/// is changed, all geometry belonging to the given face handle will be re-generated.
 	/// is changed, all geometry belonging to the given face handle will be re-generated.

+ 15 - 5
Source/Core/ElementText.cpp

@@ -44,7 +44,7 @@ namespace Rml {
 static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation, bool decode_escape_characters);
 static bool BuildToken(String& token, const char*& token_begin, const char* string_end, bool first_token, bool collapse_white_space, bool break_at_endline, Style::TextTransform text_transformation, bool decode_escape_characters);
 static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline);
 static bool LastToken(const char* token_begin, const char* string_end, bool collapse_white_space, bool break_at_endline);
 
 
-ElementText::ElementText(const String& tag) : Element(tag), colour(255, 255, 255), decoration(this)
+ElementText::ElementText(const String& tag) : Element(tag), colour(255, 255, 255), opacity(1), decoration(this)
 {
 {
 	dirty_layout_on_change = true;
 	dirty_layout_on_change = true;
 
 
@@ -355,13 +355,23 @@ void ElementText::OnPropertyChange(const PropertyIdSet& changed_properties)
 	if (changed_properties.Contains(PropertyId::Color) ||
 	if (changed_properties.Contains(PropertyId::Color) ||
 		changed_properties.Contains(PropertyId::Opacity))
 		changed_properties.Contains(PropertyId::Opacity))
 	{
 	{
-		// Fetch our (potentially) new colour.
+		const float new_opacity = computed.opacity;
+		const bool opacity_changed = opacity != new_opacity;
+
 		Colourb new_colour = computed.color;
 		Colourb new_colour = computed.color;
-		float opacity = computed.opacity;
-		new_colour.alpha = byte(opacity * float(new_colour.alpha));
+		new_colour.alpha = byte(new_opacity * float(new_colour.alpha));
 		colour_changed = colour != new_colour;
 		colour_changed = colour != new_colour;
+
 		if (colour_changed)
 		if (colour_changed)
+		{
 			colour = new_colour;
 			colour = new_colour;
+		}
+		if (opacity_changed)
+		{
+			opacity = new_opacity;
+			font_effects_dirty = true;
+			geometry_dirty = true;
+		}
 	}
 	}
 
 
 	if (changed_properties.Contains(PropertyId::FontFamily) ||
 	if (changed_properties.Contains(PropertyId::FontFamily) ||
@@ -465,7 +475,7 @@ void ElementText::GenerateGeometry(const FontFaceHandle font_face_handle)
 
 
 void ElementText::GenerateGeometry(const FontFaceHandle font_face_handle, Line& line)
 void ElementText::GenerateGeometry(const FontFaceHandle font_face_handle, Line& line)
 {
 {
-	line.width = GetFontEngineInterface()->GenerateString(font_face_handle, font_effects_handle, line.text, line.position, colour, geometry);
+	line.width = GetFontEngineInterface()->GenerateString(font_face_handle, font_effects_handle, line.text, line.position, colour, opacity, geometry);
 	for (size_t i = 0; i < geometry.size(); ++i)
 	for (size_t i = 0; i < geometry.size(); ++i)
 		geometry[i].SetHostElement(this);
 		geometry[i].SetHostElement(this);
 }
 }

+ 2 - 2
Source/Core/FontEngineDefault/FontEngineInterfaceDefault.cpp

@@ -101,10 +101,10 @@ int FontEngineInterfaceDefault::GetStringWidth(FontFaceHandle handle, const Stri
 }
 }
 
 
 int FontEngineInterfaceDefault::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string,
 int FontEngineInterfaceDefault::GenerateString(FontFaceHandle handle, FontEffectsHandle font_effects_handle, const String& string,
-	const Vector2f& position, const Colourb& colour, GeometryList& geometry)
+	const Vector2f& position, const Colourb& colour, float opacity, GeometryList& geometry)
 {
 {
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
 	auto handle_default = reinterpret_cast<FontFaceHandleDefault *>(handle);
-	return handle_default->GenerateString(geometry, string, position, colour, (int)font_effects_handle);
+	return handle_default->GenerateString(geometry, string, position, colour, opacity, (int)font_effects_handle);
 }
 }
 
 
 int FontEngineInterfaceDefault::GetVersion(FontFaceHandle handle)
 int FontEngineInterfaceDefault::GetVersion(FontFaceHandle handle)

+ 2 - 1
Source/Core/FontEngineDefault/FontEngineInterfaceDefault.h

@@ -69,7 +69,8 @@ public:
 	int GetStringWidth(FontFaceHandle, const String& string, Character prior_character) override;
 	int GetStringWidth(FontFaceHandle, const String& string, Character prior_character) override;
 
 
 	/// Generates the geometry required to render a single line of text.
 	/// Generates the geometry required to render a single line of text.
-	int GenerateString(FontFaceHandle, FontEffectsHandle, const String& string, const Vector2f& position, const Colourb& colour, GeometryList& geometry) override;
+	int GenerateString(FontFaceHandle, FontEffectsHandle, const String& string, const Vector2f& position, const Colourb& colour, float opacity,
+		GeometryList& geometry) override;
 
 
 	/// Returns the current version of the font face.
 	/// Returns the current version of the font face.
 	int GetVersion(FontFaceHandle handle) override;
 	int GetVersion(FontFaceHandle handle) override;

+ 8 - 1
Source/Core/FontEngineDefault/FontFaceHandleDefault.cpp

@@ -218,7 +218,8 @@ bool FontFaceHandleDefault::GenerateLayerTexture(UniquePtr<const byte[]>& textur
 }
 }
 
 
 // Generates the geometry required to render a single line of text.
 // Generates the geometry required to render a single line of text.
-int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const String& string, const Vector2f position, const Colourb colour, int layer_configuration_index)
+int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const String& string, const Vector2f position, const Colourb colour,
+	const float opacity, const int layer_configuration_index)
 {
 {
 	int geometry_index = 0;
 	int geometry_index = 0;
 	int line_width = 0;
 	int line_width = 0;
@@ -240,9 +241,15 @@ int FontFaceHandleDefault::GenerateString(GeometryList& geometry, const String&
 
 
 		Colourb layer_colour;
 		Colourb layer_colour;
 		if (layer == base_layer)
 		if (layer == base_layer)
+		{
 			layer_colour = colour;
 			layer_colour = colour;
+		}
 		else
 		else
+		{
 			layer_colour = layer->GetColour();
 			layer_colour = layer->GetColour();
+			if (opacity < 1.f)
+				layer_colour.alpha = byte(opacity * float(layer_colour.alpha));
+		}
 
 
 		const int num_textures = layer->GetNumTextures();
 		const int num_textures = layer->GetNumTextures();
 
 

+ 3 - 1
Source/Core/FontEngineDefault/FontFaceHandleDefault.h

@@ -92,8 +92,10 @@ public:
 	/// @param[in] string The string to render.
 	/// @param[in] string The string to render.
 	/// @param[in] position The position of the baseline of the first character to render.
 	/// @param[in] position The position of the baseline of the first character to render.
 	/// @param[in] colour The colour to render the text.
 	/// @param[in] colour The colour to render the text.
+	/// @param[in] opacity The opacity of the text, should be applied to font effects.
+	/// @param[in] layer_configuration Face configuration index to use for generating string.
 	/// @return The width, in pixels, of the string geometry.
 	/// @return The width, in pixels, of the string geometry.
-	int GenerateString(GeometryList& geometry, const String& string, Vector2f position, Colourb colour, int layer_configuration = 0);
+	int GenerateString(GeometryList& geometry, const String& string, Vector2f position, Colourb colour, float opacity, int layer_configuration = 0);
 
 
 	/// Version is changed whenever the layers are dirtied, requiring regeneration of string geometry.
 	/// Version is changed whenever the layers are dirtied, requiring regeneration of string geometry.
 	int GetVersion() const;
 	int GetVersion() const;

+ 9 - 13
Source/Core/FontEngineInterface.cpp

@@ -15,7 +15,7 @@
  *
  *
  * The above copyright notice and this permission notice shall be included in
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -30,31 +30,27 @@
 
 
 namespace Rml {
 namespace Rml {
 
 
-FontEngineInterface::FontEngineInterface()
-{
-}
+FontEngineInterface::FontEngineInterface() {}
 
 
-FontEngineInterface::~FontEngineInterface()
-{
-}
+FontEngineInterface::~FontEngineInterface() {}
 
 
 bool FontEngineInterface::LoadFontFace(const String& /*file_name*/, bool /*fallback_face*/)
 bool FontEngineInterface::LoadFontFace(const String& /*file_name*/, bool /*fallback_face*/)
 {
 {
 	return false;
 	return false;
 }
 }
 
 
-bool FontEngineInterface::LoadFontFace(const byte* /*data*/, int /*data_size*/, const String& /*font_family*/,
-	Style::FontStyle /*style*/, Style::FontWeight /*weight*/, bool /*fallback_face*/)
+bool FontEngineInterface::LoadFontFace(const byte* /*data*/, int /*data_size*/, const String& /*font_family*/, Style::FontStyle /*style*/,
+	Style::FontWeight /*weight*/, bool /*fallback_face*/)
 {
 {
 	return false;
 	return false;
 }
 }
 
 
-FontFaceHandle FontEngineInterface::GetFontFaceHandle(const String& /*family*/, Style::FontStyle /*style*/,
-	Style::FontWeight /*weight*/, int /*size*/)
+FontFaceHandle FontEngineInterface::GetFontFaceHandle(const String& /*family*/, Style::FontStyle /*style*/, Style::FontWeight /*weight*/,
+	int /*size*/)
 {
 {
 	return 0;
 	return 0;
 }
 }
-	
+
 FontEffectsHandle FontEngineInterface::PrepareFontEffects(FontFaceHandle /*handle*/, const FontEffectList& /*font_effects*/)
 FontEffectsHandle FontEngineInterface::PrepareFontEffects(FontFaceHandle /*handle*/, const FontEffectList& /*font_effects*/)
 {
 {
 	return 0;
 	return 0;
@@ -91,7 +87,7 @@ int FontEngineInterface::GetStringWidth(FontFaceHandle /*handle*/, const String&
 }
 }
 
 
 int FontEngineInterface::GenerateString(FontFaceHandle /*face_handle*/, FontEffectsHandle /*font_effects_handle*/, const String& /*string*/,
 int FontEngineInterface::GenerateString(FontFaceHandle /*face_handle*/, FontEffectsHandle /*font_effects_handle*/, const String& /*string*/,
-	const Vector2f& /*position*/, const Colourb& /*colour*/, GeometryList& /*geometry*/)
+	const Vector2f& /*position*/, const Colourb& /*colour*/, float /*opacity*/, GeometryList& /*geometry*/)
 {
 {
 	return 0;
 	return 0;
 }
 }

+ 59 - 0
Tests/Data/VisualTests/opacity.rml

@@ -0,0 +1,59 @@
+<rml>
+<head>
+    <title>Opacity</title>
+    <link type="text/rcss" href="../style.rcss"/>
+	<link rel="Issue #270" href="https://github.com/mikke89/RmlUi/issues/270" />
+	<meta name="Description" content="Opacity should also apply to font effects." />
+	<style>
+		h1 {
+			margin-top: 2em;
+			font-size: 1.1em;
+		}
+		p {
+			margin-left: 2em;
+		}
+		.red {
+			color: #f00;
+		}
+		.translucent {
+			opacity: 0.25;
+		}
+		.invisible {
+			opacity: 0.0;
+		}
+		.font_effect {
+			font-effect: outline(2px #f00);
+			color: #ff0;
+		}
+		.red.alpha {
+			color: #f004;
+		}
+		.font_effect.alpha {
+			font-effect: outline(2px #f004);
+			color: #ff04;
+		}
+	</style>
+</head>
+
+<body>
+	<h1>Reference.</h1>
+	<p class="red">This is some text.</p>
+	<p class="font_effect">This is some text.</p>
+	
+	<h1>Translucent.</h1>
+	<p class="red translucent">This is some text.</p>
+	<p class="font_effect translucent">This is some text.</p>
+	
+	<h1>Invisible, there should be no red text below.</h1>
+	<p class="red invisible">This is some text.</p>
+	<p class="font_effect invisible">This is some text.</p>
+	
+	<h1>Color with alpha channel.</h1>
+	<p class="red alpha">This is some text.</p>
+	<p class="font_effect alpha">This is some text.</p>
+	
+	<h1>Color with alpha channel and translucency.</h1>
+	<p class="red alpha translucent">This is some text.</p>
+	<p class="font_effect alpha translucent">This is some text.</p>	
+</body>
+</rml>

+ 5 - 0
changelog.md

@@ -15,6 +15,7 @@
 - Release memory pools on `Rml::Shutdown`, or manually through the core API. [#263](https://github.com/mikke89/RmlUi/issues/263) [#265](https://github.com/mikke89/RmlUi/pull/265) (thanks @jack9267)
 - Release memory pools on `Rml::Shutdown`, or manually through the core API. [#263](https://github.com/mikke89/RmlUi/issues/263) [#265](https://github.com/mikke89/RmlUi/pull/265) (thanks @jack9267)
 - Fix classes not always copied over to a cloned element. [#264](https://github.com/mikke89/RmlUi/issues/264)
 - Fix classes not always copied over to a cloned element. [#264](https://github.com/mikke89/RmlUi/issues/264)
 - `select` element: Fix clipping on select box.
 - `select` element: Fix clipping on select box.
+- The `opacity` property is now also applied to font effects. [#270](https://github.com/mikke89/RmlUi/issues/270)
 
 
 ### Layout
 ### Layout
 
 
@@ -24,6 +25,10 @@
 
 
 - New sample for integration with SDL2's native renderer. [#252](https://github.com/mikke89/RmlUi/pull/252) (thanks @1bsyl)
 - New sample for integration with SDL2's native renderer. [#252](https://github.com/mikke89/RmlUi/pull/252) (thanks @1bsyl)
 
 
+### Breaking changes
+
+- `FontEngineInterface::GenerateString` now takes a new argument, `opacity`.
+
 
 
 ## RmlUi 4.3
 ## RmlUi 4.3