浏览代码

img element: Sprites are now specified by the `sprite` attribute, and the `coords` attribute is renamed to `rect`.

Michael Ragazzon 6 年之前
父节点
当前提交
eba2a91520
共有 3 个文件被更改,包括 115 次插入89 次删除
  1. 5 5
      Samples/basic/demo/data/demo.rml
  2. 94 68
      Source/Core/ElementImage.cpp
  3. 16 16
      Source/Core/ElementImage.h

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

@@ -235,7 +235,7 @@ form h2
 	<p class="emojis" style="margin-top: 1.8em;">RmlUi 😍</p>
 	<p class="emojis" style="margin-top: 1.8em;">RmlUi 😍</p>
 	<p>Have fun fiddling about in this (incomplete) demo.</p>
 	<p>Have fun fiddling about in this (incomplete) demo.</p>
 	<p>Press 'F8' to open up the debugger.</p>
 	<p>Press 'F8' to open up the debugger.</p>
-	<p class="emojis" style="margin-top: 1em; ">🎉</p>
+	<p class="emojis" style="margin-top: 1em;">🎉</p>
 </panel>
 </panel>
 <tab>Decorators</tab>
 <tab>Decorators</tab>
 <panel id="decorators" style="max-width: 850px;">
 <panel id="decorators" style="max-width: 850px;">
@@ -293,10 +293,10 @@ form h2
 	<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="../../../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>
+	<img sprite="icon-game" style="vertical-align: 10px;"/>
+	<img src="../../../assets/high_scores_defender.tga" style="image-color: #fc5;" rect="0 0 64 64"/>
+	<img src="../../../assets/high_scores_defender.tga" style="image-color: #9c5;" rect="64 0 64 64"/>
+	<p>Img elements can take both images and sprites. For images it also supports a 'rect' attribute for specifying a sub-rectangle.</p>
 </panel>
 </panel>
 <tab>Controls</tab>
 <tab>Controls</tab>
 <panel id="controls" class="minipanel">
 <panel id="controls" class="minipanel">

+ 94 - 68
Source/Core/ElementImage.cpp

