1
0
forked from 0ad/0ad

Use pointers instead of copying sprites in the GUI. Fixes #1984. Patch by jP_wanN.

This was SVN commit r14493.
This commit is contained in:
JoshuaJB 2014-01-03 20:19:43 +00:00
parent 28f022993a
commit fb8032043b
6 changed files with 100 additions and 83 deletions

View File

@ -485,8 +485,7 @@ void CGUI::Destroy()
{
// We can use the map to delete all
// now we don't want to cancel all if one Destroy fails
map_pObjects::iterator it;
for (it = m_pAllObjects.begin(); it != m_pAllObjects.end(); ++it)
for (map_pObjects::iterator it = m_pAllObjects.begin(); it != m_pAllObjects.end(); ++it)
{
try
{
@ -502,12 +501,10 @@ void CGUI::Destroy()
delete it->second;
}
for (std::map<CStr, CGUISprite>::iterator it2 = m_Sprites.begin(); it2 != m_Sprites.end(); ++it2)
for (std::vector<SGUIImage>::iterator it3 = it2->second.m_Images.begin(); it3 != it2->second.m_Images.end(); ++it3)
delete it3->m_Effects;
// Clear all
m_pAllObjects.clear();
for(std::map<CStr, CGUISprite*>::iterator it = m_Sprites.begin(); it != m_Sprites.end(); ++it)
delete it->second;
m_Sprites.clear();
m_Icons.clear();
}
@ -1454,7 +1451,7 @@ void CGUI::Xeromyces_ReadScript(XMBElement Element, CXeromyces* pFile, boost::un
void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
{
// Sprite object we're adding
CGUISprite sprite;
CGUISprite* Sprite = new CGUISprite;
// and what will be its reference name
CStr name;
@ -1487,7 +1484,7 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
if (ElementName == "image")
{
Xeromyces_ReadImage(child, pFile, sprite);
Xeromyces_ReadImage(child, pFile, *Sprite);
}
else if (ElementName == "effect")
{
@ -1510,9 +1507,9 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
// Apply the effects to every image (unless the image overrides it with
// different effects)
if (effects)
for (std::vector<SGUIImage>::iterator it = sprite.m_Images.begin(); it != sprite.m_Images.end(); ++it)
if (! it->m_Effects)
it->m_Effects = new SGUIImageEffects(*effects); // do a copy just so it can be deleted correctly later
for (std::vector<SGUIImage*>::iterator it = Sprite->m_Images.begin(); it != Sprite->m_Images.end(); ++it)
if (! (*it)->m_Effects)
(*it)->m_Effects = new SGUIImageEffects(*effects); // do a copy just so it can be deleted correctly later
delete effects;
@ -1520,18 +1517,18 @@ void CGUI::Xeromyces_ReadSprite(XMBElement Element, CXeromyces* pFile)
// Add Sprite
//
m_Sprites[name] = sprite;
m_Sprites[name] = Sprite;
}
void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite &parent)
{
// Image object we're adding
SGUIImage image;
SGUIImage* Image = new SGUIImage;
// Set defaults to "0 0 100% 100%"
image.m_TextureSize = CClientArea(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
image.m_Size = CClientArea(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
Image->m_TextureSize = CClientArea(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
Image->m_Size = CClientArea(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
// TODO Gee: Setup defaults here (or maybe they are in the SGUIImage ctor)
@ -1549,7 +1546,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
if (attr_name == "texture")
{
image.m_TextureName = VfsPath("art/textures/ui") / attr_value;
Image->m_TextureName = VfsPath("art/textures/ui") / attr_value;
}
else
if (attr_name == "size")
@ -1557,7 +1554,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CClientArea ca;
if (!GUI<CClientArea>::ParseString(attr_value, ca))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_Size = ca;
else Image->m_Size = ca;
}
else
if (attr_name == "texture_size")
@ -1565,7 +1562,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CClientArea ca;
if (!GUI<CClientArea>::ParseString(attr_value, ca))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_TextureSize = ca;
else Image->m_TextureSize = ca;
}
else
if (attr_name == "real_texture_placement")
@ -1573,7 +1570,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CRect rect;
if (!GUI<CRect>::ParseString(attr_value, rect))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_TexturePlacementInFile = rect;
else Image->m_TexturePlacementInFile = rect;
}
else
if (attr_name == "cell_size")
@ -1581,7 +1578,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CSize size;
if (!GUI<CSize>::ParseString(attr_value, size))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_CellSize = size;
else Image->m_CellSize = size;
}
else
if (attr_name == "fixed_h_aspect_ratio")
@ -1589,7 +1586,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
float val;
if (!GUI<float>::ParseString(attr_value, val))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_FixedHAspectRatio = val;
else Image->m_FixedHAspectRatio = val;
}
else
if (attr_name == "round_coordinates")
@ -1597,17 +1594,17 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
bool b;
if (!GUI<bool>::ParseString(attr_value, b))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_RoundCoordinates = b;
else Image->m_RoundCoordinates = b;
}
else
if (attr_name == "wrap_mode")
{
if (attr_value == L"repeat")
image.m_WrapMode = GL_REPEAT;
Image->m_WrapMode = GL_REPEAT;
else if (attr_value == L"mirrored_repeat")
image.m_WrapMode = GL_MIRRORED_REPEAT;
Image->m_WrapMode = GL_MIRRORED_REPEAT;
else if (attr_value == L"clamp_to_edge")
image.m_WrapMode = GL_CLAMP_TO_EDGE;
Image->m_WrapMode = GL_CLAMP_TO_EDGE;
else
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
}
@ -1617,7 +1614,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
float z_level;
if (!GUI<float>::ParseString(attr_value, z_level))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_DeltaZ = z_level/100.f;
else Image->m_DeltaZ = z_level/100.f;
}
else
if (attr_name == "backcolor")
@ -1625,7 +1622,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CColor color;
if (!GUI<CColor>::ParseString(attr_value, color))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_BackColor = color;
else Image->m_BackColor = color;
}
else
if (attr_name == "bordercolor")
@ -1633,7 +1630,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CColor color;
if (!GUI<CColor>::ParseString(attr_value, color))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_BorderColor = color;
else Image->m_BorderColor = color;
}
else
if (attr_name == "border")
@ -1641,7 +1638,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
bool b;
if (!GUI<bool>::ParseString(attr_value, b))
LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
else image.m_Border = b;
else Image->m_Border = b;
}
else
{
@ -1657,14 +1654,14 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
CStr ElementName (pFile->GetElementString(child.GetNodeName()));
if (ElementName == "effect")
{
if (image.m_Effects)
if (Image->m_Effects)
{
LOGERROR(L"GUI <image> must not have more than one <effect>");
}
else
{
image.m_Effects = new SGUIImageEffects;
Xeromyces_ReadEffects(child, pFile, *image.m_Effects);
Image->m_Effects = new SGUIImageEffects;
Xeromyces_ReadEffects(child, pFile, *Image->m_Effects);
}
}
else
@ -1677,7 +1674,7 @@ void CGUI::Xeromyces_ReadImage(XMBElement Element, CXeromyces* pFile, CGUISprite
// Input
//
parent.AddImage(image);
parent.AddImage(Image);
}
void CGUI::Xeromyces_ReadEffects(XMBElement Element, CXeromyces* pFile, SGUIImageEffects &effects)

View File

@ -670,7 +670,7 @@ private:
//--------------------------------------------------------
// Sprites
std::map<CStr, CGUISprite> m_Sprites;
std::map<CStr, CGUISprite*> m_Sprites;
// Styles
std::map<CStr, SGUIStyle> m_Styles;

View File

@ -18,7 +18,20 @@
#include "precompiled.h"
#include "CGUISprite.h"
void CGUISpriteInstance::Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites, float Z) const
CGUISprite::~CGUISprite()
{
for (std::vector<SGUIImage*>::iterator it = m_Images.begin(); it != m_Images.end(); it++)
{
delete *it;
}
}
void CGUISprite::AddImage(SGUIImage* image)
{
m_Images.push_back(image);
}
void CGUISpriteInstance::Draw(CRect Size, int CellID, std::map<CStr, CGUISprite*> &Sprites, float Z) const
{
if (m_CachedSize != Size || m_CachedCellID != CellID)
{

View File

@ -69,7 +69,6 @@ struct SGUIImageEffects
bool m_Greyscale;
};
/**
* A CGUISprite is actually a collage of several <b>real</b>
* sprites, this struct represents is such real sprite.
@ -81,6 +80,11 @@ struct SGUIImage
m_Effects(NULL), m_Border(false), m_DeltaZ(0.f)
{
}
~SGUIImage()
{
delete m_Effects;
}
// Filename of the texture
VfsPath m_TextureName;
@ -135,8 +139,9 @@ struct SGUIImage
* way of declaring delta-z.
*/
float m_DeltaZ;
};
NONCOPYABLE(SGUIImage);
};
/**
* The GUI sprite, is actually several real sprites (images)
@ -151,17 +156,19 @@ class CGUISprite
{
public:
CGUISprite() {}
virtual ~CGUISprite() {}
virtual ~CGUISprite();
/**
* Adds an image to the sprite collage.
*
* @param image Adds this image to the sprite collage.
*/
void AddImage(const SGUIImage &image) { m_Images.push_back(image); }
void AddImage(SGUIImage*);
/// List of images
std::vector<SGUIImage> m_Images;
std::vector<SGUIImage*> m_Images;
NONCOPYABLE(CGUISprite);
};
#include "GUIRenderer.h"
@ -176,7 +183,7 @@ public:
CGUISpriteInstance(const CStr& SpriteName);
CGUISpriteInstance(const CGUISpriteInstance &Sprite);
CGUISpriteInstance &operator=(const CStr& SpriteName);
void Draw(CRect Size, int CellID, std::map<CStr, CGUISprite> &Sprites, float Z) const;
void Draw(CRect Size, int CellID, std::map<CStr, CGUISprite*>& Sprites, float Z) const;
void Invalidate();
bool IsEmpty() const;
const CStr& GetName() { return m_SpriteName; }

