Browse Source

Support sprites in img elements.

Michael Ragazzon 6 years ago
parent
commit
5b6428fa43
4 changed files with 61 additions and 44 deletions
  1. 5 0
      Samples/basic/demo/data/demo.rml
  2. 50 39
      Source/Core/ElementImage.cpp
  3. 3 3
      Source/Core/ElementImage.h
  4. 3 2
      readme.md

+ 5 - 0
Samples/basic/demo/data/demo.rml

@@ -226,6 +226,11 @@ textarea {
 	<button id="options">Options</button><br />
 	<button id="options">Options</button><br />
 	<button id="help">Help</button><br />
 	<button id="help">Help</button><br />
 	<div><button id="exit" onclick="exit">Exit</button></div>
 	<div><button id="exit" onclick="exit">Exit</button></div>
+	<img src="../../../assets/high_scores_defender.tga"/>
+	<img src="icon-game" style="vertical-align: 10px;"/>
+	<img src="../../../assets/high_scores_defender.tga" style="image-color: #fc5;" coords="0 0 64 64"/>
+	<img src="../../../assets/high_scores_defender.tga" style="image-color: #9c5;" coords="64 0 64 64"/>
+	<p>Img elements can take both sprites and images. For images it also supports a 'coords' attribute for specifying a sub-rectangle.</p>
 </panel>
 </panel>
 <tab>Controls</tab>
 <tab>Controls</tab>
 <panel>
 <panel>

+ 50 - 39
Source/Core/ElementImage.cpp

@@ -35,9 +35,8 @@ namespace Rml {
 namespace Core {
 namespace Core {
 
 
 // Constructs a new ElementImage.
 // Constructs a new ElementImage.
-ElementImage::ElementImage(const String& tag) : Element(tag), dimensions(-1, -1), geometry(this)
+ElementImage::ElementImage(const String& tag) : Element(tag), dimensions(-1, -1), coords_source(CoordsSource::None), geometry(this)
 {
 {
-	ResetCoords();
 	geometry_dirty = false;
 	geometry_dirty = false;
 	texture_dirty = true;
 	texture_dirty = true;
 }
 }
@@ -56,16 +55,16 @@ bool ElementImage::GetIntrinsicDimensions(Vector2f& _dimensions)
 	// Calculate the x dimension.
 	// Calculate the x dimension.
 	if (HasAttribute("width"))
 	if (HasAttribute("width"))
 		dimensions.x = GetAttribute< float >("width", -1);
 		dimensions.x = GetAttribute< float >("width", -1);
-	else if (using_coords)
-		dimensions.x = (float) (coords[2] - coords[0]);
+	else if (coords_source != CoordsSource::None)
+		dimensions.x = coords.width;
 	else
 	else
 		dimensions.x = (float) texture.GetDimensions(GetRenderInterface()).x;
 		dimensions.x = (float) texture.GetDimensions(GetRenderInterface()).x;
 
 
 	// Calculate the y dimension.
 	// Calculate the y dimension.
 	if (HasAttribute("height"))
 	if (HasAttribute("height"))
 		dimensions.y = GetAttribute< float >("height", -1);
 		dimensions.y = GetAttribute< float >("height", -1);
-	else if (using_coords)
-		dimensions.y = (float) (coords[3] - coords[1]);
+	else if (coords_source != CoordsSource::None)
+		dimensions.y = coords.height;
 	else
 	else
 		dimensions.y = (float) texture.GetDimensions(GetRenderInterface()).y;
 		dimensions.y = (float) texture.GetDimensions(GetRenderInterface()).y;
 
 
@@ -112,13 +111,13 @@ void ElementImage::OnAttributeChange(const Rml::Core::ElementAttributes& changed
 	}
 	}
 
 
 	// Check for a change to the 'coords' attribute. If this changes, the coordinates are
 	// Check for a change to the 'coords' attribute. If this changes, the coordinates are
-	// recomputed and a layout forced.
-	if (changed_attributes.find("coords") != changed_attributes.end())
+	// recomputed and a layout forced. If a sprite is set to source, then that will override any attribute.
+	if (changed_attributes.find("coords") != changed_attributes.end() && coords_source != CoordsSource::Sprite)
 	{
 	{
 		if (HasAttribute("coords"))
 		if (HasAttribute("coords"))
 		{
 		{
 			StringList coords_list;
 			StringList coords_list;
-			StringUtilities::ExpandString(coords_list, GetAttribute< String >("coords", ""));
+			StringUtilities::ExpandString(coords_list, GetAttribute< String >("coords", ""), ' ');
 
 
 			if (coords_list.size() != 4)
 			if (coords_list.size() != 4)
 			{
 			{
@@ -127,22 +126,15 @@ void ElementImage::OnAttributeChange(const Rml::Core::ElementAttributes& changed
 			}
 			}
 			else
 			else
 			{
 			{
-				for (size_t i = 0; i < 4; ++i)
-					coords[i] = atoi(coords_list[i].c_str());
-
-				// Check for the validity of the coordinates.
-				if (coords[0] < 0 || coords[2] < coords[0] ||
-					coords[1] < 0 || coords[3] < coords[1])
-				{
-					Rml::Core::Log::Message(Log::LT_WARNING, "Element '%s' has an invalid 'coords' attribute; invalid coordinate values specified.", GetAddress().c_str());
-					ResetCoords();
-				}
-				else
-				{
-					// We have new, valid coordinates; force the geometry to be regenerated.
-					geometry_dirty = true;
-					using_coords = true;
-				}
+				coords.x = (float)std::atof(coords_list[0].c_str());
+				coords.y = (float)std::atof(coords_list[1].c_str());
+				coords.width = (float)std::atof(coords_list[2].c_str());
+				coords.height = (float)std::atof(coords_list[3].c_str());
+
+				// We have new, valid coordinates; force the geometry to be regenerated.
+				geometry_dirty = true;
+				coords_source = CoordsSource::Attribute;
+
 			}
 			}
 		}
 		}
 		else
 		else
@@ -185,7 +177,7 @@ void ElementImage::GenerateGeometry()
 
 
 	// Generate the texture coordinates.
 	// Generate the texture coordinates.
 	Vector2f texcoords[2];
 	Vector2f texcoords[2];
-	if (using_coords)
+	if (coords_source != CoordsSource::None)
 	{
 	{
 		Vector2f texture_dimensions((float) texture.GetDimensions(GetRenderInterface()).x, (float) texture.GetDimensions(GetRenderInterface()).y);
 		Vector2f texture_dimensions((float) texture.GetDimensions(GetRenderInterface()).x, (float) texture.GetDimensions(GetRenderInterface()).y);
 		if (texture_dimensions.x == 0)
 		if (texture_dimensions.x == 0)
@@ -193,11 +185,11 @@ void ElementImage::GenerateGeometry()
 		if (texture_dimensions.y == 0)
 		if (texture_dimensions.y == 0)
 			texture_dimensions.y = 1;
 			texture_dimensions.y = 1;
 
 
-		texcoords[0].x = (float) coords[0] / texture_dimensions.x;
-		texcoords[0].y = (float) coords[1] / texture_dimensions.y;
+		texcoords[0].x = coords.x / texture_dimensions.x;
+		texcoords[0].y = coords.y / texture_dimensions.y;
 
 
-		texcoords[1].x = (float) coords[2] / texture_dimensions.x;
-		texcoords[1].y = (float) coords[3] / texture_dimensions.y;
+		texcoords[1].x = (coords.x + coords.width) / texture_dimensions.x;
+		texcoords[1].y = (coords.y + coords.height) / texture_dimensions.y;
 	}
 	}
 	else
 	else
 	{
 	{
@@ -222,17 +214,38 @@ bool ElementImage::LoadTexture()
 {
 {
 	texture_dirty = false;
 	texture_dirty = false;
 
 
-	// Get the source URL for the image.
-	String image_source = GetAttribute< String >("src", "");
-	if (image_source.empty())
+	// Get the sprite name or image source URL.
+	const String source_name = GetAttribute< String >("src", "");
+	if (source_name.empty())
 		return false;
 		return false;
 
 
 	geometry_dirty = true;
 	geometry_dirty = true;
 
 
+	bool valid_sprite = false;
+	URL source_url;
+
 	Rml::Core::ElementDocument* document = GetOwnerDocument();
 	Rml::Core::ElementDocument* document = GetOwnerDocument();
-	URL source_url(document == nullptr ? "" : document->GetSourceURL());
 
 
-	texture.Set(image_source, source_url.GetPath());
+	// Check if the name is a sprite first, otherwise treat it as an image url.
+	if (document) 
+	{
+		if (auto& style_sheet = document->GetStyleSheet())
+		{
+			if (const Sprite* sprite = style_sheet->GetSprite(source_name))
+			{
+				coords = sprite->rectangle;
+				coords_source = CoordsSource::Sprite;
+				texture = sprite->sprite_sheet->texture;
+				valid_sprite = true;
+			}
+		}
+
+		if(!valid_sprite)
+			source_url.SetURL(document->GetSourceURL());
+	}
+
+	if(!valid_sprite)
+		texture.Set(source_name, source_url.GetPath());
 
 
 	// Set the texture onto our geometry object.
 	// Set the texture onto our geometry object.
 	geometry.SetTexture(&texture);
 	geometry.SetTexture(&texture);
@@ -241,10 +254,8 @@ bool ElementImage::LoadTexture()
 
 
 void ElementImage::ResetCoords()
 void ElementImage::ResetCoords()
 {
 {
-	using_coords = false;
-
-	for (int i = 0; i < 4; ++i)
-		coords[i] = -1;
+	coords = {};
+	coords_source = CoordsSource::None;
 }
 }
 
 
 }
 }

+ 3 - 3
Source/Core/ElementImage.h

@@ -106,10 +106,10 @@ private:
 	// that dimension has not been computed yet.
 	// that dimension has not been computed yet.
 	Vector2f dimensions;
 	Vector2f dimensions;
 
 
-	// The integer coords extracted from the 'coords' attribute. using_coords will be false if
+	// The coords extracted from the sprite or 'coords' attribute. The coords_source will be None if
 	// these have not been specified or are invalid.
 	// these have not been specified or are invalid.
-	int coords[4];
-	bool using_coords;
+	Rectangle coords;
+	enum class CoordsSource { None, Attribute, Sprite } coords_source;
 
 
 	// The geometry used to render this element.
 	// The geometry used to render this element.
 	Geometry geometry;
 	Geometry geometry;

+ 3 - 2
readme.md

@@ -369,13 +369,14 @@ Three new CMake options added.
 - `ENABLE_TRACY_PROFILING`: RmlUi has parts of the library tagged with markers for profiling with [Tracy Profiler](https://bitbucket.org/wolfpld/tracy/src/master/). This enables a visual inspection of bottlenecks and slowdowns on individual frames. To compile the library with profiling support, add the Tracy Profiler library to `/Dependencies/tracy/`, enable this option, and compile.  Follow the Tracy Profiler instructions to build and connect the separate viewer. As users may want to only use profiling for specific compilation targets, then instead one can `#define RMLUI_ENABLE_PROFILING` for the given target.
 - `ENABLE_TRACY_PROFILING`: RmlUi has parts of the library tagged with markers for profiling with [Tracy Profiler](https://bitbucket.org/wolfpld/tracy/src/master/). This enables a visual inspection of bottlenecks and slowdowns on individual frames. To compile the library with profiling support, add the Tracy Profiler library to `/Dependencies/tracy/`, enable this option, and compile.  Follow the Tracy Profiler instructions to build and connect the separate viewer. As users may want to only use profiling for specific compilation targets, then instead one can `#define RMLUI_ENABLE_PROFILING` for the given target.
 
 
 
 
-### Other changes
+### Other features
 
 
 - `Context::ProcessMouseWheel` now takes a float value for the `wheel_delta` property, thereby enabling continuous/smooth scrolling for input devices with such support. The default scroll length for unity value of `wheel_delta` is now three times the default line-height multiplied by the current dp-ratio.
 - `Context::ProcessMouseWheel` now takes a float value for the `wheel_delta` property, thereby enabling continuous/smooth scrolling for input devices with such support. The default scroll length for unity value of `wheel_delta` is now three times the default line-height multiplied by the current dp-ratio.
 - The system interface now has two new functions for setting and getting text to and from the clipboard: `virtual void SystemInterface::SetClipboardText(const Core::String& text)` and `virtual void SystemInterface::GetClipboardText(Core::String& text)`.
 - The system interface now has two new functions for setting and getting text to and from the clipboard: `virtual void SystemInterface::SetClipboardText(const Core::String& text)` and `virtual void SystemInterface::GetClipboardText(Core::String& text)`.
 - The debugger now has the ability to clear the log. Additionally, the displayed element information updates when the element changes.
 - The debugger now has the ability to clear the log. Additionally, the displayed element information updates when the element changes.
 - The `text-decoration` property can now also be used with `overline` and `line-through`.
 - The `text-decoration` property can now also be used with `overline` and `line-through`.
 - The text input and text area elements can be navigated word for word by holding the 'ctrl' key.
 - The text input and text area elements can be navigated word for word by holding the 'ctrl' key.
+- The `\<img\>` element can now take sprite names in its `src` attribute.
 
 
 
 
 ### Breaking changes
 ### Breaking changes
@@ -388,7 +389,7 @@ Breaking changes since RmlUi v2.0.
 - The Controls::DataGrid "min-rows" property has been removed.
 - The Controls::DataGrid "min-rows" property has been removed.
 - 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.
-- Anglees need to be declared in either 'deg' or 'rad', unit-less numbers do not work.
+- Angles need to be declared in either 'deg' or 'rad', unit-less numbers do not work.
 - 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.
 - See changes to the render interface regarding transforms above.
 - The focus flag in `ElementDocument::Show` has been changed, with a new enum name and new options, see above.
 - The focus flag in `ElementDocument::Show` has been changed, with a new enum name and new options, see above.