@@ -35,7 +35,7 @@ namespace Rml {
 namespace Core {
 namespace Core {
 
 
 // Constructs a new ElementImage.
 // Constructs a new ElementImage.
-ElementImage::ElementImage(const String& tag) : Element(tag), dimensions(-1, -1), coords_source(CoordsSource::None), geometry(this)
+ElementImage::ElementImage(const String& tag) : Element(tag), dimensions(-1, -1), rect_source(RectSource::None), geometry(this)
 {
 {
 	geometry_dirty = false;
 	geometry_dirty = false;
 	texture_dirty = true;
 	texture_dirty = true;
@@ -55,18 +55,18 @@ 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 (coords_source != CoordsSource::None)
-		dimensions.x = coords.width;
+	else if (rect_source != RectSource::None)
+		dimensions.x = rect.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 (coords_source != CoordsSource::None)
-		dimensions.y = coords.height;
+	else if (rect_source != RectSource::None)
+		dimensions.y = rect.height;
 	else
 	else
-		dimensions.y = (float) texture.GetDimensions(GetRenderInterface()).y;
+		dimensions.y = (float)texture.GetDimensions(GetRenderInterface()).y;
 
 
 	// Return the calculated dimensions. If this changes the size of the element, it will result in
 	// Return the calculated dimensions. If this changes the size of the element, it will result in
 	// a 'resize' event which is caught below and will regenerate the geometry.
 	// a 'resize' event which is caught below and will regenerate the geometry.
@@ -77,8 +77,7 @@ bool ElementImage::GetIntrinsicDimensions(Vector2f& _dimensions)
 // Renders the element.
 // Renders the element.
 void ElementImage::OnRender()
 void ElementImage::OnRender()
 {
 {
-	// Regenerate the geometry if required (this will be set if 'coords' changes but does not
-	// result in a resize).
+	// Regenerate the geometry if required (this will be set if 'rect' changes but does not result in a resize).
 	if (geometry_dirty)
 	if (geometry_dirty)
 		GenerateGeometry();
 		GenerateGeometry();
 
 
@@ -96,7 +95,8 @@ void ElementImage::OnAttributeChange(const Rml::Core::ElementAttributes& changed
 
 
 	// Check for a changed 'src' attribute. If this changes, the old texture handle is released,
 	// Check for a changed 'src' attribute. If this changes, the old texture handle is released,
 	// forcing a reload when the layout is regenerated.
 	// forcing a reload when the layout is regenerated.
-	if (changed_attributes.find("src") != changed_attributes.end())
+	if (changed_attributes.find("src") != changed_attributes.end() ||
+		changed_attributes.find("sprite") != changed_attributes.end())
 	{
 	{
 		texture_dirty = true;
 		texture_dirty = true;
 		dirty_layout = true;
 		dirty_layout = true;
@@ -110,37 +110,13 @@ void ElementImage::OnAttributeChange(const Rml::Core::ElementAttributes& changed
 		dirty_layout = true;
 		dirty_layout = true;
 	}
 	}
 
 
-	// Check for a change to the 'coords' attribute. If this changes, the coordinates are
+	// Check for a change to the 'rect' attribute. If this changes, the coordinates are
 	// recomputed and a layout forced. If a sprite is set to source, then that will override any attribute.
 	// 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 (changed_attributes.find("rect") != changed_attributes.end())
 	{
 	{
-		if (HasAttribute("coords"))
-		{
-			StringList coords_list;
-			StringUtilities::ExpandString(coords_list, GetAttribute< String >("coords", ""), ' ');
+		UpdateRect();
 
 
-			if (coords_list.size() != 4)
-			{
-				Rml::Core::Log::Message(Log::LT_WARNING, "Element '%s' has an invalid 'coords' attribute; coords requires 4 values, found %d.", GetAddress().c_str(), coords_list.size());
-				ResetCoords();
-			}
-			else
-			{
-				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
-			ResetCoords();
-
-		// Coordinates have changes; this will most likely result in a size change, so we need to force a layout.
+		// Rectangle has changed; this will most likely result in a size change, so we need to force a layout.
 		dirty_layout = true;
 		dirty_layout = true;
 	}
 	}
 
 
@@ -177,7 +153,7 @@ void ElementImage::GenerateGeometry()
 
 
 	// Generate the texture coordinates.
 	// Generate the texture coordinates.
 	Vector2f texcoords[2];
 	Vector2f texcoords[2];
-	if (coords_source != CoordsSource::None)
+	if (rect_source != RectSource::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)
@@ -185,11 +161,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 = coords.x / texture_dimensions.x;
-		texcoords[0].y = coords.y / texture_dimensions.y;
+		texcoords[0].x = rect.x / texture_dimensions.x;
+		texcoords[0].y = rect.y / texture_dimensions.y;
 
 
-		texcoords[1].x = (coords.x + coords.width) / texture_dimensions.x;
-		texcoords[1].y = (coords.y + coords.height) / texture_dimensions.y;
+		texcoords[1].x = (rect.x + rect.width) / texture_dimensions.x;
+		texcoords[1].y = (rect.y + rect.height) / texture_dimensions.y;
 	}
 	}
 	else
 	else
 	{
 	{
@@ -213,49 +189,99 @@ void ElementImage::GenerateGeometry()
 bool ElementImage::LoadTexture()
 bool ElementImage::LoadTexture()
 {
 {
 	texture_dirty = false;
 	texture_dirty = false;
-
-	// Get the sprite name or image source URL.
-	const String source_name = GetAttribute< String >("src", "");
-	if (source_name.empty())
-		return false;
-
 	geometry_dirty = true;
 	geometry_dirty = true;
 
 
-	bool valid_sprite = false;
-	URL source_url;
-
-	Rml::Core::ElementDocument* document = GetOwnerDocument();
-
-	// Check if the name is a sprite first, otherwise treat it as an image url.
-	if (document) 
+	// Check for a sprite first, this takes precedence.
+	const String sprite_name = GetAttribute< String >("sprite", "");
+	if (!sprite_name.empty())
 	{
 	{
-		if (auto& style_sheet = document->GetStyleSheet())
+		// Load sprite.
+		bool valid_sprite = false;
+
+		if (ElementDocument* document = GetOwnerDocument())
 		{
 		{
-			if (const Sprite* sprite = style_sheet->GetSprite(source_name))
+			if (auto& style_sheet = document->GetStyleSheet())
 			{
 			{
-				coords = sprite->rectangle;
-				coords_source = CoordsSource::Sprite;
-				texture = sprite->sprite_sheet->texture;
-				valid_sprite = true;
+				if (const Sprite* sprite = style_sheet->GetSprite(sprite_name))
+				{
+					rect = sprite->rectangle;
+					rect_source = RectSource::Sprite;
+					texture = sprite->sprite_sheet->texture;
+					valid_sprite = true;
+				}
 			}
 			}
 		}
 		}
 
 
-		if(!valid_sprite)
-			source_url.SetURL(document->GetSourceURL());
+		if (!valid_sprite)
+		{
+			texture = Texture();
+			rect_source = RectSource::None;
+			UpdateRect();
+			Log::Message(Log::LT_WARNING, "Could not find sprite '%s' specified in img element.", sprite_name.c_str());
+			return false;
+		}
 	}
 	}
+	else
+	{
+		// Load image from source URL.
+		const String source_name = GetAttribute< String >("src", "");
+		if (source_name.empty())
+		{
+			texture = Texture();
+			rect_source = RectSource::None;
+			return false;
+		}
+
+		URL source_url;
+
+		if (ElementDocument* document = GetOwnerDocument())
+			source_url.SetURL(document->GetSourceURL());
 
 
-	if(!valid_sprite)
 		texture.Set(source_name, source_url.GetPath());
 		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);
+
 	return true;
 	return true;
 }
 }
 
 
-void ElementImage::ResetCoords()
+void ElementImage::UpdateRect()
 {
 {
-	coords = {};
-	coords_source = CoordsSource::None;
+	if(rect_source != RectSource::Sprite)
+	{
+		bool valid_rect = false;
+
+		String rect_string = GetAttribute< String >("rect", "");
+		if (!rect_string.empty())
+		{
+			StringList coords_list;
+			StringUtilities::ExpandString(coords_list, rect_string, ' ');
+
+			if (coords_list.size() != 4)
+			{
+				Rml::Core::Log::Message(Log::LT_WARNING, "Element '%s' has an invalid 'rect' attribute; rect requires 4 space-separated values, found %d.", GetAddress().c_str(), coords_list.size());
+			}
+			else
+			{
+				rect.x = (float)std::atof(coords_list[0].c_str());
+				rect.y = (float)std::atof(coords_list[1].c_str());
+				rect.width = (float)std::atof(coords_list[2].c_str());
+				rect.height = (float)std::atof(coords_list[3].c_str());
+
+				// We have new, valid coordinates; force the geometry to be regenerated.
+				valid_rect = true;
+				geometry_dirty = true;
+				rect_source = RectSource::Attribute;
+			}
+		}
+
+		if (!valid_rect)
+		{
+			rect = {};
+			rect_source = RectSource::None;
+		}
+	}
 }
 }
 
 
 }
 }

+ 16 - 16
Source/Core/ElementImage.h

@@ -38,23 +38,23 @@ namespace Rml {
 namespace Core {
 namespace Core {
 
 
 /**
 /**
-	The 'img' element. The image element can have a rectangular sub-region of its source texture
-	specified with the 'coords' attribute; the element will render this region rather than the
-	entire image.
+	The 'img' element can render images and sprites. 
 
 
-	The 'coords' attribute is similar to that of the HTML imagemap. It takes four comma-separated
-	integer values, specifying the top-left and the bottom right of the region in
-	pixel-coordinates, in that order. So for example, the attribute "coords" = "0, 10, 100, 210"
-	will render a 100 x 200 region, beginning at (0, 10) and rendering through to (100, 210). No
-	clamping to the dimensions of the source image will occur; rendered results in this case will
-	depend on the texture addressing mode.
+	The 'src' attribute is used to specify an image url. If instead the `sprite` attribute is set,
+	it will load a sprite and ignore the `src` and `rect` attributes.
+
+	The 'rect' attribute takes four space-separated	integer values, specifying a rectangle
+	using 'x y width height' in pixel coordinates inside the image. No clamping to the
+	dimensions of the source image will occur; rendered results in this case will
+	depend on the user's texture addressing mode.
 
 
 	The intrinsic dimensions of the image can now come from three different sources. They are
 	The intrinsic dimensions of the image can now come from three different sources. They are
 	used in the following order:
 	used in the following order:
 
 
 	1) 'width' / 'height' attributes if present
 	1) 'width' / 'height' attributes if present
-	2) pixel width / height given by the 'coords' attribute
-	3) width / height of the source texture
+	2) pixel width / height of the sprite 
+	3) pixel width / height given by the 'rect' attribute
+	4) width / height of the image texture
 
 
 	This has the result of sizing the element to the pixel-size of the rendered image, unless
 	This has the result of sizing the element to the pixel-size of the rendered image, unless
 	overridden by the 'width' or 'height' attributes.
 	overridden by the 'width' or 'height' attributes.
@@ -95,8 +95,8 @@ private:
 	void GenerateGeometry();
 	void GenerateGeometry();
 	// Loads the element's texture, as specified by the 'src' attribute.
 	// Loads the element's texture, as specified by the 'src' attribute.
 	bool LoadTexture();
 	bool LoadTexture();
-	// Resets the values of the 'coords' attribute to mark them as unused.
-	void ResetCoords();
+	// Loads the rect value from the element's attribute, but only if we're not a sprite.
+	void UpdateRect();
 
 
 	// The texture this element is rendering from.
 	// The texture this element is rendering from.
 	Texture texture;
 	Texture texture;
@@ -106,10 +106,10 @@ private:
 	// that dimension has not been computed yet.
 	// that dimension has not been computed yet.
 	Vector2f dimensions;
 	Vector2f dimensions;
 
 
-	// The coords extracted from the sprite or 'coords' attribute. The coords_source will be None if
+	// The rectangle extracted from the sprite or 'rect' attribute. The rect_source will be None if
 	// these have not been specified or are invalid.
 	// these have not been specified or are invalid.
-	Rectangle coords;
-	enum class CoordsSource { None, Attribute, Sprite } coords_source;
+	Rectangle rect;
+	enum class RectSource { None, Attribute, Sprite } rect_source;
 
 
 	// The geometry used to render this element.
 	// The geometry used to render this element.
 	Geometry geometry;
 	Geometry geometry;