View File

@ -56,7 +56,7 @@ DrawCalls& DrawCalls::operator=(const DrawCalls&)
}
void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, const CRect &Size, int CellID, std::map<CStr, CGUISprite> &Sprites)
void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, const CRect &Size, int CellID, std::map<CStr, CGUISprite*> &Sprites)
{
// This is called only when something has changed (like the size of the
// sprite), so it doesn't need to be particularly efficient.
@ -71,7 +71,7 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
return;
std::map<CStr, CGUISprite>::iterator it (Sprites.find(SpriteName));
std::map<CStr, CGUISprite*>::iterator it (Sprites.find(SpriteName));
if (it == Sprites.end())
{
// Sprite not found. Check whether this a special sprite:
@ -84,26 +84,26 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
if (SpriteName.substr(0, 10) == "stretched:")
{
// TODO: Should check (nicely) that this is a valid file?
SGUIImage Image;
SGUIImage* Image = new SGUIImage;
// Allow grayscale images for disabled portraits
if (SpriteName.substr(10, 10) == "grayscale:")
{
Image.m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(20));
Image.m_Effects = new SGUIImageEffects;
Image.m_Effects->m_Greyscale = true;
Image->m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(20));
Image->m_Effects = new SGUIImageEffects;
Image->m_Effects->m_Greyscale = true;
}
else
{
Image.m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(10));
Image->m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(10));
}
CClientArea ca(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
Image.m_Size = ca;
Image.m_TextureSize = ca;
Image->m_Size = ca;
Image->m_TextureSize = ca;
CGUISprite Sprite;
Sprite.AddImage(Image);
CGUISprite* Sprite = new CGUISprite;
Sprite->AddImage(Image);
Sprites[SpriteName] = Sprite;
@ -113,22 +113,22 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
else if (SpriteName.substr(0, 8) == "cropped:")
{
// TODO: Should check (nicely) that this is a valid file?
SGUIImage Image;
SGUIImage* Image = new SGUIImage;
double xRatio = SpriteName.BeforeFirst(",").AfterLast("(").ToDouble();
double yRatio = SpriteName.BeforeFirst(")").AfterLast(",").ToDouble();
int PathStart = SpriteName.Find(")") + 1;
Image.m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(PathStart));
Image->m_TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.substr(PathStart));
CClientArea ca(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
CClientArea cb(CRect(0, 0, 0, 0), CRect(0, 0, 100/xRatio, 100/yRatio));
Image.m_Size = ca;
Image.m_TextureSize = cb;
Image->m_Size = ca;
Image->m_TextureSize = cb;
CGUISprite Sprite;
Sprite.AddImage(Image);
CGUISprite* Sprite = new CGUISprite;
Sprite->AddImage(Image);
Sprites[SpriteName] = Sprite;
@ -147,16 +147,16 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
return;
}
SGUIImage image;
SGUIImage* Image = new SGUIImage;
image.m_BackColor = color;
Image->m_BackColor = color;
CClientArea ca(CRect(0, 0, 0, 0), CRect(0, 0, 100, 100));
image.m_Size = ca;
image.m_TextureSize = ca;
Image->m_Size = ca;
Image->m_TextureSize = ca;
CGUISprite Sprite;
Sprite.AddImage(image);
CGUISprite* Sprite = new CGUISprite;
Sprite->AddImage(Image);
Sprites[SpriteName] = Sprite;
@ -171,16 +171,16 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
}
}
Calls.reserve(it->second.m_Images.size());
Calls.reserve(it->second->m_Images.size());
// Iterate through all the sprite's images, loading the texture and
// calculating the texture coordinates
std::vector<SGUIImage>::const_iterator cit;
for (cit = it->second.m_Images.begin(); cit != it->second.m_Images.end(); ++cit)
std::vector<SGUIImage*>::const_iterator cit;
for (cit = it->second->m_Images.begin(); cit != it->second->m_Images.end(); ++cit)
{
SDrawCall Call(&*cit); // pointers are safe since we never modify sprites/images after startup
SDrawCall Call(*cit); // pointers are safe since we never modify sprites/images after startup
CRect ObjectSize = cit->m_Size.GetClientArea(Size);
CRect ObjectSize = (*cit)->m_Size.GetClientArea(Size);
if (ObjectSize.GetWidth() == 0.0 || ObjectSize.GetHeight() == 0.0)
{
@ -189,7 +189,7 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
}
Call.m_Vertices = ObjectSize;
if (cit->m_RoundCoordinates)
if ((*cit)->m_RoundCoordinates)
{
// Round the vertex coordinates to integers, to avoid ugly filtering artifacts
Call.m_Vertices.left = (int)(Call.m_Vertices.left + 0.5f);
@ -198,10 +198,10 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
Call.m_Vertices.bottom = (int)(Call.m_Vertices.bottom + 0.5f);
}
if (! cit->m_TextureName.empty())
if (!(*cit)->m_TextureName.empty())
{
CTextureProperties textureProps(cit->m_TextureName);
textureProps.SetWrap(cit->m_WrapMode);
CTextureProperties textureProps((*cit)->m_TextureName);
textureProps.SetWrap((*cit)->m_WrapMode);
CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps);
texture->Prefetch();
Call.m_HasTexture = true;
@ -216,29 +216,29 @@ void GUIRenderer::UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName,
{
Call.m_HasTexture = false;
// Enable blending if it's transparent (allowing a little error in the calculations)
Call.m_EnableBlending = !(fabs(cit->m_BackColor.a - 1.0f) < 0.0000001f);
Call.m_EnableBlending = !(fabs((*cit)->m_BackColor.a - 1.0f) < 0.0000001f);
}
Call.m_BackColor = cit->m_BackColor;
Call.m_BorderColor = cit->m_Border ? cit->m_BorderColor : CColor();
Call.m_DeltaZ = cit->m_DeltaZ;
Call.m_BackColor = (*cit)->m_BackColor;
Call.m_BorderColor = (*cit)->m_Border ? (*cit)->m_BorderColor : CColor();
Call.m_DeltaZ = (*cit)->m_DeltaZ;
if (!Call.m_HasTexture)
{
Call.m_Shader = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid);
}
else if (cit->m_Effects)
else if ((*cit)->m_Effects)
{
if (cit->m_Effects->m_AddColor != CColor())
if ((*cit)->m_Effects->m_AddColor != CColor())
{
Call.m_Shader = g_Renderer.GetShaderManager().LoadEffect(str_gui_add);
Call.m_ShaderColorParameter = cit->m_Effects->m_AddColor;
Call.m_ShaderColorParameter = (*cit)->m_Effects->m_AddColor;
// Always enable blending if something's being subtracted from
// the alpha channel
if (cit->m_Effects->m_AddColor.a < 0.f)
if ((*cit)->m_Effects->m_AddColor.a < 0.f)
Call.m_EnableBlending = true;
}
else if (cit->m_Effects->m_Greyscale)
else if ((*cit)->m_Effects->m_Greyscale)
{
Call.m_Shader = g_Renderer.GetShaderManager().LoadEffect(str_gui_grayscale);
}

View File

@ -77,7 +77,7 @@ namespace GUIRenderer
namespace GUIRenderer
{
void UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, const CRect& Size, int CellID, std::map<CStr, CGUISprite> &Sprites);
void UpdateDrawCallCache(DrawCalls &Calls, const CStr& SpriteName, const CRect& Size, int CellID, std::map<CStr, CGUISprite*> &Sprites);
void Draw(DrawCalls &Calls, float Z);
}