Index: ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.fp =================================================================== --- ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.fp (revision 25602) +++ ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.fp (revision 25603) @@ -1,15 +1,27 @@ !!ARBfp1.0 TEMP colorTex; TEX colorTex, fragment.texcoord[0], texture[0], 2D; +TEMP grayscale; +MOV grayscale.r, 0.3; +MOV grayscale.g, 0.59; +MOV grayscale.b, 0.11; +MOV grayscale.a, 0.0; + PARAM colorAdd = program.local[1]; PARAM colorMul = program.local[2]; +PARAM grayscaleFactor = program.local[3]; + +TEMP colorGray; +DP3 colorGray.rgb, colorTex, grayscale; +MOV colorGray.a, colorTex.a; TEMP color; -MUL color, colorTex, colorMul; +LRP color, grayscaleFactor, colorGray, colorTex; +MUL color, color, colorMul; ADD color, color, colorAdd; MOV result.color, color; END Index: ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.xml =================================================================== --- ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.xml (revision 25602) +++ ps/trunk/binaries/data/mods/mod/shaders/arb/canvas2d.xml (revision 25603) @@ -1,16 +1,17 @@ + Index: ps/trunk/binaries/data/mods/mod/shaders/glsl/canvas2d.fs =================================================================== --- ps/trunk/binaries/data/mods/mod/shaders/glsl/canvas2d.fs (revision 25602) +++ ps/trunk/binaries/data/mods/mod/shaders/glsl/canvas2d.fs (revision 25603) @@ -1,12 +1,15 @@ #version 110 +uniform sampler2D tex; uniform vec4 colorAdd; uniform vec4 colorMul; -uniform sampler2D tex; +uniform float grayscaleFactor; varying vec2 v_uv; void main() { - gl_FragColor = clamp(texture2D(tex, v_uv) * colorMul + colorAdd, 0.0, 1.0); + vec4 colorTex = texture2D(tex, v_uv); + vec3 grayColor = vec3(dot(vec3(0.3, 0.59, 0.11), colorTex.rgb)); + gl_FragColor = clamp(mix(colorTex, vec4(grayColor, colorTex.a), grayscaleFactor) * colorMul + colorAdd, 0.0, 1.0); } Index: ps/trunk/source/graphics/Canvas2D.cpp =================================================================== --- ps/trunk/source/graphics/Canvas2D.cpp (revision 25602) +++ ps/trunk/source/graphics/Canvas2D.cpp (revision 25603) @@ -1,152 +1,153 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "Canvas2D.h" #include "graphics/Color.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "gui/GUIMatrix.h" #include "maths/Rect.h" #include "maths/Vector2D.h" #include "ps/CStrInternStatic.h" #include "renderer/Renderer.h" #include namespace { // Array of 2D elements unrolled into 1D array. using PlaneArray2D = std::array; inline void DrawTextureImpl(CTexturePtr texture, const PlaneArray2D& vertices, PlaneArray2D uvs, - const CColor& multiply, const CColor& add) + const CColor& multiply, const CColor& add, const float grayscaleFactor) { CShaderDefines defines; CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect( str_canvas2d, g_Renderer.GetSystemShaderDefines(), defines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->BindTexture(str_tex, texture); for (size_t idx = 0; idx < uvs.size(); idx += 2) { if (texture->GetWidth() > 0.0f) uvs[idx + 0] /= texture->GetWidth(); if (texture->GetHeight() > 0.0f) uvs[idx + 1] /= texture->GetHeight(); } shader->Uniform(str_transform, GetDefaultGuiMatrix()); shader->Uniform(str_colorAdd, add); shader->Uniform(str_colorMul, multiply); + shader->Uniform(str_grayscaleFactor, grayscaleFactor); shader->VertexPointer(2, GL_FLOAT, 0, vertices.data()); shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 0, uvs.data()); shader->AssertPointersBound(); if (!g_Renderer.DoSkipSubmit()) glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size() / 2); tech->EndPass(); } } // anonymous namespace void CCanvas2D::DrawLine(const std::vector& points, const float width, const CColor& color) { std::vector vertices; vertices.reserve(points.size() * 3); for (const CVector2D& point : points) { vertices.emplace_back(point.X); vertices.emplace_back(point.Y); vertices.emplace_back(0.0f); } // Setup the render state CMatrix3D transform = GetDefaultGuiMatrix(); CShaderDefines lineDefines; CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_gui_solid, g_Renderer.GetSystemShaderDefines(), lineDefines); tech->BeginPass(); CShaderProgramPtr shader = tech->GetShader(); shader->Uniform(str_transform, transform); shader->Uniform(str_color, color); shader->VertexPointer(3, GL_FLOAT, 0, vertices.data()); shader->AssertPointersBound(); #if !CONFIG2_GLES glEnable(GL_LINE_SMOOTH); #endif glLineWidth(width); if (!g_Renderer.DoSkipSubmit()) glDrawArrays(GL_LINE_STRIP, 0, vertices.size() / 3); glLineWidth(1.0f); #if !CONFIG2_GLES glDisable(GL_LINE_SMOOTH); #endif tech->EndPass(); } void CCanvas2D::DrawRect(const CRect& rect, const CColor& color) { const PlaneArray2D uvs = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; const PlaneArray2D vertices = { rect.left, rect.bottom, rect.right, rect.bottom, rect.right, rect.top, rect.left, rect.top }; DrawTextureImpl( g_Renderer.GetTextureManager().GetTransparentTexture(), - vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color); + vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f); } void CCanvas2D::DrawTexture(CTexturePtr texture, const CRect& destination) { DrawTexture(texture, destination, CRect(0, 0, texture->GetWidth(), texture->GetHeight()), - CColor(1.0f, 1.0f, 1.0f, 1.0f), CColor(0.0f, 0.0f, 0.0f, 0.0f)); + CColor(1.0f, 1.0f, 1.0f, 1.0f), CColor(0.0f, 0.0f, 0.0f, 0.0f), 0.0f); } void CCanvas2D::DrawTexture( CTexturePtr texture, const CRect& destination, const CRect& source, - const CColor& multiply, const CColor& add) + const CColor& multiply, const CColor& add, const float grayscaleFactor) { const PlaneArray2D uvs = { source.left, source.bottom, source.right, source.bottom, source.right, source.top, source.left, source.top }; const PlaneArray2D vertices = { destination.left, destination.bottom, destination.right, destination.bottom, destination.right, destination.top, destination.left, destination.top }; - DrawTextureImpl(texture, vertices, uvs, multiply, add); + DrawTextureImpl(texture, vertices, uvs, multiply, add, grayscaleFactor); } Index: ps/trunk/source/graphics/Canvas2D.h =================================================================== --- ps/trunk/source/graphics/Canvas2D.h (revision 25602) +++ ps/trunk/source/graphics/Canvas2D.h (revision 25603) @@ -1,63 +1,65 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_CANVAS2D #define INCLUDED_CANVAS2D #include "graphics/Texture.h" #include "maths/Vector2D.h" #include class CRect; struct CColor; // Encapsulates 2D drawing functionality to hide and optimize // low level API calls. class CCanvas2D { public: /** * Draws a line by the given points with the width and color. */ void DrawLine( const std::vector& points, const float width, const CColor& color); /** * Draws the rect filled with the color. */ void DrawRect(const CRect& rect, const CColor& color); /** * Draws a piece of the texture from the source rect into the * destination rect. The result color is set by the following formula: * TEXTURE_COLOR * COLOR_MULTIPLY + COLOR_ADD + * The texture color is blended with its own grayscale version according to + * the grayscale factor. */ void DrawTexture(CTexturePtr texture, const CRect& destination, const CRect& source, - const CColor& multiply, const CColor& add); + const CColor& multiply, const CColor& add, const float grayscaleFactor); /** * A simpler version of the previous one, draws the texture into the * destination rect without color modifications. */ void DrawTexture(CTexturePtr texture, const CRect& destination); }; #endif // INCLUDED_CANVAS2D Index: ps/trunk/source/gui/GUIRenderer.cpp =================================================================== --- ps/trunk/source/gui/GUIRenderer.cpp (revision 25602) +++ ps/trunk/source/gui/GUIRenderer.cpp (revision 25603) @@ -1,425 +1,361 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #include "precompiled.h" #include "GUIRenderer.h" #include "graphics/Canvas2D.h" -#include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "gui/CGUI.h" #include "gui/CGUISprite.h" #include "gui/GUIMatrix.h" #include "gui/SettingTypes/CGUIColor.h" #include "i18n/L10n.h" #include "lib/ogl.h" #include "lib/res/graphics/ogl_tex.h" #include "lib/res/h_mgr.h" #include "lib/tex/tex.h" #include "lib/utf8.h" #include "ps/CLogger.h" #include "ps/CStrInternStatic.h" #include "ps/Filesystem.h" #include "renderer/Renderer.h" using namespace GUIRenderer; DrawCalls::DrawCalls() { } // DrawCalls needs to be copyable, so it can be used in other copyable types. // But actually copying data is hard, since we'd need to avoid losing track of // who owns various pointers, so instead we just return an empty list. // The list should get filled in again (by GUIRenderer::UpdateDrawCallCache) // before it's used for rendering. (TODO: Is this class actually used safely // in practice?) DrawCalls::DrawCalls(const DrawCalls&) : std::vector() { } DrawCalls& DrawCalls::operator=(const DrawCalls&) { return *this; } void GUIRenderer::UpdateDrawCallCache(const CGUI& pGUI, DrawCalls& Calls, const CStr& SpriteName, const CRect& Size, std::map& Sprites) { // This is called only when something has changed (like the size of the // sprite), so it doesn't need to be particularly efficient. // Clean up the old data Calls.clear(); // If this object has zero size, there's nothing to render. (This happens // with e.g. tooltips that have zero size before they're first drawn, so // it isn't necessarily an error.) if (Size.left == Size.right && Size.top == Size.bottom) return; std::map::iterator it(Sprites.find(SpriteName)); if (it == Sprites.end()) { /* * Sprite not found. Check whether this a special sprite, * and if so create a new sprite: * "stretched:filename.ext" - stretched image * "stretched:grayscale:filename.ext" - stretched grayscale image. * "cropped:0.5, 0.25" - stretch this ratio (x,y) of the top left of the image * "color:r g b a" - solid color * > "textureAsMask" - when using color, use the (optional) texture alpha channel as mask. * These can be combined, but they must be separated by a ":" * so you can have a white overlay over an stretched grayscale image with: * "grayscale:color:255 255 255 100:stretched:filename.ext" */ // Check that this can be a special sprite. if (SpriteName.ReverseFind(":") == -1 && SpriteName.Find("color(") == -1) { LOGERROR("Trying to use a sprite that doesn't exist (\"%s\").", SpriteName.c_str()); return; } CGUISprite* Sprite = new CGUISprite; VfsPath TextureName = VfsPath("art/textures/ui") / wstring_from_utf8(SpriteName.AfterLast(":")); if (SpriteName.Find("stretched:") != -1) { // TODO: Should check (nicely) that this is a valid file? SGUIImage* Image = new SGUIImage(); Image->m_TextureName = TextureName; if (SpriteName.Find("grayscale:") != -1) { Image->m_Effects = std::make_shared(); Image->m_Effects->m_Greyscale = true; } Sprite->AddImage(Image); Sprites[SpriteName] = Sprite; } else if (SpriteName.Find("cropped:") != -1) { // TODO: Should check (nicely) that this is a valid file? SGUIImage* Image = new SGUIImage(); const bool centered = SpriteName.Find("center:") != -1; CStr info = SpriteName.AfterLast("cropped:").BeforeFirst(":"); double xRatio = info.BeforeFirst(",").ToDouble(); double yRatio = info.AfterLast(",").ToDouble(); const CRect percentSize = centered ? CRect(50 - 50 / xRatio, 50 - 50 / yRatio, 50 + 50 / xRatio, 50 + 50 / yRatio) : CRect(0, 0, 100 / xRatio, 100 / yRatio); Image->m_TextureSize = CGUISize(CRect(0, 0, 0, 0), percentSize); Image->m_TextureName = TextureName; if (SpriteName.Find("grayscale:") != -1) { Image->m_Effects = std::make_shared(); Image->m_Effects->m_Greyscale = true; } Sprite->AddImage(Image); Sprites[SpriteName] = Sprite; } if (SpriteName.Find("color:") != -1) { CStrW value = wstring_from_utf8(SpriteName.AfterLast("color:").BeforeFirst(":")); SGUIImage* Image = new SGUIImage(); CGUIColor* color; // If we are using a mask, this is an effect. // Otherwise we can fallback to the "back color" attribute // TODO: we are assuming there is a filename here. if (SpriteName.Find("textureAsMask:") != -1) { Image->m_TextureName = TextureName; Image->m_Effects = std::make_shared(); color = &Image->m_Effects->m_SolidColor; } else color = &Image->m_BackColor; // Check color is valid if (!CGUI::ParseString(&pGUI, value, *color)) { LOGERROR("GUI: Error parsing sprite 'color' (\"%s\")", utf8_from_wstring(value)); return; } Sprite->AddImage(Image); Sprites[SpriteName] = Sprite; } it = Sprites.find(SpriteName); // Otherwise, just complain and give up: if (it == Sprites.end()) { SAFE_DELETE(Sprite); LOGERROR("Trying to use a sprite that doesn't exist (\"%s\").", SpriteName.c_str()); return; } } Calls.reserve(it->second->m_Images.size()); // Iterate through all the sprite's images, loading the texture and // calculating the texture coordinates std::vector::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 CRect ObjectSize = (*cit)->m_Size.GetSize(Size); if (ObjectSize.GetWidth() == 0.0 || ObjectSize.GetHeight() == 0.0) { // Zero sized object. Don't report as an error, since it's common for e.g. hitpoint bars. continue; // i.e. don't continue with this image } Call.m_Vertices = ObjectSize; 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); Call.m_Vertices.right = (int)(Call.m_Vertices.right + 0.5f); Call.m_Vertices.top = (int)(Call.m_Vertices.top + 0.5f); Call.m_Vertices.bottom = (int)(Call.m_Vertices.bottom + 0.5f); } + bool hasTexture = false; if (!(*cit)->m_TextureName.empty()) { CTextureProperties textureProps(g_L10n.LocalizePath((*cit)->m_TextureName)); textureProps.SetWrap((*cit)->m_WrapMode); CTexturePtr texture = g_Renderer.GetTextureManager().CreateTexture(textureProps); texture->Prefetch(); - Call.m_HasTexture = true; + hasTexture = true; Call.m_Texture = texture; Call.m_ObjectSize = ObjectSize; } - else - { - Call.m_HasTexture = false; - } Call.m_BackColor = &(*cit)->m_BackColor; - if (!Call.m_HasTexture) + Call.m_GrayscaleFactor = 0.0f; + if (!hasTexture) { - Call.m_Material = str_gui_solid; Call.m_ColorAdd = *Call.m_BackColor; Call.m_ColorMultiply = CColor(0.0f, 0.0f, 0.0f, 0.0f); Call.m_Texture = g_Renderer.GetTextureManager().GetTransparentTexture(); } else if ((*cit)->m_Effects) { if ((*cit)->m_Effects->m_AddColor != CGUIColor()) { - Call.m_Material = str_gui_add; const CColor color = (*cit)->m_Effects->m_AddColor; Call.m_ColorAdd = CColor(color.r, color.g, color.b, 0.0f); Call.m_ColorMultiply = CColor(1.0f, 1.0f, 1.0f, 1.0f); } else if ((*cit)->m_Effects->m_Greyscale) { - Call.m_Shader = g_Renderer.GetShaderManager().LoadEffect(str_gui_grayscale); - Call.m_Material = str_gui_grayscale; + Call.m_ColorAdd = CColor(0.0f, 0.0f, 0.0f, 0.0f); + Call.m_ColorMultiply = CColor(1.0f, 1.0f, 1.0f, 1.0f); + Call.m_GrayscaleFactor = 1.0f; } else if ((*cit)->m_Effects->m_SolidColor != CGUIColor()) { - Call.m_Material = str_gui_solid_mask; const CColor color = (*cit)->m_Effects->m_SolidColor; Call.m_ColorAdd = CColor(color.r, color.g, color.b, 0.0f); Call.m_ColorMultiply = CColor(0.0f, 0.0f, 0.0f, color.a); } else /* Slight confusion - why no effects? */ { - Call.m_Material = str_gui_basic; Call.m_ColorAdd = CColor(0.0f, 0.0f, 0.0f, 0.0f); Call.m_ColorMultiply = CColor(1.0f, 1.0f, 1.0f, 1.0f); } } else { - Call.m_Material = str_gui_basic; Call.m_ColorAdd = CColor(0.0f, 0.0f, 0.0f, 0.0f); Call.m_ColorMultiply = CColor(1.0f, 1.0f, 1.0f, 1.0f); } Calls.push_back(Call); } } CRect SDrawCall::ComputeTexCoords() const { float TexWidth = m_Texture->GetWidth(); float TexHeight = m_Texture->GetHeight(); if (!TexWidth || !TexHeight) return CRect(0, 0, 1, 1); // Textures are positioned by defining a rectangular block of the // texture (usually the whole texture), and a rectangular block on // the screen. The texture is positioned to make those blocks line up. // Get the screen's position/size for the block CRect BlockScreen = m_Image->m_TextureSize.GetSize(m_ObjectSize); if (m_Image->m_FixedHAspectRatio) BlockScreen.right = BlockScreen.left + BlockScreen.GetHeight() * m_Image->m_FixedHAspectRatio; // Get the texture's position/size for the block: CRect BlockTex; // "real_texture_placement" overrides everything if (m_Image->m_TexturePlacementInFile != CRect()) BlockTex = m_Image->m_TexturePlacementInFile; // Use the whole texture else BlockTex = CRect(0, 0, TexWidth, TexHeight); // When rendering, BlockTex will be transformed onto BlockScreen. // Also, TexCoords will be transformed onto ObjectSize (giving the // UV coords at each vertex of the object). We know everything // except for TexCoords, so calculate it: CVector2D translation(BlockTex.TopLeft()-BlockScreen.TopLeft()); float ScaleW = BlockTex.GetWidth()/BlockScreen.GetWidth(); float ScaleH = BlockTex.GetHeight()/BlockScreen.GetHeight(); CRect TexCoords ( // Resize (translating to/from the origin, so the // topleft corner stays in the same place) (m_ObjectSize-m_ObjectSize.TopLeft()) .Scale(ScaleW, ScaleH) + m_ObjectSize.TopLeft() // Translate from BlockTex to BlockScreen + translation ); // The tex coords need to be scaled so that (texwidth,texheight) is // mapped onto (1,1) TexCoords.left /= TexWidth; TexCoords.right /= TexWidth; TexCoords.top /= TexHeight; TexCoords.bottom /= TexHeight; return TexCoords; } void GUIRenderer::Draw(DrawCalls& Calls, CCanvas2D& canvas) { if (Calls.empty()) return; // Called every frame, to draw the object (based on cached calculations) // TODO: batching by shader/texture/etc would be nice - CMatrix3D matrix = GetDefaultGuiMatrix(); - glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Iterate through each DrawCall, and execute whatever drawing code is being called for (DrawCalls::const_iterator cit = Calls.begin(); cit != Calls.end(); ++cit) { - if (cit->m_HasTexture && (cit->m_Material == str_gui_basic || cit->m_Material == str_gui_solid_mask || cit->m_Material == str_gui_add)) - { - // A hack to preload the handle to get a correct texture size. - GLuint h; - ogl_tex_get_texture_id(cit->m_Texture->GetHandle(), &h); - - CRect texCoords = cit->ComputeTexCoords().Scale( - cit->m_Texture->GetWidth(), cit->m_Texture->GetHeight()); - - // Ensure the quad has the correct winding order - CRect rect = cit->m_Vertices; - if (rect.right < rect.left) - { - std::swap(rect.right, rect.left); - std::swap(texCoords.right, texCoords.left); - } - if (rect.bottom < rect.top) - { - std::swap(rect.bottom, rect.top); - std::swap(texCoords.bottom, texCoords.top); - } + // A hack to preload the handle to get a correct texture size. + GLuint h; + ogl_tex_get_texture_id(cit->m_Texture->GetHandle(), &h); - canvas.DrawTexture(cit->m_Texture, - rect, texCoords, cit->m_ColorMultiply, cit->m_ColorAdd); - } - else if (cit->m_HasTexture) - { - cit->m_Shader->BeginPass(); - CShaderProgramPtr shader = cit->m_Shader->GetShader(); - shader->Uniform(str_transform, matrix); - shader->Uniform(str_color, cit->m_ShaderColorParameter); - shader->BindTexture(str_tex, cit->m_Texture); - - CRect TexCoords = cit->ComputeTexCoords(); - - // Ensure the quad has the correct winding order, and update texcoords to match - CRect Verts = cit->m_Vertices; - if (Verts.right < Verts.left) - { - std::swap(Verts.right, Verts.left); - std::swap(TexCoords.right, TexCoords.left); - } - if (Verts.bottom < Verts.top) - { - std::swap(Verts.bottom, Verts.top); - std::swap(TexCoords.bottom, TexCoords.top); - } - - std::vector data; -#define ADD(u, v, x, y, z) STMT(data.push_back(u); data.push_back(v); data.push_back(x); data.push_back(y); data.push_back(z)) - ADD(TexCoords.left, TexCoords.bottom, Verts.left, Verts.bottom, 0.0f); - ADD(TexCoords.right, TexCoords.bottom, Verts.right, Verts.bottom, 0.0f); - ADD(TexCoords.right, TexCoords.top, Verts.right, Verts.top, 0.0f); - - ADD(TexCoords.right, TexCoords.top, Verts.right, Verts.top, 0.0f); - ADD(TexCoords.left, TexCoords.top, Verts.left, Verts.top, 0.0f); - ADD(TexCoords.left, TexCoords.bottom, Verts.left, Verts.bottom, 0.0f); -#undef ADD - - shader->TexCoordPointer(GL_TEXTURE0, 2, GL_FLOAT, 5*sizeof(float), &data[0]); - shader->VertexPointer(3, GL_FLOAT, 5*sizeof(float), &data[2]); - glDrawArrays(GL_TRIANGLES, 0, 6); + CRect texCoords = cit->ComputeTexCoords().Scale( + cit->m_Texture->GetWidth(), cit->m_Texture->GetHeight()); - cit->m_Shader->EndPass(); + // Ensure the quad has the correct winding order + CRect rect = cit->m_Vertices; + if (rect.right < rect.left) + { + std::swap(rect.right, rect.left); + std::swap(texCoords.right, texCoords.left); } - else + if (rect.bottom < rect.top) { - // Ensure the quad has the correct winding order - CRect rect = cit->m_Vertices; - if (rect.right < rect.left) - std::swap(rect.right, rect.left); - if (rect.bottom < rect.top) - std::swap(rect.bottom, rect.top); - canvas.DrawTexture(cit->m_Texture, - rect, CRect(0, 0, cit->m_Texture->GetWidth(), cit->m_Texture->GetHeight()), - cit->m_ColorMultiply, cit->m_ColorAdd); + std::swap(rect.bottom, rect.top); + std::swap(texCoords.bottom, texCoords.top); } + + canvas.DrawTexture(cit->m_Texture, + rect, texCoords, cit->m_ColorMultiply, cit->m_ColorAdd, cit->m_GrayscaleFactor); } glDisable(GL_BLEND); } Index: ps/trunk/source/gui/GUIRenderer.h =================================================================== --- ps/trunk/source/gui/GUIRenderer.h (revision 25602) +++ ps/trunk/source/gui/GUIRenderer.h (revision 25603) @@ -1,80 +1,73 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_GUIRENDERER #define INCLUDED_GUIRENDERER #include "graphics/Color.h" #include "graphics/ShaderTechniquePtr.h" #include "graphics/Texture.h" #include "lib/res/handle.h" #include "maths/Rect.h" #include "ps/CStrIntern.h" #include #include class CCanvas2D; class CGUI; class CGUISprite; class CStr8; struct CGUIColor; struct SGUIImage; namespace GUIRenderer { struct SDrawCall { SDrawCall(const SGUIImage* image) : m_Image(image) {} CRect ComputeTexCoords() const; const SGUIImage* m_Image; - bool m_HasTexture; CTexturePtr m_Texture; CRect m_ObjectSize; - - CShaderTechniquePtr m_Shader; - CColor m_ShaderColorParameter; - CRect m_Vertices; CGUIColor* m_BackColor; - // Temporary type to make a soft transition to canvas rendering. - CStrIntern m_Material; - CColor m_ColorAdd; CColor m_ColorMultiply; + float m_GrayscaleFactor; }; class DrawCalls : public std::vector { public: DrawCalls(); // Copy/assignment results in an empty list, not an actual copy DrawCalls(const DrawCalls&); DrawCalls& operator=(const DrawCalls&); }; void UpdateDrawCallCache(const CGUI& pGUI, DrawCalls& Calls, const CStr8& SpriteName, const CRect& Size, std::map& Sprites); void Draw(DrawCalls& Calls, CCanvas2D& canvas); } #endif // INCLUDED_GUIRENDERER Index: ps/trunk/source/ps/CStrInternStatic.h =================================================================== --- ps/trunk/source/ps/CStrInternStatic.h (revision 25602) +++ ps/trunk/source/ps/CStrInternStatic.h (revision 25603) @@ -1,178 +1,179 @@ /* Copyright (C) 2021 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ // This file defines global CStrIntern variables, to avoid the cost of // constructing CStrInterns frequently at runtime. // // A line like // X(foo) // defines a variable str_foo with value "foo". // // A line like // X2(foo_0, "foo[0]") // defines a variable str_foo_0 with value "foo[0]". // For direct inclusion, we presumably just want the extern definitions. #ifndef X #include "CStrIntern.h" #define X(id) extern CStrIntern str_##id; #define X2(id, str) extern CStrIntern str_##id; #endif X(0) X(1) X(2) X(ALPHABLEND_PASS_BLEND) X(ALPHABLEND_PASS_OPAQUE) X(BLEND) X(BLOOM_NOP) X(BLOOM_PASS_H) X(BLOOM_PASS_V) X(DECAL) X(DISABLE_RECEIVE_SHADOWS) X(IGNORE_LOS) X(MINIMAP_BASE) X(MINIMAP_LINE) X(MINIMAP_LOS) X(MINIMAP_MASK) X(MINIMAP_POINT) X(MODE_SHADOWCAST) X(MODE_SILHOUETTEDISPLAY) X(MODE_SILHOUETTEOCCLUDER) X(MODE_WIREFRAME) X(SYS_HAS_ARB) X(SYS_HAS_GLSL) X(SYS_PREFER_GLSL) X(USE_FANCY_EFFECTS) X(USE_FP_SHADOW) X(USE_GPU_SKINNING) X(USE_INSTANCING) X(USE_NORMALS) X(USE_OBJECTCOLOR) X(USE_REAL_DEPTH) X(USE_REFLECTION) X(USE_REFRACTION) X(USE_SHADOW) X(USE_SHADOW_PCF) X(USE_SHADOW_SAMPLER) X(USE_FOG) X(WATERTYPE_CLAP) X(WATERTYPE_LAKE) X2(_emptystring, "") X(a_apexPosition) X(a_otherPosition) X(a_retreatPosition) X(a_skinJoints) X(a_skinWeights) X(a_splashPosition) X(a_tangent) X(a_waterInfo) X(ambient) X(baseTex) X(blendTex) X(bloom) X(blurTex2) X(blurTex4) X(blurTex8) X(brightness) X(cameraPos) X(canvas2d) X(color) X(colorAdd) X(colorMul) X(debug_line) X(debug_overlay) X(delta) X(depthTex) X(foamTex) X(fogColor) X(fogParams) X(foreground_overlay) +X(grayscaleFactor) X(gui_add) X(gui_basic) X(gui_grayscale) X(gui_solid) X(gui_solid_mask) X(gui_text) X(hdr) X(height) X(instancingTransform) X(losTex) X(losTex1) X(losTex2) X(losTransform) X(los_interp) X(mapSize) X(maskTex) X(maskTextureTransform) X(minimap) X(modelViewMatrix) X(murkiness) X(normalMap) X(normalMap2) X(objectColor) X(overlay_solid) X(particle) X(particle_solid) X(playerColor) X(pointSize) X(projInvTransform) X(qualityLevel) X(reflectionMap) X(reflectionMatrix) X(refractionMap) X(refractionMatrix) X(renderedTex) X(repeatScale) X2(sans_10, "sans-10"); X(saturation) X(screenSize) X(shadingColor) X(shadowScale) X(shadowTex) X(shadowTransform) X(sharpness) X(skinBlendMatrices) X2(skinBlendMatrices_0, "skinBlendMatrices[0]") X(skyBoxRot) X(skyCube) X(sky_simple) X(solid) X(sunColor) X(sunDir) X(tex) X(texSize) X(textureTransform) X(time) X(tint) X(transform) X(translation) X(viewInvTransform) X(water_simple) X(waterEffectsTex) X(waterTex) X(waveTex) X(waviness) X(waveParams1) X(waveParams2) X(width) X(windAngle) X(zFar) X(zNear) #undef X #undef X2