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="help">Help</button><br />
 	<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>
 <tab>Controls</tab>
 <panel>

+ 50 - 39
Source/Core/ElementImage.cpp

@@ -35,9 +35,8 @@ namespace Rml {
 namespace Core {
 
 // 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;
 	texture_dirty = true;
 }
@@ -56,16 +55,16 @@ bool ElementImage::GetIntrinsicDimensions(Vector2f& _dimensions)
 	// Calculate the x dimension.
 	if (HasAttribute("width"))
 		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
 		dimensions.x = (float) texture.GetDimensions(GetRenderInterface()).x;
 
 	// Calculate the y dimension.
 	if (HasAttribute("height"))
 		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
 		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
-	// 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"))
 		{
 			StringList coords_list;
-			StringUtilities::ExpandString(coords_list, GetAttribute< String >("coords", ""));
+			StringUtilities::ExpandString(coords_list, GetAttribute< String >("coords", ""), ' ');
 
 			if (coords_list.size() != 4)
 			{
@@ -127,22 +126,15 @@ void ElementImage::OnAttributeChange(const Rml::Core::ElementAttributes& changed
 			}
 			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
@@ -185,7 +177,7 @@ void ElementImage::GenerateGeometry()
 
 	// Generate the texture coordinates.
 	Vector2f texcoords[2];
-	if (using_coords)
+	if (coords_source != CoordsSource::None)
 	{
 		Vector2f texture_dimensions((float) texture.GetDimensions(GetRenderInterface()).x, (float) texture.GetDimensions(GetRenderInterface()).y);
 		if (texture_dimensions.x == 0)
@@ -193,11 +185,11 @@ void ElementImage::GenerateGeometry()
 		if (texture_dimensions.y == 0)
 			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
 	{
@@ -222,17 +214,38 @@ bool ElementImage::LoadTexture()
 {
 	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;
 
 	geometry_dirty = true;
 
+	bool valid_sprite = false;
+	URL source_url;
+
 	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.
 	geometry.SetTexture(&texture);
@@ -241,10 +254,8 @@ bool ElementImage::LoadTexture()
 
 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.
 	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.
-	int coords[4];
-	bool using_coords;
+	Rectangle coords;
+	enum class CoordsSource { None, Attribute, Sprite } coords_source;
 
 	// The geometry used to render this element.
 	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.
 
 
-### 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.
 - 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 `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 `\<img\>` element can now take sprite names in its `src` attribute.
 
 
 ### Breaking changes
@@ -388,7 +389,7 @@ Breaking changes since RmlUi v2.0.
 - 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 '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 render interface regarding transforms above.
 - The focus flag in `ElementDocument::Show` has been changed, with a new enum name and new options, see above.