From 714e33dec0d76db007561a335e70e858afec6a36 Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 07:08:26 -0400 Subject: [PATCH 1/6] Cache Font & Texture data in renderers to reduce lookups; Fix bug in utf8_to_wchart; Fix software renderer alpha blending bug --- source/platform/include/Gwork/BaseRender.h | 1 + source/platform/include/Gwork/PlatformTypes.h | 6 + .../include/Gwork/Renderers/Allegro5.h | 3 + .../include/Gwork/Renderers/DirectX11.h | 3 + .../include/Gwork/Renderers/Irrlicht.h | 2 + .../platform/include/Gwork/Renderers/OpenGL.h | 3 + .../include/Gwork/Renderers/OpenGLCore.h | 7 +- .../platform/include/Gwork/Renderers/SDL2.h | 3 + .../include/Gwork/Renderers/Software.h | 9 +- source/platform/include/Gwork/Utility.h | 12 +- .../platform/renderers/Allegro5/Allegro5.cpp | 85 ++- .../renderers/DirectX11/DirectX11.cpp | 97 ++-- .../platform/renderers/Irrlicht/Irrlicht.cpp | 548 +++++++++--------- source/platform/renderers/OpenGL/OpenGL.cpp | 104 ++-- .../renderers/OpenGLCore/OpenGLCore.cpp | 120 ++-- source/platform/renderers/SDL2/SDL2.cpp | 97 ++-- .../platform/renderers/Software/Software.cpp | 114 ++-- 17 files changed, 718 insertions(+), 496 deletions(-) diff --git a/source/platform/include/Gwork/BaseRender.h b/source/platform/include/Gwork/BaseRender.h index a0502aef..5554dd30 100644 --- a/source/platform/include/Gwork/BaseRender.h +++ b/source/platform/include/Gwork/BaseRender.h @@ -176,6 +176,7 @@ namespace Gwk protected: virtual bool EnsureFont(const Gwk::Font& font) { return false; } + virtual bool EnsureTexture(const Gwk::Texture& texture) { return false; } float m_fScale; diff --git a/source/platform/include/Gwork/PlatformTypes.h b/source/platform/include/Gwork/PlatformTypes.h index 29ae933d..1db7157d 100644 --- a/source/platform/include/Gwork/PlatformTypes.h +++ b/source/platform/include/Gwork/PlatformTypes.h @@ -252,6 +252,11 @@ namespace Gwk return facename == rhs.facename && size == rhs.size && bold == rhs.bold; } + inline bool operator!=(const Font& rhs) const + { + return bold != rhs.bold || size != rhs.size || facename != rhs.facename; + } + String facename; float size; bool bold; @@ -279,6 +284,7 @@ namespace Gwk Texture& operator=(const Texture&) = default; inline bool operator==(const Texture& rhs) const { return name == rhs.name; } + inline bool operator!=(const Texture& rhs) const { return name != rhs.name; } String name; bool readable; diff --git a/source/platform/include/Gwork/Renderers/Allegro5.h b/source/platform/include/Gwork/Renderers/Allegro5.h index a4eaf515..38a905cb 100644 --- a/source/platform/include/Gwork/Renderers/Allegro5.h +++ b/source/platform/include/Gwork/Renderers/Allegro5.h @@ -65,6 +65,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses struct ALTextureData : public Gwk::TextureData @@ -111,6 +112,8 @@ namespace Gwk std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; public: void DrawLinedRect(Gwk::Rect rect) override; void DrawShavedCornerRect(Gwk::Rect rect, bool bSlight = false) override; diff --git a/source/platform/include/Gwork/Renderers/DirectX11.h b/source/platform/include/Gwork/Renderers/DirectX11.h index 9861ab4a..f8c10f04 100644 --- a/source/platform/include/Gwork/Renderers/DirectX11.h +++ b/source/platform/include/Gwork/Renderers/DirectX11.h @@ -65,6 +65,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected: @@ -179,6 +180,8 @@ namespace Gwk std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; void Flush(); void Present(); diff --git a/source/platform/include/Gwork/Renderers/Irrlicht.h b/source/platform/include/Gwork/Renderers/Irrlicht.h index dd8f39db..599edfd0 100644 --- a/source/platform/include/Gwork/Renderers/Irrlicht.h +++ b/source/platform/include/Gwork/Renderers/Irrlicht.h @@ -74,6 +74,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses @@ -122,6 +123,7 @@ namespace Gwk std::unordered_map m_fonts;*/ std::unordered_map m_textures; + std::pair* m_lastTexture; private: diff --git a/source/platform/include/Gwork/Renderers/OpenGL.h b/source/platform/include/Gwork/Renderers/OpenGL.h index 52625536..868488c3 100644 --- a/source/platform/include/Gwork/Renderers/OpenGL.h +++ b/source/platform/include/Gwork/Renderers/OpenGL.h @@ -67,6 +67,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses struct GLTextureData : public Gwk::TextureData @@ -130,6 +131,8 @@ namespace Gwk std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; protected: Rect m_viewRect; diff --git a/source/platform/include/Gwork/Renderers/OpenGLCore.h b/source/platform/include/Gwork/Renderers/OpenGLCore.h index f6ac7d27..8f91a131 100644 --- a/source/platform/include/Gwork/Renderers/OpenGLCore.h +++ b/source/platform/include/Gwork/Renderers/OpenGLCore.h @@ -62,6 +62,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses @@ -119,13 +120,15 @@ namespace Gwk float m_Spacing; - float width; - float height; + int width; + int height; unsigned int texture_id; }; std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; public: bool InitializeContext(Gwk::WindowProvider* window) override; diff --git a/source/platform/include/Gwork/Renderers/SDL2.h b/source/platform/include/Gwork/Renderers/SDL2.h index 4ce094f7..26042649 100644 --- a/source/platform/include/Gwork/Renderers/SDL2.h +++ b/source/platform/include/Gwork/Renderers/SDL2.h @@ -73,6 +73,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses @@ -122,6 +123,8 @@ namespace Gwk std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; public: bool BeginContext(Gwk::WindowProvider* window) override; diff --git a/source/platform/include/Gwork/Renderers/Software.h b/source/platform/include/Gwork/Renderers/Software.h index 2671aaba..c5fb61bc 100644 --- a/source/platform/include/Gwork/Renderers/Software.h +++ b/source/platform/include/Gwork/Renderers/Software.h @@ -93,6 +93,7 @@ namespace Gwk Texture::Status LoadTexture(const Gwk::Texture& texture) override; void FreeTexture(const Gwk::Texture& texture) override; TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; protected:// Resourses @@ -121,13 +122,15 @@ namespace Gwk Color& At(int x, int y) { - return (reinterpret_cast(m_ReadData.get()))[y * static_cast(width) + x]; + unsigned char* color_ptr = m_ReadData.get() + (y * 4 * static_cast(width) + x * 4); + return *reinterpret_cast(color_ptr); } Color& At(Point const& pt) { return At(pt.x, pt.y); } const Color& At(int x, int y) const { - return (reinterpret_cast(m_ReadData.get()))[y * static_cast(width) + x]; + unsigned char* color_ptr = m_ReadData.get() + (y * 4 * static_cast(width) + x * 4); + return *reinterpret_cast(color_ptr); } const Color& At(Point const& pt) const { return At(pt.x, pt.y); } @@ -172,6 +175,8 @@ namespace Gwk std::unordered_map m_fonts; std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; public: diff --git a/source/platform/include/Gwork/Utility.h b/source/platform/include/Gwork/Utility.h index b02610d7..0fccc8c8 100644 --- a/source/platform/include/Gwork/Utility.h +++ b/source/platform/include/Gwork/Utility.h @@ -87,7 +87,15 @@ namespace Gwk static inline wchar_t utf8_to_wchart(char*& in)// Gwk::Utility::Widen too slow { + thread_local static unsigned int next = 0x10000; + if (next != 0x10000) + { + wchar_t ret = static_cast(next); + next = 0x10000; + return ret; + } unsigned int codepoint; + while (*in != 0) { unsigned char ch = static_cast(*in); @@ -108,11 +116,11 @@ namespace Gwk return static_cast(codepoint); else if (codepoint > 0xffff) { + next = static_cast(0xdc00 + (codepoint & 0x03ff)); return static_cast(0xd800 + (codepoint >> 10)); - return static_cast(0xdc00 + (codepoint & 0x03ff)); } else if (codepoint < 0xd800 || codepoint >= 0xe000) - return 1, static_cast(codepoint); + return static_cast(codepoint); } } return 0; diff --git a/source/platform/renderers/Allegro5/Allegro5.cpp b/source/platform/renderers/Allegro5/Allegro5.cpp index 3e51a6a1..3fa25d55 100644 --- a/source/platform/renderers/Allegro5/Allegro5.cpp +++ b/source/platform/renderers/Allegro5/Allegro5.cpp @@ -116,6 +116,9 @@ void AllegroCTT::DrawCachedControlTexture(CacheHandle control) Font::Status Allegro::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); ALLEGRO_FONT* afont = al_load_font(filename.c_str(), @@ -126,7 +129,7 @@ Font::Status Allegro::LoadFont(const Font& font) { ALFontData fontData; fontData.font = deleted_unique_ptr(afont, [](ALLEGRO_FONT* mem) { if (mem) al_destroy_font(mem); }); - m_fonts.insert(std::make_pair(font, std::move(fontData))); + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } else @@ -138,23 +141,38 @@ Font::Status Allegro::LoadFont(const Font& font) void Allegro::FreeFont(const Gwk::Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls ALFontData destructor } bool Allegro::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status Allegro::LoadTexture(const Texture& texture) { FreeTexture(texture); - + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); ALLEGRO_BITMAP* bmp = al_load_bitmap(filename.c_str()); @@ -166,7 +184,7 @@ Texture::Status Allegro::LoadTexture(const Texture& texture) texData.width = al_get_bitmap_width(bmp); texData.height = al_get_bitmap_height(bmp); texData.readable = false; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } @@ -177,13 +195,19 @@ Texture::Status Allegro::LoadTexture(const Texture& texture) } } -void Allegro::FreeTexture(const Texture& texture) +void Allegro::FreeTexture(const Gwk::Texture& texture) { - m_textures.erase(texture); // calls GLTextureData destructor + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + + m_textures.erase(texture); // calls ALTextureData destructor } TextureData Allegro::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -193,11 +217,35 @@ TextureData Allegro::GetTextureData(const Texture& texture) const return TextureData(); } +bool Allegro::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} + //------------------------------------------------------------------------------- Allegro::Allegro(ResourcePaths& paths) : Base(paths) , m_ctt(new AllegroCTT) +, m_lastFont(nullptr) +, m_lastTexture(nullptr) { m_ctt->SetRenderer(this); m_ctt->Initialize(); @@ -262,17 +310,12 @@ void Allegro::DrawTexturedRect(const Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { - Translate(rect); - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rect); + if (!EnsureTexture(texture)) + DrawMissingImage(rect); - it = m_textures.find(texture); - } + Translate(rect); - ALTextureData& texData = it->second; + ALTextureData& texData = m_lastTexture->second; const unsigned int w = texData.width; const unsigned int h = texData.height; @@ -285,16 +328,10 @@ void Allegro::DrawTexturedRect(const Texture& texture, Gwk::Rect rect, Gwk::Color Allegro::PixelColor(const Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return col_default; - ALTextureData& texData = it->second; + ALTextureData& texData = m_lastTexture->second; ALLEGRO_COLOR col = al_get_pixel(texData.texture.get(), x, y); Gwk::Color gcol; diff --git a/source/platform/renderers/DirectX11/DirectX11.cpp b/source/platform/renderers/DirectX11/DirectX11.cpp index 1e81ce69..66c9c338 100644 --- a/source/platform/renderers/DirectX11/DirectX11.cpp +++ b/source/platform/renderers/DirectX11/DirectX11.cpp @@ -133,6 +133,9 @@ static HRESULT CompileShaderFromMemory(const char* szdata, SIZE_T len, LPCSTR sz Font::Status DirectX11::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const float realsize = font.size * Scale(); HDC hDC = CreateCompatibleDC(nullptr); DWORD texWidth = 2048, texHeight; @@ -298,29 +301,45 @@ Font::Status DirectX11::LoadFont(const Font& font) return Font::Status::ErrorBadData; } - m_fonts.insert(std::make_pair(font, std::move(fontData))); + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } void DirectX11::FreeFont(const Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls DxFontData destructor } bool DirectX11::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status DirectX11::LoadTexture(const Texture& texture) { FreeTexture(texture); + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); @@ -379,17 +398,23 @@ Texture::Status DirectX11::LoadTexture(const Texture& texture) texData.width = width; texData.height = height; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } -void DirectX11::FreeTexture(const Texture& texture) +void DirectX11::FreeTexture(const Gwk::Texture& texture) { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + m_textures.erase(texture); // calls DxTextureData destructor } TextureData DirectX11::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -399,10 +424,34 @@ TextureData DirectX11::GetTextureData(const Texture& texture) const return TextureData(); } +bool DirectX11::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} + DirectX11::DirectX11(ResourcePaths& paths, ID3D11Device* pDevice) : Base(paths) , m_pDevice(pDevice) , m_Buffer(256) + , m_lastFont(nullptr) + , m_lastTexture(nullptr) { m_Valid = false; @@ -653,13 +702,7 @@ void DirectX11::RenderText(const Gwk::Font& font, Gwk::Point pos, const Gwk::Str if (!EnsureFont(font)) return; - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return; - - DxFontData& fontData = it->second; + DxFontData& fontData = m_lastFont->second; if (m_pCurrentTexture != fontData.m_TextureResource) { @@ -718,13 +761,7 @@ Gwk::Point DirectX11::MeasureText(const Gwk::Font& font, const Gwk::String& text if (!EnsureFont(font)) return Gwk::Point(0, 0); - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return Gwk::Point(0, 0); - - DxFontData& fontData = it->second; + DxFontData& fontData = m_lastFont->second; float fRowWidth = 0.0f; float fRowHeight = (fontData.m_TexCoords[0].w - fontData.m_TexCoords[0].y) * fontData.height; @@ -784,16 +821,10 @@ void DirectX11::EndClip() void DirectX11::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rec, float u1, float v1, float u2, float v2) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rec); - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return DrawMissingImage(rec); - DxTextureData& texData = it->second; + DxTextureData& texData = m_lastTexture->second; ID3D11ShaderResourceView* pImage = texData.m_TextureResource; @@ -830,16 +861,10 @@ void DirectX11::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rec, flo Gwk::Color DirectX11::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return col_default; - DxTextureData& texData = it->second; + DxTextureData& texData = m_lastTexture->second; if (texData.readable) { diff --git a/source/platform/renderers/Irrlicht/Irrlicht.cpp b/source/platform/renderers/Irrlicht/Irrlicht.cpp index f75e327f..20dad4f5 100644 --- a/source/platform/renderers/Irrlicht/Irrlicht.cpp +++ b/source/platform/renderers/Irrlicht/Irrlicht.cpp @@ -1,8 +1,8 @@ /* - * Gwork - * Copyright (c) 2013-2017 Billy Quith - * See license in Gwork.h - */ +* Gwork +* Copyright (c) 2013-2017 Billy Quith +* See license in Gwork.h +*/ #include @@ -12,304 +12,324 @@ #include namespace Gwk { -namespace Renderer { + namespace Renderer { -// Resource Loader -Font::Status Irrlicht::LoadFont(const Gwk::Font& font) -{ - return Font::Status::Loaded; -} - -void Irrlicht::FreeFont(const Gwk::Font& font) -{ -} - -bool Irrlicht::EnsureFont(const Gwk::Font& font) -{ - return LoadFont(font) == Font::Status::Loaded; -} - -Texture::Status Irrlicht::LoadTexture(const Gwk::Texture& texture) -{ - FreeTexture(texture); - - const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); - - irr::video::ITexture* NewTex = Driver->getTexture(filename.c_str()); - if (!NewTex) - { - return Texture::Status::ErrorFileNotFound; - } - else - { - IRTextureData texData; - - const irr::core::dimension2d TexSize = NewTex->getSize(); - texData.texture = deleted_unique_ptr(NewTex, [this](irr::video::ITexture* mem) { if (mem) Driver->removeTexture(mem); }); - texData.readable = false; - texData.width = TexSize.Width; - texData.height = TexSize.Height; - m_textures.insert(std::make_pair(texture, std::move(texData))); - return Texture::Status::Loaded; - } -} - -void Irrlicht::FreeTexture(const Gwk::Texture& texture) -{ - m_textures.erase(texture); // calls IRTextureData destructor -} - -TextureData Irrlicht::GetTextureData(const Texture& texture) const -{ - auto it = m_textures.find(texture); - if (it != m_textures.cend()) - { - return it->second; - } - // Texture not loaded :( - return TextureData(); -} - -// -// Irrlicht ICacheToTexture -// -class IrrlichtCTT : public Gwk::Renderer::ICacheToTexture -{ -private: - Gwk::Renderer::Base *m_renderer; + // Resource Loader + Font::Status Irrlicht::LoadFont(const Gwk::Font& font) + { + return Font::Status::Loaded; + } - irr::video::IVideoDriver* m_Driver; - std::map m_TextureCache; + void Irrlicht::FreeFont(const Gwk::Font& font) + { + } -public: - IrrlichtCTT(irr::video::IVideoDriver* VideoDriver) : m_Driver(VideoDriver) {} + bool Irrlicht::EnsureFont(const Gwk::Font& font) + { + return LoadFont(font) == Font::Status::Loaded; + } - ~IrrlichtCTT() - { - // Cleanup all cached textures - for (auto it : m_TextureCache) + Texture::Status Irrlicht::LoadTexture(const Gwk::Texture& texture) { - m_Driver->removeTexture(it.second); + FreeTexture(texture); + m_lastTexture = nullptr; + + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); + + irr::video::ITexture* NewTex = Driver->getTexture(filename.c_str()); + if (!NewTex) + { + return Texture::Status::ErrorFileNotFound; + } + else + { + IRTextureData texData; + + const irr::core::dimension2d TexSize = NewTex->getSize(); + texData.texture = deleted_unique_ptr(NewTex, [this](irr::video::ITexture* mem) { if (mem) Driver->removeTexture(mem); }); + texData.readable = false; + texData.width = TexSize.Width; + texData.height = TexSize.Height; + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); + return Texture::Status::Loaded; + } } - } - void SetRenderer(Gwk::Renderer::Base* renderer) { m_renderer = renderer; } + void Irrlicht::FreeTexture(const Gwk::Texture& texture) + { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; - void Initialize() {} - void ShutDown() {} + m_textures.erase(texture); // calls IRTextureData destructor + } - // - // Create this controls cached texture if it doesn't already exist - void CreateControlCacheTexture(CacheHandle control, const Point& size) - { - if (m_TextureCache.find(control) == m_TextureCache.end()) + TextureData Irrlicht::GetTextureData(const Texture& texture) const { - irr::video::ITexture* RTT = - m_Driver->addRenderTargetTexture( - irr::core::dimension2d(size.x, size.y)); - m_TextureCache.insert(std::pair(control, RTT)); + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + + auto it = m_textures.find(texture); + if (it != m_textures.cend()) + { + return it->second; + } + // Texture not loaded :( + return TextureData(); } - } - // Setup Irrlicht to cache this control to a texture - void SetupCacheTexture(CacheHandle control) - { - auto it = m_TextureCache.find(control); - if (it != m_TextureCache.end()) + bool Irrlicht::EnsureTexture(const Gwk::Texture& texture) { - m_Driver->setRenderTarget((*it).second); + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; } - } - - // Revert Irrlicht's render target - void FinishCacheTexture(CacheHandle control) - { - m_Driver->setRenderTarget(NULL); - } - // Draw this controls cached texture - void DrawCachedControlTexture(CacheHandle control) - { - auto it = m_TextureCache.find(control); - if (it != m_TextureCache.end()) + // + // Irrlicht ICacheToTexture + // + class IrrlichtCTT : public Gwk::Renderer::ICacheToTexture { - const Gwk::Point &pos = m_renderer->GetRenderOffset(); - m_Driver->draw2DImage((*it).second, - irr::core::vector2di(pos.x, pos.y), - irr::core::rect(irr::core::dimension2d(0, 0), - (*it).second->getSize()), - NULL, - irr::video::SColor(255, 255, 255, 255), - true); + private: + Gwk::Renderer::Base *m_renderer; + + irr::video::IVideoDriver* m_Driver; + std::map m_TextureCache; + + public: + IrrlichtCTT(irr::video::IVideoDriver* VideoDriver) : m_Driver(VideoDriver) {} + + ~IrrlichtCTT() + { + // Cleanup all cached textures + for (auto it : m_TextureCache) + { + m_Driver->removeTexture(it.second); + } + } + + void SetRenderer(Gwk::Renderer::Base* renderer) { m_renderer = renderer; } + + void Initialize() {} + void ShutDown() {} + + // + // Create this controls cached texture if it doesn't already exist + void CreateControlCacheTexture(CacheHandle control, const Point& size) + { + if (m_TextureCache.find(control) == m_TextureCache.end()) + { + irr::video::ITexture* RTT = + m_Driver->addRenderTargetTexture( + irr::core::dimension2d(size.x, size.y)); + m_TextureCache.insert(std::pair(control, RTT)); + } + } + + // Setup Irrlicht to cache this control to a texture + void SetupCacheTexture(CacheHandle control) + { + auto it = m_TextureCache.find(control); + if (it != m_TextureCache.end()) + { + m_Driver->setRenderTarget((*it).second); + } + } + + // Revert Irrlicht's render target + void FinishCacheTexture(CacheHandle control) + { + m_Driver->setRenderTarget(NULL); + } + + // Draw this controls cached texture + void DrawCachedControlTexture(CacheHandle control) + { + auto it = m_TextureCache.find(control); + if (it != m_TextureCache.end()) + { + const Gwk::Point &pos = m_renderer->GetRenderOffset(); + m_Driver->draw2DImage((*it).second, + irr::core::vector2di(pos.x, pos.y), + irr::core::rect(irr::core::dimension2d(0, 0), + (*it).second->getSize()), + NULL, + irr::video::SColor(255, 255, 255, 255), + true); + } + } + + void UpdateControlCacheTexture(CacheHandle control) {} + }; + + + // + // Irrlicht Renderer + // + Irrlicht::Irrlicht(ResourcePaths& paths, irr::IrrlichtDevice* Device) + : Base(paths) + , m_CTT(new IrrlichtCTT(Device->getVideoDriver())) + , Driver(Device->getVideoDriver()) + , m_lastTexture(nullptr) + { + m_CTT->SetRenderer(this); + m_CTT->Initialize(); + DrawColor.set(255, 255, 255, 255); + ClipRect = irr::core::rect(); + Text = Device->getGUIEnvironment()->getBuiltInFont(); } - } - void UpdateControlCacheTexture(CacheHandle control) {} -}; - - -// -// Irrlicht Renderer -// -Irrlicht::Irrlicht(ResourcePaths& paths, irr::IrrlichtDevice* Device) - : Base(paths) - , m_CTT(new IrrlichtCTT(Device->getVideoDriver())) - , Driver(Device->getVideoDriver()) -{ - m_CTT->SetRenderer(this); - m_CTT->Initialize(); - DrawColor.set(255, 255, 255, 255); - ClipRect = irr::core::rect(); - Text = Device->getGUIEnvironment()->getBuiltInFont(); -} + Irrlicht::~Irrlicht() + { + delete m_CTT; + } -Irrlicht::~Irrlicht() -{ - delete m_CTT; -} + void Irrlicht::SetDrawColor(Gwk::Color color) + { + DrawColor.set((irr::u32)color.a, (irr::u32)color.r, (irr::u32)color.g, (irr::u32)color.b); + } -void Irrlicht::SetDrawColor(Gwk::Color color) -{ - DrawColor.set((irr::u32)color.a, (irr::u32)color.r, (irr::u32)color.g, (irr::u32)color.b); -} + void Irrlicht::StartClip() + { + const Gwk::Rect rect = ClipRegion(); + ClipRect.UpperLeftCorner = irr::core::vector2di(rect.x, rect.y); + ClipRect.LowerRightCorner = irr::core::vector2di(rect.x + rect.w, rect.y + rect.h); + } -void Irrlicht::StartClip() -{ - const Gwk::Rect rect = ClipRegion(); - ClipRect.UpperLeftCorner = irr::core::vector2di(rect.x, rect.y); - ClipRect.LowerRightCorner = irr::core::vector2di(rect.x + rect.w, rect.y + rect.h); -} + void Irrlicht::EndClip() + { + ClipRect.UpperLeftCorner = irr::core::vector2di(0, 0); + ClipRect.LowerRightCorner = irr::core::vector2di(0, 0); + } -void Irrlicht::EndClip() -{ - ClipRect.UpperLeftCorner = irr::core::vector2di(0, 0); - ClipRect.LowerRightCorner = irr::core::vector2di(0, 0); -} + Gwk::Color Irrlicht::PixelColor(const Gwk::Texture& texture, + unsigned int x, unsigned int y, const Gwk::Color& col_default) + { -Gwk::Color Irrlicht::PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, const Gwk::Color& col_default) -{ - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) + if (!EnsureTexture(texture)) + return col_default; + + IRTextureData& texData = m_lastTexture->second; + + irr::video::ITexture* Texture = texData.texture.get(); + + const irr::u32 pitch = Texture->getPitch(); + const irr::video::ECOLOR_FORMAT format = Texture->getColorFormat(); + const irr::u32 bytes = irr::video::IImage::getBitsPerPixelFromFormat(format) / 8; + + if (!texData.readable) + { + + unsigned char* buffer = (unsigned char*)Texture->lock(); + if (buffer) + { + texData.m_ReadData = deleted_unique_ptr( + new unsigned char[texData.width * texData.height * bytes], + [](unsigned char* mem) { if (mem) delete[](mem); }); + memcpy(texData.m_ReadData.get(), buffer, texData.width * texData.height * bytes); + texData.readable = true; + const irr::video::SColor pixelColor = irr::video::SColor(*(unsigned int*)(buffer + (y * pitch) + (x*bytes))); + Texture->unlock(); + return Gwk::Color(pixelColor.getRed(), + pixelColor.getGreen(), + pixelColor.getBlue(), + pixelColor.getAlpha()); + } + } + else + { + + const irr::video::SColor pixelColor = irr::video::SColor(*(unsigned int*)(texData.m_ReadData.get() + (y * pitch) + (x*bytes))); + return Gwk::Color(pixelColor.getRed(), + pixelColor.getGreen(), + pixelColor.getBlue(), + pixelColor.getAlpha()); + } return col_default; + } - it = m_textures.find(texture); - } - - IRTextureData& texData = it->second; - - irr::video::ITexture* Texture = texData.texture.get(); - - const irr::u32 pitch = Texture->getPitch(); - const irr::video::ECOLOR_FORMAT format = Texture->getColorFormat(); - const irr::u32 bytes = irr::video::IImage::getBitsPerPixelFromFormat(format) / 8; - - if (!texData.readable) - { - - unsigned char* buffer = (unsigned char*)Texture->lock(); - if (buffer) + void Irrlicht::RenderText(const Gwk::Font& font, Gwk::Point pos, const Gwk::String & text) { - texData.m_ReadData = deleted_unique_ptr(new unsigned char[texData.width * texData.height * bytes], [](unsigned char* mem) { if (mem) delete[](mem); }); - memcpy(texData.m_ReadData.get(), buffer, texData.width * texData.height * bytes); - texData.readable = true; - const irr::video::SColor pixelColor = irr::video::SColor(*(unsigned int*)(buffer + (y * pitch) + (x*bytes))); - Texture->unlock(); - return Gwk::Color(pixelColor.getRed(), - pixelColor.getGreen(), - pixelColor.getBlue(), - pixelColor.getAlpha()); + Translate(pos.x, pos.y); + Text->draw(text.c_str(), + irr::core::rect(pos.x, pos.y, pos.x, pos.y), + DrawColor, + false, + false, + &ClipRect); } - } - else - { - - const irr::video::SColor pixelColor = irr::video::SColor(*(unsigned int*)(texData.m_ReadData.get() + (y * pitch) + (x*bytes))); - return Gwk::Color(pixelColor.getRed(), - pixelColor.getGreen(), - pixelColor.getBlue(), - pixelColor.getAlpha()); - } - return col_default; -} - -void Irrlicht::RenderText(const Gwk::Font& font, Gwk::Point pos, const Gwk::String & text) -{ - Translate(pos.x, pos.y); - Text->draw(text.c_str(), - irr::core::rect(pos.x, pos.y, pos.x, pos.y), - DrawColor, - false, - false, - &ClipRect); -} - -Gwk::Point Irrlicht::MeasureText(const Gwk::Font& font, const Gwk::String & text) -{ - // Get size of string from Irrlicht (hopefully correct for TTF stuff) - const std::wstring wText(text.begin(), text.end()); - const irr::core::dimension2d irrDimension = Text->getDimension(wText.c_str()); - return Gwk::Point(irrDimension.Width, irrDimension.Height);; -} - -void Irrlicht::DrawTexturedRect(const Gwk::Texture& texture, - Gwk::Rect pTargetRect, - float u1, float v1, float u2, float v2) -{ - Translate(pTargetRect); + Gwk::Point Irrlicht::MeasureText(const Gwk::Font& font, const Gwk::String & text) + { + // Get size of string from Irrlicht (hopefully correct for TTF stuff) + const std::wstring wText(text.begin(), text.end()); + const irr::core::dimension2d irrDimension = Text->getDimension(wText.c_str()); - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(pTargetRect); + return Gwk::Point(irrDimension.Width, irrDimension.Height);; + } - it = m_textures.find(texture); - } + void Irrlicht::DrawTexturedRect(const Gwk::Texture& texture, + Gwk::Rect pTargetRect, + float u1, float v1, float u2, float v2) + { + if (!EnsureTexture(texture)) + return DrawMissingImage(pTargetRect); - IRTextureData& texData = it->second; + Translate(pTargetRect); - const unsigned int w = texData.width; - const unsigned int h = texData.height; + IRTextureData& texData = m_lastTexture->second; - Driver->draw2DImage(texData.texture.get(), - irr::core::rect(pTargetRect.x, - pTargetRect.y, - pTargetRect.x + pTargetRect.w, - pTargetRect.y + pTargetRect.h), - irr::core::rect(u1*w, v1*h, u2*w, v2*h), - &ClipRect, - 0, - true); + const unsigned int w = texData.width; + const unsigned int h = texData.height; -} + Driver->draw2DImage(texData.texture.get(), + irr::core::rect(pTargetRect.x, + pTargetRect.y, + pTargetRect.x + pTargetRect.w, + pTargetRect.y + pTargetRect.h), + irr::core::rect(u1*w, v1*h, u2*w, v2*h), + &ClipRect, + 0, + true); + } -void Irrlicht::DrawFilledRect(Gwk::Rect rect) -{ - Translate(rect); - Driver->draw2DRectangle(DrawColor, - irr::core::rect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h), &ClipRect); -} + void Irrlicht::DrawFilledRect(Gwk::Rect rect) + { + Translate(rect); + Driver->draw2DRectangle(DrawColor, + irr::core::rect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h), &ClipRect); + } -void Irrlicht::DrawLinedRect(Gwk::Rect rect) -{ - Translate(rect); - Driver->draw2DRectangleOutline( - irr::core::rect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h), - DrawColor); -} + void Irrlicht::DrawLinedRect(Gwk::Rect rect) + { + Translate(rect); + Driver->draw2DRectangleOutline( + irr::core::rect(rect.x, rect.y, rect.x + rect.w, rect.y + rect.h), + DrawColor); + } -void Irrlicht::DrawPixel(int x, int y) -{ - Translate(x, y); - Driver->drawPixel(x, y, DrawColor); -} + void Irrlicht::DrawPixel(int x, int y) + { + Translate(x, y); + Driver->drawPixel(x, y, DrawColor); + } -ICacheToTexture* Irrlicht::GetCTT() { return m_CTT; } + ICacheToTexture* Irrlicht::GetCTT() { return m_CTT; } -} + } } diff --git a/source/platform/renderers/OpenGL/OpenGL.cpp b/source/platform/renderers/OpenGL/OpenGL.cpp index e8122b79..d830cae6 100644 --- a/source/platform/renderers/OpenGL/OpenGL.cpp +++ b/source/platform/renderers/OpenGL/OpenGL.cpp @@ -44,7 +44,7 @@ namespace Renderer // See "Font Size in Pixels or Points" in "stb_truetype.h" static constexpr float c_pointsToPixels = 1.333f; // Arbitrary size chosen for texture cache target. -static constexpr int c_texsz = 512; +static constexpr int c_texsz = 800; // Texture size too small for wchar_t characters but stbtt_BakeFontBitmap crashes on larger sizes OpenGL::GLTextureData::~GLTextureData() { @@ -54,6 +54,9 @@ OpenGL::GLTextureData::~GLTextureData() Font::Status OpenGL::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); std::ifstream inFile(filename, std::ifstream::in | std::ifstream::binary); @@ -77,8 +80,6 @@ Font::Status OpenGL::LoadFont(const Font& font) std::unique_ptr font_bmp = std::unique_ptr(new unsigned char[c_texsz * c_texsz]); GLFontData fontData; - fontData.width = c_texsz; - fontData.height = c_texsz; const float realsize = font.size * Scale(); fontData.baked_chars.resize(LastCharacter - BeginCharacter + 1); @@ -98,28 +99,47 @@ Font::Status OpenGL::LoadFont(const Font& font) GL_ALPHA, GL_UNSIGNED_BYTE, font_bmp.get()); - m_fonts.insert(std::make_pair(font, std::move(fontData))); + fontData.width = c_texsz; + fontData.height = c_texsz; + + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } void OpenGL::FreeFont(const Gwk::Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls GLFontData destructor } bool OpenGL::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status OpenGL::LoadTexture(const Texture& texture) { FreeTexture(texture); + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); @@ -157,17 +177,23 @@ Texture::Status OpenGL::LoadTexture(const Texture& texture) texData.width = width; texData.height = height; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } -void OpenGL::FreeTexture(const Texture& texture) +void OpenGL::FreeTexture(const Gwk::Texture& texture) { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + m_textures.erase(texture); // calls GLTextureData destructor } TextureData OpenGL::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -177,6 +203,28 @@ TextureData OpenGL::GetTextureData(const Texture& texture) const return TextureData(); } +bool OpenGL::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} + //------------------------------------------------------------------------------- OpenGL::OpenGL(ResourcePaths& paths, const Rect& viewRect) @@ -184,6 +232,8 @@ OpenGL::OpenGL(ResourcePaths& paths, const Rect& viewRect) , m_viewRect(viewRect) , m_vertNum(0) , m_context(nullptr) +, m_lastFont(nullptr) +, m_lastTexture(nullptr) { for (int i = 0; i < MaxVerts; i++) { @@ -319,16 +369,10 @@ void OpenGL::EndClip() void OpenGL::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rect); - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return DrawMissingImage(rect); - GLTextureData& texData = it->second; + const GLTextureData& texData = m_lastTexture->second; Translate(rect); @@ -349,16 +393,10 @@ void OpenGL::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, Gwk::Color OpenGL::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; + if (!EnsureTexture(texture)) + return col_default; - it = m_textures.find(texture); - } - - GLTextureData& texData = it->second; + GLTextureData& texData = m_lastTexture->second; static const unsigned int iPixelSize = sizeof(unsigned char) * 4; @@ -384,13 +422,7 @@ void OpenGL::RenderText(const Gwk::Font& font, Gwk::Point pos, if (!EnsureFont(font)) return; - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return; - - GLFontData& fontData = it->second; + GLFontData& fontData = m_lastFont->second; if (m_current_texture != fontData.texture_id) { @@ -434,13 +466,7 @@ Gwk::Point OpenGL::MeasureText(const Gwk::Font& font, const Gwk::String& text) if (!EnsureFont(font)) return Gwk::Point(0, 0); - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return Gwk::Point(0, 0); - - GLFontData& fontData = it->second; + GLFontData& fontData = m_lastFont->second; Point sz(0, font.size * Scale() * c_pointsToPixels); diff --git a/source/platform/renderers/OpenGLCore/OpenGLCore.cpp b/source/platform/renderers/OpenGLCore/OpenGLCore.cpp index e0a8edfd..05cc1901 100644 --- a/source/platform/renderers/OpenGLCore/OpenGLCore.cpp +++ b/source/platform/renderers/OpenGLCore/OpenGLCore.cpp @@ -51,7 +51,7 @@ namespace Renderer { // See "Font Size in Pixels or Points" in "stb_truetype.h" static constexpr float c_pointsToPixels = 1.333f; // Arbitrary size chosen for texture cache target. -static constexpr int c_texsz = 512; +static constexpr int c_texsz = 800; // Texture size too small for wchar_t characters but stbtt_BakeFontBitmap crashes on larger sizes OpenGLCore::GLTextureData::~GLTextureData() @@ -62,6 +62,9 @@ OpenGLCore::GLTextureData::~GLTextureData() Font::Status OpenGLCore::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); std::ifstream inFile(filename, std::ifstream::in | std::ifstream::binary); @@ -85,17 +88,15 @@ Font::Status OpenGLCore::LoadFont(const Font& font) std::unique_ptr font_bmp = std::unique_ptr(new unsigned char[c_texsz * c_texsz]); GLFontData fontData; - fontData.width = c_texsz; - fontData.height = c_texsz; const float realsize = font.size * Scale(); fontData.baked_chars.resize(LastCharacter - BeginCharacter + 1); stbtt_BakeFontBitmap(ttfdata.get(), 0, - realsize * c_pointsToPixels, // height - font_bmp.get(), - c_texsz, c_texsz, - BeginCharacter, LastCharacter, // range to bake - reinterpret_cast(fontData.baked_chars.data())); + realsize * c_pointsToPixels, // height + font_bmp.get(), + c_texsz, c_texsz, + BeginCharacter, LastCharacter, // range to bake + reinterpret_cast(fontData.baked_chars.data())); glGenTextures(1, &fontData.texture_id); SetTexture(fontData.texture_id); @@ -106,28 +107,47 @@ Font::Status OpenGLCore::LoadFont(const Font& font) GL_RED, GL_UNSIGNED_BYTE, font_bmp.get()); - m_fonts.insert(std::make_pair(font, std::move(fontData))); + fontData.width = c_texsz; + fontData.height = c_texsz; + + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } void OpenGLCore::FreeFont(const Gwk::Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls GLFontData destructor } bool OpenGLCore::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status OpenGLCore::LoadTexture(const Texture& texture) { FreeTexture(texture); + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); @@ -165,17 +185,23 @@ Texture::Status OpenGLCore::LoadTexture(const Texture& texture) texData.width = width; texData.height = height; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } -void OpenGLCore::FreeTexture(const Texture& texture) +void OpenGLCore::FreeTexture(const Gwk::Texture& texture) { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + m_textures.erase(texture); // calls GLTextureData destructor } TextureData OpenGLCore::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -185,6 +211,28 @@ TextureData OpenGLCore::GetTextureData(const Texture& texture) const return TextureData(); } +bool OpenGLCore::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} + //------------------------------------------------------------------------------- OpenGLCore::OpenGLCore(ResourcePaths& paths, const Rect& viewRect) @@ -193,6 +241,8 @@ OpenGLCore::OpenGLCore(ResourcePaths& paths, const Rect& viewRect) , m_viewRect(viewRect) , m_current_texture(0) , m_vertices(1024) + , m_lastFont(nullptr) + , m_lastTexture(nullptr) { } @@ -456,16 +506,10 @@ void OpenGLCore::EndClip() void OpenGLCore::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rect); + if (!EnsureTexture(texture)) + return DrawMissingImage(rect); - it = m_textures.find(texture); - } - - GLTextureData& texData = it->second; + GLTextureData& texData = m_lastTexture->second; Translate(rect); @@ -487,16 +531,10 @@ void OpenGLCore::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, Gwk::Color OpenGLCore::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return col_default; - GLTextureData& texData = it->second; + GLTextureData& texData = m_lastTexture->second; static const unsigned int iPixelSize = sizeof(unsigned char) * 4; @@ -521,14 +559,8 @@ void OpenGLCore::RenderText(const Gwk::Font& font, Gwk::Point pos, { if (!EnsureFont(font)) return; - - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return; - - GLFontData& fontData = it->second; + + GLFontData& fontData = m_lastFont->second; if (m_current_texture != fontData.texture_id) { @@ -550,7 +582,7 @@ void OpenGLCore::RenderText(const Gwk::Font& font, Gwk::Point pos, stbtt_aligned_quad q; stbtt_GetBakedQuad(reinterpret_cast(fontData.baked_chars.data()), - c_texsz, c_texsz, + fontData.width, fontData.height, c, &x, &y, &q, 1); // 1=opengl & d3d10+,0=d3d9 @@ -572,13 +604,7 @@ Gwk::Point OpenGLCore::MeasureText(const Gwk::Font& font, const Gwk::String& tex if (!EnsureFont(font)) return Gwk::Point(0, 0); - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return Gwk::Point(0, 0); - - GLFontData& fontData = it->second; + GLFontData& fontData = m_lastFont->second; Point sz(0, font.size * Scale() * c_pointsToPixels); @@ -595,7 +621,7 @@ Gwk::Point OpenGLCore::MeasureText(const Gwk::Font& font, const Gwk::String& tex stbtt_aligned_quad q; stbtt_GetBakedQuad(reinterpret_cast(fontData.baked_chars.data()), - c_texsz, c_texsz, + fontData.width, fontData.height, c, &x, &y, &q, 1); // 1=opengl & d3d10+,0=d3d9 diff --git a/source/platform/renderers/SDL2/SDL2.cpp b/source/platform/renderers/SDL2/SDL2.cpp index fc96cac0..4c9c2c25 100644 --- a/source/platform/renderers/SDL2/SDL2.cpp +++ b/source/platform/renderers/SDL2/SDL2.cpp @@ -16,6 +16,9 @@ namespace Renderer Font::Status SDL2::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); TTF_Font *tfont = TTF_OpenFont(filename.c_str(), font.size * Scale()); @@ -23,7 +26,7 @@ Font::Status SDL2::LoadFont(const Font& font) { SDL2FontData fontData; fontData.tFont = deleted_unique_ptr(tfont, [](TTF_Font* mem) { if (mem) TTF_CloseFont(mem); }); - m_fonts.insert(std::make_pair(font, std::move(fontData))); + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } else @@ -35,22 +38,38 @@ Font::Status SDL2::LoadFont(const Font& font) void SDL2::FreeFont(const Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls SDL2FontData destructor } bool SDL2::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status SDL2::LoadTexture(const Texture& texture) { FreeTexture(texture); + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); @@ -94,7 +113,7 @@ Texture::Status SDL2::LoadTexture(const Texture& texture) texData.texture = deleted_unique_ptr(tex, [](SDL_Texture* mem) { if (mem) SDL_DestroyTexture(mem); }); texData.width = w; texData.height = h; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } else @@ -105,11 +124,17 @@ Texture::Status SDL2::LoadTexture(const Texture& texture) void SDL2::FreeTexture(const Texture& texture) { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + m_textures.erase(texture); // calls SDLTextureData destructor } TextureData SDL2::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -119,12 +144,36 @@ TextureData SDL2::GetTextureData(const Texture& texture) const return TextureData(); } +bool SDL2::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} + //------------------------------------------------------------------------------- SDL2::SDL2(ResourcePaths& paths, SDL_Window *window) : Base(paths) , m_window(window) , m_renderer(nullptr) + , m_lastFont(nullptr) + , m_lastTexture(nullptr) { m_renderer = SDL_GetRenderer( m_window ); } @@ -148,13 +197,7 @@ void SDL2::RenderText(const Gwk::Font& font, Gwk::Point pos, const Gwk::String& if (!EnsureFont(font)) return; - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return; - - SDL2FontData& fontData = it->second; + SDL2FontData& fontData = m_lastFont->second; Translate(pos.x, pos.y); @@ -176,13 +219,7 @@ Gwk::Point SDL2::MeasureText(const Gwk::Font& font, const Gwk::String& text) if (!EnsureFont(font)) return Gwk::Point(0, 0); - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return Gwk::Point(0, 0); - - SDL2FontData& fontData = it->second; + SDL2FontData& fontData = m_lastFont->second; int w,h; TTF_SizeUTF8(fontData.tFont.get(), text.c_str(), &w,&h); @@ -220,19 +257,13 @@ void SDL2::EndClip() void SDL2::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rect); - - it = m_textures.find(texture); - } - - SDL2TextureData& texData = it->second; + if (!EnsureTexture(texture)) + return DrawMissingImage(rect); Translate(rect); + SDL2TextureData& texData = m_lastTexture->second; + const unsigned int w = texData.width; const unsigned int h = texData.height; @@ -245,16 +276,10 @@ void SDL2::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, Gwk::Color SDL2::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return col_default; - SDL2TextureData& texData = it->second; + SDL2TextureData& texData = m_lastTexture->second; if (!texData.readable || !texData.surface) return col_default; diff --git a/source/platform/renderers/Software/Software.cpp b/source/platform/renderers/Software/Software.cpp index e7193d5e..17d767ee 100644 --- a/source/platform/renderers/Software/Software.cpp +++ b/source/platform/renderers/Software/Software.cpp @@ -48,7 +48,7 @@ namespace Drawing Color *px = &pb.At(r.x, r.y + y); for (int x = r.w; x > 0; --x) { - *px++ = c; + *px++ = BlendAlpha(c, *px); } } } @@ -59,15 +59,15 @@ namespace Drawing { for (int x = 0; x < r.w; ++x) { - pb.At(r.x + x, r.y) = c; // top + pb.At(r.x + x, r.y) = BlendAlpha(c, pb.At(r.x + x, r.y)); // top if (r.h > 1) - pb.At(r.x + x, r.y + r.h - 1) = c; // bottom + pb.At(r.x + x, r.y + r.h - 1) = BlendAlpha(c, pb.At(r.x + x, r.y + r.h - 1)); // bottom } for (int y = 0; y < r.h; ++y) { - pb.At(r.x, r.y + y) = c; // left + pb.At(r.x, r.y + y) = BlendAlpha(c, pb.At(r.x, r.y + y)); // left if (r.w > 1) - pb.At(r.x + r.w - 1, r.y + y) = c; // right + pb.At(r.x + r.w - 1, r.y + y) = BlendAlpha(c, pb.At(r.x + r.w - 1, r.y + y)); // right } } @@ -101,10 +101,14 @@ namespace Drawing // See "Font Size in Pixels or Points" in "stb_truetype.h" static constexpr float c_pointsToPixels = 1.333f; -static constexpr int c_texsz = 512; // arbitrary font cache texture size +// arbitrary font cache texture size +static constexpr int c_texsz = 800; // Texture size too small for wchar_t characters but stbtt_BakeFontBitmap crashes on larger sizes Font::Status Software::LoadFont(const Font& font) { + FreeFont(font); + m_lastFont = nullptr; + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); std::ifstream inFile(filename, std::ifstream::in | std::ifstream::binary); @@ -142,28 +146,44 @@ Font::Status Software::LoadFont(const Font& font) BeginCharacter, LastCharacter, // range to bake reinterpret_cast(fontData.baked_chars.data())); - m_fonts.insert(std::make_pair(font, std::move(fontData))); + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); return Font::Status::Loaded; } void Software::FreeFont(const Gwk::Font& font) { + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; + m_fonts.erase(font); // calls SWFontData destructor } bool Software::EnsureFont(const Font& font) { + if (m_lastFont != nullptr) + { + if (m_lastFont->first == font) + return true; + } + + // Was it loaded before? auto it = m_fonts.find(font); - if (it != m_fonts.cend()) + if (it != m_fonts.end()) { + m_lastFont = &(*it); return true; } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded return LoadFont(font) == Font::Status::Loaded; } Texture::Status Software::LoadTexture(const Texture& texture) { FreeTexture(texture); + m_lastTexture = nullptr; const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); @@ -191,17 +211,23 @@ Texture::Status Software::LoadTexture(const Texture& texture) texData.width = width; texData.height = height; - m_textures.insert(std::make_pair(texture, std::move(texData))); + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); return Texture::Status::Loaded; } -void Software::FreeTexture(const Texture& texture) +void Software::FreeTexture(const Gwk::Texture& texture) { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + m_textures.erase(texture); // calls SWTextureData destructor } TextureData Software::GetTextureData(const Texture& texture) const { + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + auto it = m_textures.find(texture); if (it != m_textures.cend()) { @@ -211,12 +237,35 @@ TextureData Software::GetTextureData(const Texture& texture) const return TextureData(); } +bool Software::EnsureTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) + { + m_lastTexture = &(*it); + return true; + } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; +} //------------------------------------------------------------------------------- Software::Software(ResourcePaths& paths, PixelBuffer& pbuff) : Base(paths) , m_isClipping(false) , m_pixbuf(&pbuff) + , m_lastFont(nullptr) + , m_lastTexture(nullptr) { } @@ -234,13 +283,7 @@ Gwk::Point Software::MeasureText(const Gwk::Font& font, const Gwk::String& text) if (!EnsureFont(font)) return Gwk::Point(0, 0); - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return Gwk::Point(0, 0); - - SWFontData& fontData = it->second; + SWFontData& fontData = m_lastFont->second; Point sz(0, font.size * Scale() * c_pointsToPixels); @@ -272,14 +315,8 @@ void Software::RenderText(const Gwk::Font& font, Gwk::Point pos, { if (!EnsureFont(font)) return; - - // at this point, the font is garented created - auto it = m_fonts.find(font); - // but double check :) - if (it == m_fonts.cend()) - return; - - SWFontData& fontData = it->second; + + SWFontData& fontData = m_lastFont->second; float x = pos.x, y = pos.y; char* text_ptr = const_cast(text.c_str()); @@ -415,36 +452,25 @@ void Software::DrawLinedRect(Gwk::Rect rect) void Software::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { + if (!EnsureTexture(texture)) + return DrawMissingImage(rect); + + const SWTextureData& texData = m_lastTexture->second; + Translate(rect); if (!Clip(rect)) return; - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return DrawMissingImage(rect); - - it = m_textures.find(texture); - } - - SWTextureData& texData = it->second; Drawing::RectTextured(*m_pixbuf, texData, rect, u1,v1, u2,v2); } Gwk::Color Software::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - auto it = m_textures.find(texture); - if (it == m_textures.cend()) - { - if (LoadTexture(texture) != Texture::Status::Loaded) - return col_default; - - it = m_textures.find(texture); - } + if (!EnsureTexture(texture)) + return col_default; - SWTextureData& texData = it->second; + const SWTextureData& texData = m_lastTexture->second; return texData.At(x, y); } From f920ad2c39ce5c807a3c18ac35600eaa92f050ef Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 07:08:38 -0400 Subject: [PATCH 2/6] Update SFML2 Renderer --- .../platform/include/Gwork/Renderers/SFML2.h | 110 +++++++-- source/platform/renderers/SFML2/SFML2.cpp | 231 ++++++++++-------- source/samples/SFML2/SFML2Sample.cpp | 3 +- 3 files changed, 216 insertions(+), 128 deletions(-) diff --git a/source/platform/include/Gwork/Renderers/SFML2.h b/source/platform/include/Gwork/Renderers/SFML2.h index 449d1919..0ab23651 100644 --- a/source/platform/include/Gwork/Renderers/SFML2.h +++ b/source/platform/include/Gwork/Renderers/SFML2.h @@ -14,43 +14,37 @@ #include #include #include +#include #include +#include +#include +#include +#include + namespace Gwk { namespace Renderer { - //! Default resource loader for SFML2. - class SFML2ResourceLoader : public ResourceLoader - { - ResourcePaths& m_paths; - public: - SFML2ResourceLoader(ResourcePaths& paths) - : m_paths(paths) - {} - - Font::Status LoadFont(Font& font) override; - void FreeFont(Font& font) override; - - Texture::Status LoadTexture(Texture& texture) override; - void FreeTexture(Texture& texture) override; - }; // //! Renderer for [SFML2](https://www.sfml-dev.org/). // class GWK_EXPORT SFML2 : public Gwk::Renderer::Base { + template + using deleted_unique_ptr = std::unique_ptr>; + public: //! Constructor for SFML2 renderer. //! \param loader : ResourceLoader for renderer. //! \param target : application render target. - SFML2(ResourceLoader& loader, sf::RenderTarget& target); + SFML2(ResourcePaths& paths, sf::RenderTarget& target); virtual ~SFML2(); - inline void EnsurePrimitiveType(sf::PrimitiveType type) + inline void SetPrimitiveType(sf::PrimitiveType type) { if (m_buffer.getPrimitiveType() != type) { @@ -59,7 +53,7 @@ namespace Gwk } } - inline void EnsureTexture(const sf::Texture *texture) + inline void SetTexture(const sf::Texture *texture) { if (m_renderStates.texture != texture) { @@ -99,16 +93,80 @@ namespace Gwk void DrawLinedRect(Gwk::Rect rect) override; void DrawFilledRect(Gwk::Rect rect) override; void DrawShavedCornerRect(Gwk::Rect rect, bool bSlight = false) override; - void DrawTexturedRect(Gwk::Texture* texture, - Gwk::Rect rect, - float u1, float v1, float u2, float v2) override; - void RenderText(Gwk::Font* font, Gwk::Point pos, const Gwk::String& text) override; - Gwk::Point MeasureText(Gwk::Font* font, const Gwk::String& text) override; + void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + + Gwk::Color PixelColor(const Gwk::Texture& texture, + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; + + void RenderText(const Gwk::Font& font, + Gwk::Point pos, + const Gwk::String& text) override; + + Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; + + // Resource Loader + Gwk::Font::Status LoadFont(const Gwk::Font& font) override; + void FreeFont(const Gwk::Font& font) override; + bool EnsureFont(const Gwk::Font& font) override; + + Texture::Status LoadTexture(const Gwk::Texture& texture) override; + void FreeTexture(const Gwk::Texture& texture) override; + TextureData GetTextureData(const Gwk::Texture& texture) const override; + bool EnsureTexture(const Gwk::Texture& texture) override; + protected:// Resourses + + struct SFMLTextureData : public Gwk::TextureData + { + SFMLTextureData() + { + } + SFMLTextureData(const SFMLTextureData&) = delete; + SFMLTextureData(SFMLTextureData&& other) + : SFMLTextureData() + { + std::swap(width, other.width); + std::swap(height, other.height); + std::swap(readable, other.readable); + + texture.swap(other.texture); + image.swap(other.image); + } + + ~SFMLTextureData() + { + } + + std::unique_ptr texture; + std::unique_ptr image; + }; + + struct SFMLFontData + { + SFMLFontData() + { + } + + SFMLFontData(const SFMLFontData&) = delete; + SFMLFontData(SFMLFontData&& other) + : SFMLFontData() + { + font.swap(other.font); + } + + ~SFMLFontData() + { + } + + std::unique_ptr font; + }; - Gwk::Color PixelColor(Gwk::Texture* texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + std::unordered_map m_fonts; + std::unordered_map m_textures; + std::pair* m_lastFont; + std::pair* m_lastTexture; protected: diff --git a/source/platform/renderers/SFML2/SFML2.cpp b/source/platform/renderers/SFML2/SFML2.cpp index 75f022fa..580d24ba 100644 --- a/source/platform/renderers/SFML2/SFML2.cpp +++ b/source/platform/renderers/SFML2/SFML2.cpp @@ -16,119 +16,155 @@ #ifdef __APPLE__ # include #else +#ifdef _WIN32 +#include +#endif # include #endif #include -#include using namespace Gwk; -class FontData : public Font::IData -{ -public: - FontData(std::unique_ptr&& pFont) - :font(std::move(pFont)) - { - } - - ~FontData() - { - } - std::unique_ptr font; -}; - -struct TextureData +Font::Status Gwk::Renderer::SFML2::LoadFont(const Gwk::Font& font) { - TextureData(sf::Image* img) : texture(nullptr), image(img) {} - - TextureData(sf::Texture* text) : texture(text), image(nullptr) {} - - ~TextureData() - { - delete texture; - delete image; - } + FreeFont(font); + m_lastFont = nullptr; - sf::Texture *texture; - sf::Image *image; -}; - -Font::Status Gwk::Renderer::SFML2ResourceLoader::LoadFont(Font& font) -{ - const String filename = m_paths.GetPath(ResourcePaths::Type::Font, font.facename); + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Font, font.facename); std::unique_ptr sfFont{new sf::Font()}; if (sfFont->loadFromFile(filename)) { - std::shared_ptr fontData = std::make_shared(std::move(sfFont)); - font.data = Utility::dynamic_pointer_cast(fontData); - font.status = Font::Status::Loaded; + SFMLFontData fontData; + fontData.font = std::move(sfFont); + + m_lastFont = &(*m_fonts.insert(std::make_pair(font, std::move(fontData))).first); + return Font::Status::Loaded; } else { Gwk::Log::Write(Log::Level::Error, "Font file not found: %s", filename.c_str()); - delete sfFont; - font.status = Font::Status::ErrorFileNotFound; + return Font::Status::ErrorFileNotFound; } +} + +void Gwk::Renderer::SFML2::FreeFont(const Gwk::Font& font) +{ + if (m_lastFont != nullptr && m_lastFont->first == font) + m_lastFont = nullptr; - return font.status; + m_fonts.erase(font); // calls SFMLFontData destructor } -void Gwk::Renderer::SFML2ResourceLoader::FreeFont(Gwk::Font& font) +bool Gwk::Renderer::SFML2::EnsureFont(const Font& font) { - if (font.IsLoaded()) + if (m_lastFont != nullptr) { - font.data.reset(); - font.status = Font::Status::Unloaded; + if (m_lastFont->first == font) + return true; } + + // Was it loaded before? + auto it = m_fonts.find(font); + if (it != m_fonts.end()) + { + m_lastFont = &(*it); + return true; + } + + // No, try load to it + + // LoadFont sets m_lastFont, if loaded + return LoadFont(font) == Font::Status::Loaded; } -Texture::Status Gwk::Renderer::SFML2ResourceLoader::LoadTexture(Texture& texture) +Texture::Status Gwk::Renderer::SFML2::LoadTexture(const Gwk::Texture& texture) { - if (texture.IsLoaded()) - FreeTexture(texture); + FreeTexture(texture); + m_lastTexture = nullptr; sf::Texture* tex = new sf::Texture(); tex->setSmooth(true); - const String filename = m_paths.GetPath(ResourcePaths::Type::Texture, texture.name); + const String filename = GetResourcePaths().GetPath(ResourcePaths::Type::Texture, texture.name); if (tex->loadFromFile(filename)) { - texture.height = tex->getSize().x; - texture.width = tex->getSize().y; - texture.data = new TextureData(tex); - texture.status = Texture::Status::Loaded; + SFMLTextureData texData; + texData.height = tex->getSize().x; + texData.width = tex->getSize().y; + texData.texture = std::unique_ptr(tex); + if (texture.readable) + { + texData.image = std::unique_ptr(new sf::Image(texData.texture->copyToImage())); + texData.readable = true; + } + + m_lastTexture = &(*m_textures.insert(std::make_pair(texture, std::move(texData))).first); + return Texture::Status::Loaded; } else { Gwk::Log::Write(Log::Level::Error, "Texture file not found: %s", filename.c_str()); delete tex; - texture.status = Texture::Status::ErrorFileNotFound; + return Texture::Status::ErrorFileNotFound; } +} - return texture.status; +void Gwk::Renderer::SFML2::FreeTexture(const Gwk::Texture& texture) +{ + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + m_lastTexture = nullptr; + + m_textures.erase(texture); // calls SFMLTextureData destructor +} + +TextureData Gwk::Renderer::SFML2::GetTextureData(const Texture& texture) const +{ + if (m_lastTexture != nullptr && m_lastTexture->first == texture) + return m_lastTexture->second; + + auto it = m_textures.find(texture); + if (it != m_textures.cend()) + { + return it->second; + } + // Texture not loaded :( + return TextureData(); } -void Gwk::Renderer::SFML2ResourceLoader::FreeTexture(Texture& texture) +bool Gwk::Renderer::SFML2::EnsureTexture(const Gwk::Texture& texture) { - if (texture.IsLoaded()) + if (m_lastTexture != nullptr) + { + if (m_lastTexture->first == texture) + return true; + } + + // Was it loaded before? + auto it = m_textures.find(texture); + if (it != m_textures.end()) { - TextureData* data = static_cast(texture.data); - delete data; - texture.data = nullptr; - texture.status = Texture::Status::Unloaded; + m_lastTexture = &(*it); + return true; } + + // No, try load to it + + // LoadTexture sets m_lastTexture, if exist + return LoadTexture(texture) == Texture::Status::Loaded; } -Gwk::Renderer::SFML2::SFML2(ResourceLoader& loader, sf::RenderTarget& target) - : Base(loader) +Gwk::Renderer::SFML2::SFML2(ResourcePaths& paths, sf::RenderTarget& target) + : Base(paths) , m_target(target) , m_renderStates(sf::RenderStates::Default) , m_height(m_target.getSize().y) + , m_lastFont(nullptr) + , m_lastTexture(nullptr) { m_buffer.setPrimitiveType(sf::Triangles); m_renderStates.blendMode = sf::BlendAlpha; @@ -194,16 +230,16 @@ void Gwk::Renderer::SFML2::SetDrawColor(Gwk::Color color) void Gwk::Renderer::SFML2::DrawPixel(int x, int y) { - EnsurePrimitiveType(sf::Points); - EnsureTexture(nullptr); + SetPrimitiveType(sf::Points); + SetTexture(nullptr); Translate(x, y); AddVert(x, y+1); } void Gwk::Renderer::SFML2::DrawLinedRect(Gwk::Rect rect) { - EnsurePrimitiveType(sf::Lines); - EnsureTexture(nullptr); + SetPrimitiveType(sf::Lines); + SetTexture(nullptr); Translate(rect); @@ -226,8 +262,8 @@ void Gwk::Renderer::SFML2::DrawLinedRect(Gwk::Rect rect) void Gwk::Renderer::SFML2::DrawFilledRect(Gwk::Rect rect) { - EnsurePrimitiveType(sf::Triangles); - EnsureTexture(nullptr); + SetPrimitiveType(sf::Triangles); + SetTexture(nullptr); Translate(rect); @@ -246,19 +282,16 @@ void Gwk::Renderer::SFML2::DrawShavedCornerRect(Gwk::Rect rect, bool bSlight) Base::DrawShavedCornerRect(rect, bSlight); } -void Gwk::Renderer::SFML2::DrawTexturedRect(Gwk::Texture* texture, Gwk::Rect rect, float u1, +void Gwk::Renderer::SFML2::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, float u1, float v1, float u2, float v2) { - TextureData* data = reinterpret_cast(texture->data); - - // Missing image, not loaded properly? - if (!data) + if (!EnsureTexture(texture)) return DrawMissingImage(rect); - const sf::Texture* tex = data->texture; + const SFMLTextureData& texData = m_lastTexture->second; - EnsurePrimitiveType(sf::Triangles); - EnsureTexture(tex); + SetPrimitiveType(sf::Triangles); + SetTexture(texData.texture.get()); Translate(rect); @@ -271,63 +304,61 @@ void Gwk::Renderer::SFML2::DrawTexturedRect(Gwk::Texture* texture, Gwk::Rect rec AddVert(rect.x, rect.y+rect.h, u1, v2); } -void Gwk::Renderer::SFML2::RenderText(Gwk::Font* font, Gwk::Point pos, +void Gwk::Renderer::SFML2::RenderText(const Gwk::Font& font, Gwk::Point pos, const Gwk::String& text) { Flush(); - Translate(pos.x, pos.y); - FontData* fontdata = dynamic_cast(font->data.get()); - - if (fontdata == nullptr) + if (!EnsureFont(font)) return; - const sf::Font* sFFont = fontdata->font; + SFMLFontData& fontData = m_lastFont->second; + + Translate(pos.x, pos.y); sf::Text sfStr; sfStr.setString(text); - sfStr.setFont(*sFFont); + sfStr.setFont(*fontData.font); sfStr.move(pos.x, pos.y); - sfStr.setCharacterSize(font->realsize); - sfStr.setFillColor(m_color); + sfStr.setCharacterSize(font.size * Scale()); + sfStr.setColor(m_color); m_target.draw(sfStr); } -Gwk::Point Gwk::Renderer::SFML2::MeasureText(Gwk::Font* font, const Gwk::String& text) +Gwk::Point Gwk::Renderer::SFML2::MeasureText(const Gwk::Font& font, const Gwk::String& text) { - if (!EnsureFont(*font)) + if (!EnsureFont(font)) return Gwk::Point(0, 0); - FontData* fontdata = dynamic_cast(font->data.get()); - - if (fontdata == nullptr) - return; - - const sf::Font* sFFont = fontdata->font; + SFMLFontData& fontData = m_lastFont->second; sf::Text sfStr; sfStr.setString(text); - sfStr.setFont(*sFFont); + sfStr.setFont(*fontData.font); sfStr.setScale(Scale(), Scale()); - sfStr.setCharacterSize(font->realsize); + sfStr.setCharacterSize(font.size * Scale()); sf::FloatRect sz = sfStr.getLocalBounds(); return Gwk::Point(sz.left+sz.width, sz.top+sz.height); } -Gwk::Color Gwk::Renderer::SFML2::PixelColor(Gwk::Texture* texture, unsigned int x, +Gwk::Color Gwk::Renderer::SFML2::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, const Gwk::Color& col_default) { - TextureData* data = static_cast(texture->data); - if (!data->texture && !data->image) + if (!EnsureTexture(texture)) + return col_default; + + SFMLTextureData& texData = m_lastTexture->second; + + if (!texData.texture) return col_default; - if (!data->image) + if (!texData.readable) { - sf::Image copy = data->texture->copyToImage(); - data->image = new sf::Image(copy); + texData.image = std::unique_ptr(new sf::Image(texData.texture->copyToImage())); + texData.readable = true; } - const sf::Color col = data->image->getPixel(x, y); + const sf::Color col = texData.image->getPixel(x, y); return Gwk::Color(col.r, col.g, col.b, col.a); } diff --git a/source/samples/SFML2/SFML2Sample.cpp b/source/samples/SFML2/SFML2Sample.cpp index f0adb936..fe36007e 100644 --- a/source/samples/SFML2/SFML2Sample.cpp +++ b/source/samples/SFML2/SFML2Sample.cpp @@ -21,10 +21,9 @@ int main() sf::RenderWindow app(sf::VideoMode(1004, 650, 32), "Gwork SFML2 Sample"); Gwk::Platform::RelativeToExecutablePaths paths(GWORK_RESOURCE_DIR); - Gwk::Renderer::SFML2ResourceLoader loader(paths); // Create renderer - Gwk::Renderer::SFML2 renderer(loader, app); + Gwk::Renderer::SFML2 renderer(paths, app); // Create a Gwork skin Gwk::Skin::TexturedBase skin(&renderer); From ee87bd1955ce04fa7a7f6e6b8e891cfb3f1bb27e Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 10:46:48 -0400 Subject: [PATCH 3/6] Code formatting --- source/platform/include/Gwork/Renderers/Allegro5.h | 8 ++++---- source/platform/include/Gwork/Renderers/Irrlicht.h | 10 +++++----- source/platform/include/Gwork/Renderers/OpenGLCore.h | 10 +++++----- source/platform/include/Gwork/Renderers/SDL2.h | 10 +++++----- source/platform/include/Gwork/Renderers/SFML2.h | 10 +++++----- source/platform/include/Gwork/Renderers/Software.h | 10 +++++----- source/platform/renderers/OpenGLCore/OpenGLCore.cpp | 4 ++-- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/source/platform/include/Gwork/Renderers/Allegro5.h b/source/platform/include/Gwork/Renderers/Allegro5.h index 38a905cb..2e3d894f 100644 --- a/source/platform/include/Gwork/Renderers/Allegro5.h +++ b/source/platform/include/Gwork/Renderers/Allegro5.h @@ -48,12 +48,12 @@ namespace Gwk float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/include/Gwork/Renderers/Irrlicht.h b/source/platform/include/Gwork/Renderers/Irrlicht.h index 599edfd0..7bcf8064 100644 --- a/source/platform/include/Gwork/Renderers/Irrlicht.h +++ b/source/platform/include/Gwork/Renderers/Irrlicht.h @@ -54,15 +54,15 @@ namespace Gwk void DrawPixel(int x, int y) override; void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, - float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/include/Gwork/Renderers/OpenGLCore.h b/source/platform/include/Gwork/Renderers/OpenGLCore.h index 8f91a131..5e289727 100644 --- a/source/platform/include/Gwork/Renderers/OpenGLCore.h +++ b/source/platform/include/Gwork/Renderers/OpenGLCore.h @@ -42,15 +42,15 @@ namespace Gwk void EndClip() override; void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, - float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/include/Gwork/Renderers/SDL2.h b/source/platform/include/Gwork/Renderers/SDL2.h index 26042649..a455da4a 100644 --- a/source/platform/include/Gwork/Renderers/SDL2.h +++ b/source/platform/include/Gwork/Renderers/SDL2.h @@ -53,15 +53,15 @@ namespace Gwk void EndClip() override; void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, - float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/include/Gwork/Renderers/SFML2.h b/source/platform/include/Gwork/Renderers/SFML2.h index 0ab23651..fc973b2b 100644 --- a/source/platform/include/Gwork/Renderers/SFML2.h +++ b/source/platform/include/Gwork/Renderers/SFML2.h @@ -95,15 +95,15 @@ namespace Gwk void DrawShavedCornerRect(Gwk::Rect rect, bool bSlight = false) override; void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, - float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/include/Gwork/Renderers/Software.h b/source/platform/include/Gwork/Renderers/Software.h index c5fb61bc..6f1429dd 100644 --- a/source/platform/include/Gwork/Renderers/Software.h +++ b/source/platform/include/Gwork/Renderers/Software.h @@ -73,15 +73,15 @@ namespace Gwk void DrawPixel(int x, int y) override; void DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect targetRect, float u1 = 0.0f, - float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; + float v1 = 0.0f, float u2 = 1.0f, float v2 = 1.0f) override; Gwk::Color PixelColor(const Gwk::Texture& texture, - unsigned int x, unsigned int y, - const Gwk::Color& col_default) override; + unsigned int x, unsigned int y, + const Gwk::Color& col_default) override; void RenderText(const Gwk::Font& font, - Gwk::Point pos, - const Gwk::String& text) override; + Gwk::Point pos, + const Gwk::String& text) override; Gwk::Point MeasureText(const Gwk::Font& font, const Gwk::String& text) override; diff --git a/source/platform/renderers/OpenGLCore/OpenGLCore.cpp b/source/platform/renderers/OpenGLCore/OpenGLCore.cpp index 05cc1901..a3196d16 100644 --- a/source/platform/renderers/OpenGLCore/OpenGLCore.cpp +++ b/source/platform/renderers/OpenGLCore/OpenGLCore.cpp @@ -529,7 +529,7 @@ void OpenGLCore::DrawTexturedRect(const Gwk::Texture& texture, Gwk::Rect rect, } Gwk::Color OpenGLCore::PixelColor(const Gwk::Texture& texture, unsigned int x, unsigned int y, - const Gwk::Color& col_default) + const Gwk::Color& col_default) { if (!EnsureTexture(texture)) return col_default; @@ -555,7 +555,7 @@ Gwk::Color OpenGLCore::PixelColor(const Gwk::Texture& texture, unsigned int x, u } void OpenGLCore::RenderText(const Gwk::Font& font, Gwk::Point pos, - const Gwk::String& text) + const Gwk::String& text) { if (!EnsureFont(font)) return; From b833659d45667838750b4b060e80b00c145ec22b Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 10:47:13 -0400 Subject: [PATCH 4/6] Xcode version specific for thread_local --- source/platform/include/Gwork/Utility.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/platform/include/Gwork/Utility.h b/source/platform/include/Gwork/Utility.h index 0fccc8c8..d4d06d9c 100644 --- a/source/platform/include/Gwork/Utility.h +++ b/source/platform/include/Gwork/Utility.h @@ -87,7 +87,12 @@ namespace Gwk static inline wchar_t utf8_to_wchart(char*& in)// Gwk::Utility::Widen too slow { +#if defined(__clang__) && defined(__apple_build_version__) && __apple_build_version__ < 8 + // thread_local not supported on Xcode versions below 8 + static unsigned int next = 0x10000; +#else thread_local static unsigned int next = 0x10000; +#endif if (next != 0x10000) { wchar_t ret = static_cast(next); From 6a017cddde55def3b22f748db4f39f10a2eb3e26 Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 10:55:58 -0400 Subject: [PATCH 5/6] Fixed __apple_build_version__ bug --- source/platform/include/Gwork/Utility.h | 2 +- source/platform/renderers/SFML2/SFML2.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/platform/include/Gwork/Utility.h b/source/platform/include/Gwork/Utility.h index d4d06d9c..086df6c5 100644 --- a/source/platform/include/Gwork/Utility.h +++ b/source/platform/include/Gwork/Utility.h @@ -87,7 +87,7 @@ namespace Gwk static inline wchar_t utf8_to_wchart(char*& in)// Gwk::Utility::Widen too slow { -#if defined(__clang__) && defined(__apple_build_version__) && __apple_build_version__ < 8 +#if defined(__clang__) && defined(__apple_build_version__) && __apple_build_version__ >= 8 // thread_local not supported on Xcode versions below 8 static unsigned int next = 0x10000; #else diff --git a/source/platform/renderers/SFML2/SFML2.cpp b/source/platform/renderers/SFML2/SFML2.cpp index 580d24ba..0807c569 100644 --- a/source/platform/renderers/SFML2/SFML2.cpp +++ b/source/platform/renderers/SFML2/SFML2.cpp @@ -23,6 +23,11 @@ #endif #include +#if defined(__unix__) || \\ + defined(__linux__) || defined(__gnu__linux__) || \ + (defined (__APPLE__) && defined(__MACH__)) +#include +#endif using namespace Gwk; From b225ed4cbac441d84ce51de38ae740a1639a8757 Mon Sep 17 00:00:00 2001 From: Rashawn Clarke Date: Sat, 14 Jul 2018 11:55:39 -0400 Subject: [PATCH 6/6] Revert SWTextureData::At(int, int) functions --- source/platform/include/Gwork/Renderers/Software.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source/platform/include/Gwork/Renderers/Software.h b/source/platform/include/Gwork/Renderers/Software.h index 6f1429dd..9cb3dfa5 100644 --- a/source/platform/include/Gwork/Renderers/Software.h +++ b/source/platform/include/Gwork/Renderers/Software.h @@ -122,15 +122,13 @@ namespace Gwk Color& At(int x, int y) { - unsigned char* color_ptr = m_ReadData.get() + (y * 4 * static_cast(width) + x * 4); - return *reinterpret_cast(color_ptr); + return reinterpret_cast(m_ReadData.get())[y * static_cast(width) + x]; } Color& At(Point const& pt) { return At(pt.x, pt.y); } const Color& At(int x, int y) const { - unsigned char* color_ptr = m_ReadData.get() + (y * 4 * static_cast(width) + x * 4); - return *reinterpret_cast(color_ptr); + return reinterpret_cast(m_ReadData.get())[y * static_cast(width) + x]; } const Color& At(Point const& pt) const { return At(pt.x, pt.y); }