From cb100db56e4737c4594afa7712d412c1166e9ded Mon Sep 17 00:00:00 2001 From: Duncan Date: Thu, 7 Mar 2024 22:36:49 +0000 Subject: [PATCH] Put a number of OpenRCT2::Ui items in the OpenRCT2::Ui namespace --- src/openrct2-ui/SDLException.cpp | 2 + src/openrct2-ui/SDLException.h | 29 +- src/openrct2-ui/UiContext.h | 62 +-- src/openrct2-ui/audio/AudioContext.cpp | 2 +- src/openrct2-ui/drawing/BitmapReader.cpp | 139 +++--- src/openrct2-ui/drawing/BitmapReader.h | 5 +- .../drawing/engines/DrawingEngineFactory.hpp | 59 ++- .../engines/opengl/ApplyPaletteShader.cpp | 2 + .../engines/opengl/ApplyPaletteShader.h | 37 +- .../opengl/ApplyTransparencyShader.cpp | 2 + .../engines/opengl/ApplyTransparencyShader.h | 48 ++- .../drawing/engines/opengl/DrawCommands.h | 206 ++++----- .../drawing/engines/opengl/DrawLineShader.cpp | 2 + .../drawing/engines/opengl/DrawLineShader.h | 42 +- .../drawing/engines/opengl/DrawRectShader.cpp | 2 + .../drawing/engines/opengl/DrawRectShader.h | 74 ++-- .../drawing/engines/opengl/GLSLTypes.h | 162 +++---- .../drawing/engines/opengl/OpenGLAPI.cpp | 6 +- .../drawing/engines/opengl/OpenGLAPI.h | 37 +- .../engines/opengl/OpenGLFramebuffer.cpp | 2 + .../engines/opengl/OpenGLFramebuffer.h | 84 ++-- .../engines/opengl/OpenGLShaderProgram.cpp | 2 +- .../engines/opengl/OpenGLShaderProgram.h | 64 +-- .../engines/opengl/SwapFramebuffer.cpp | 2 + .../drawing/engines/opengl/SwapFramebuffer.h | 76 ++-- .../drawing/engines/opengl/TextureCache.cpp | 2 + .../drawing/engines/opengl/TextureCache.h | 403 +++++++++--------- .../engines/opengl/TransparencyDepth.cpp | 338 +++++++-------- .../engines/opengl/TransparencyDepth.h | 15 +- 29 files changed, 980 insertions(+), 926 deletions(-) diff --git a/src/openrct2-ui/SDLException.cpp b/src/openrct2-ui/SDLException.cpp index a358abcaa6..7623981ffc 100644 --- a/src/openrct2-ui/SDLException.cpp +++ b/src/openrct2-ui/SDLException.cpp @@ -11,6 +11,8 @@ #include +using namespace OpenRCT2::Ui; + SDLException::SDLException(const std::string& message) : runtime_error(message.c_str()) { diff --git a/src/openrct2-ui/SDLException.h b/src/openrct2-ui/SDLException.h index 6ba8aed36d..06f01d78cf 100644 --- a/src/openrct2-ui/SDLException.h +++ b/src/openrct2-ui/SDLException.h @@ -12,19 +12,22 @@ #include #include -/** - * An exception which wraps an SDL error. - */ -class SDLException : public std::runtime_error +namespace OpenRCT2::Ui { -public: - explicit SDLException(const std::string& message); - - explicit SDLException(const char* message); - /** - * Throws an SDL exception with a message containing the given call information - * and the message given by SDL_GetError. + * An exception which wraps an SDL error. */ - static void Throw(const char* call); -}; + class SDLException : public std::runtime_error + { + public: + explicit SDLException(const std::string& message); + + explicit SDLException(const char* message); + + /** + * Throws an SDL exception with a message containing the given call information + * and the message given by SDL_GetError. + */ + static void Throw(const char* call); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/UiContext.h b/src/openrct2-ui/UiContext.h index 37d4922701..a98ab7a900 100644 --- a/src/openrct2-ui/UiContext.h +++ b/src/openrct2-ui/UiContext.h @@ -20,35 +20,35 @@ namespace OpenRCT2 { struct IContext; struct IPlatformEnvironment; - - namespace Ui - { - struct FileDialogDesc; - class InGameConsole; - struct IUiContext; - - struct IPlatformUiContext - { - virtual ~IPlatformUiContext() = default; - virtual void SetWindowIcon(SDL_Window* window) abstract; - virtual bool IsSteamOverlayAttached() abstract; - - virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract; - virtual bool HasMenuSupport() abstract; - virtual int32_t ShowMenuDialog( - const std::vector& options, const std::string& title, const std::string& text) abstract; - virtual void OpenFolder(const std::string& path) abstract; - - virtual void OpenURL(const std::string& url) abstract; - virtual std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) abstract; - virtual std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) abstract; - - virtual bool HasFilePicker() const abstract; - }; - - [[nodiscard]] std::unique_ptr CreateUiContext(const std::shared_ptr& env); - [[nodiscard]] std::unique_ptr CreatePlatformUiContext(); - - [[nodiscard]] InGameConsole& GetInGameConsole(); - } // namespace Ui } // namespace OpenRCT2 + +namespace OpenRCT2::Ui +{ + struct FileDialogDesc; + class InGameConsole; + struct IUiContext; + + struct IPlatformUiContext + { + virtual ~IPlatformUiContext() = default; + virtual void SetWindowIcon(SDL_Window* window) abstract; + virtual bool IsSteamOverlayAttached() abstract; + + virtual void ShowMessageBox(SDL_Window* window, const std::string& message) abstract; + virtual bool HasMenuSupport() abstract; + virtual int32_t ShowMenuDialog( + const std::vector& options, const std::string& title, const std::string& text) abstract; + virtual void OpenFolder(const std::string& path) abstract; + + virtual void OpenURL(const std::string& url) abstract; + virtual std::string ShowFileDialog(SDL_Window* window, const FileDialogDesc& desc) abstract; + virtual std::string ShowDirectoryDialog(SDL_Window* window, const std::string& title) abstract; + + virtual bool HasFilePicker() const abstract; + }; + + [[nodiscard]] std::unique_ptr CreateUiContext(const std::shared_ptr& env); + [[nodiscard]] std::unique_ptr CreatePlatformUiContext(); + + [[nodiscard]] InGameConsole& GetInGameConsole(); +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/audio/AudioContext.cpp b/src/openrct2-ui/audio/AudioContext.cpp index 9fcb5e3926..829fffc754 100644 --- a/src/openrct2-ui/audio/AudioContext.cpp +++ b/src/openrct2-ui/audio/AudioContext.cpp @@ -34,7 +34,7 @@ namespace OpenRCT2::Audio { if (SDL_Init(SDL_INIT_AUDIO) < 0) { - SDLException::Throw("SDL_Init(SDL_INIT_AUDIO)"); + Ui::SDLException::Throw("SDL_Init(SDL_INIT_AUDIO)"); } _audioMixer = std::make_unique(); } diff --git a/src/openrct2-ui/drawing/BitmapReader.cpp b/src/openrct2-ui/drawing/BitmapReader.cpp index 185fba6fec..242d5b8fb6 100644 --- a/src/openrct2-ui/drawing/BitmapReader.cpp +++ b/src/openrct2-ui/drawing/BitmapReader.cpp @@ -15,90 +15,93 @@ #include #include -static std::vector ReadToVector(std::istream& stream) +namespace OpenRCT2::Ui { - std::vector result; - if (!stream.eof() && !stream.fail()) + static std::vector ReadToVector(std::istream& stream) { - stream.seekg(0, std::ios_base::end); - auto size = stream.tellg(); - result.resize(size); - stream.seekg(0, std::ios_base::beg); - stream.read(reinterpret_cast(result.data()), size); - } - return result; -} - -// TODO Bitmaps aren't very complicated to read so we should probably just write our -// own implementation in libopenrct2 and spare the AOT implementation registration. -static Image ReadBitmap(std::istream& istream, IMAGE_FORMAT format) -{ - auto buffer = ReadToVector(istream); - auto sdlStream = SDL_RWFromConstMem(buffer.data(), static_cast(buffer.size())); - auto bitmap = SDL_LoadBMP_RW(sdlStream, 1); - if (bitmap != nullptr) - { - auto numChannels = bitmap->format->BytesPerPixel; - if (numChannels < 3 || bitmap->format->BitsPerPixel < 24) + std::vector result; + if (!stream.eof() && !stream.fail()) { - SDL_FreeSurface(bitmap); - throw std::runtime_error("Only 24-bit bitmaps are supported."); + stream.seekg(0, std::ios_base::end); + auto size = stream.tellg(); + result.resize(size); + stream.seekg(0, std::ios_base::beg); + stream.read(reinterpret_cast(result.data()), size); } + return result; + } - // Copy pixels over, then discard the surface - if (SDL_LockSurface(bitmap) == 0) + // TODO Bitmaps aren't very complicated to read so we should probably just write our + // own implementation in libopenrct2 and spare the AOT implementation registration. + static Image ReadBitmap(std::istream& istream, IMAGE_FORMAT format) + { + auto buffer = ReadToVector(istream); + auto sdlStream = SDL_RWFromConstMem(buffer.data(), static_cast(buffer.size())); + auto bitmap = SDL_LoadBMP_RW(sdlStream, 1); + if (bitmap != nullptr) { - Image image; - image.Width = bitmap->w; - image.Height = bitmap->h; - image.Depth = 32; - image.Pixels.resize(bitmap->w * bitmap->h * 4); - image.Stride = bitmap->w * 4; - - // Clear image with 0xFF - std::fill(image.Pixels.begin(), image.Pixels.end(), 0xFF); - - // Copy pixels over - auto src = static_cast(bitmap->pixels); - auto dst = image.Pixels.data(); - if (numChannels == 4) + auto numChannels = bitmap->format->BytesPerPixel; + if (numChannels < 3 || bitmap->format->BitsPerPixel < 24) { - for (int32_t y = 0; y < bitmap->h; y++) - { - std::memcpy(dst, src, bitmap->w); - src += bitmap->pitch; - dst += bitmap->w; - } + SDL_FreeSurface(bitmap); + throw std::runtime_error("Only 24-bit bitmaps are supported."); } - else + + // Copy pixels over, then discard the surface + if (SDL_LockSurface(bitmap) == 0) { - for (int32_t y = 0; y < bitmap->h; y++) + Image image; + image.Width = bitmap->w; + image.Height = bitmap->h; + image.Depth = 32; + image.Pixels.resize(bitmap->w * bitmap->h * 4); + image.Stride = bitmap->w * 4; + + // Clear image with 0xFF + std::fill(image.Pixels.begin(), image.Pixels.end(), 0xFF); + + // Copy pixels over + auto src = static_cast(bitmap->pixels); + auto dst = image.Pixels.data(); + if (numChannels == 4) { - for (int32_t x = 0; x < bitmap->w; x++) + for (int32_t y = 0; y < bitmap->h; y++) { - std::memcpy(dst, src, 3); - src += 3; - dst += 4; + std::memcpy(dst, src, bitmap->w); + src += bitmap->pitch; + dst += bitmap->w; } - src += bitmap->pitch - (bitmap->w * 3); } + else + { + for (int32_t y = 0; y < bitmap->h; y++) + { + for (int32_t x = 0; x < bitmap->w; x++) + { + std::memcpy(dst, src, 3); + src += 3; + dst += 4; + } + src += bitmap->pitch - (bitmap->w * 3); + } + } + SDL_UnlockSurface(bitmap); + SDL_FreeSurface(bitmap); + + return image; } - SDL_UnlockSurface(bitmap); + SDL_FreeSurface(bitmap); - - return image; + throw std::runtime_error("Unable to lock surface."); + } + else + { + throw std::runtime_error(SDL_GetError()); } - - SDL_FreeSurface(bitmap); - throw std::runtime_error("Unable to lock surface."); } - else + + void RegisterBitmapReader() { - throw std::runtime_error(SDL_GetError()); + Imaging::SetReader(IMAGE_FORMAT::BITMAP, ReadBitmap); } -} - -void RegisterBitmapReader() -{ - Imaging::SetReader(IMAGE_FORMAT::BITMAP, ReadBitmap); -} +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/BitmapReader.h b/src/openrct2-ui/drawing/BitmapReader.h index 18d6adcf36..75ba243ad8 100644 --- a/src/openrct2-ui/drawing/BitmapReader.h +++ b/src/openrct2-ui/drawing/BitmapReader.h @@ -9,4 +9,7 @@ #pragma once -void RegisterBitmapReader(); +namespace OpenRCT2::Ui +{ + void RegisterBitmapReader(); +} diff --git a/src/openrct2-ui/drawing/engines/DrawingEngineFactory.hpp b/src/openrct2-ui/drawing/engines/DrawingEngineFactory.hpp index d535b8464b..f852816c87 100644 --- a/src/openrct2-ui/drawing/engines/DrawingEngineFactory.hpp +++ b/src/openrct2-ui/drawing/engines/DrawingEngineFactory.hpp @@ -13,41 +13,38 @@ #include #include -namespace OpenRCT2 +namespace OpenRCT2::Ui { - namespace Ui + struct IUiContext; + + [[nodiscard]] std::unique_ptr CreateSoftwareDrawingEngine( + const std::shared_ptr& uiContext); + [[nodiscard]] std::unique_ptr CreateHardwareDisplayDrawingEngine( + const std::shared_ptr& uiContext); +#ifndef DISABLE_OPENGL + [[nodiscard]] std::unique_ptr CreateOpenGLDrawingEngine( + const std::shared_ptr& uiContext); +#endif + + class DrawingEngineFactory final : public Drawing::IDrawingEngineFactory { - using namespace OpenRCT2::Drawing; - - struct IUiContext; - - [[nodiscard]] std::unique_ptr CreateSoftwareDrawingEngine(const std::shared_ptr& uiContext); - [[nodiscard]] std::unique_ptr CreateHardwareDisplayDrawingEngine( - const std::shared_ptr& uiContext); -#ifndef DISABLE_OPENGL - [[nodiscard]] std::unique_ptr CreateOpenGLDrawingEngine(const std::shared_ptr& uiContext); -#endif - - class DrawingEngineFactory final : public IDrawingEngineFactory + public: + [[nodiscard]] std::unique_ptr Create( + DrawingEngine type, const std::shared_ptr& uiContext) override { - public: - [[nodiscard]] std::unique_ptr Create( - DrawingEngine type, const std::shared_ptr& uiContext) override + switch (type) { - switch (type) - { - case DrawingEngine::Software: - return CreateSoftwareDrawingEngine(uiContext); - case DrawingEngine::SoftwareWithHardwareDisplay: - return CreateHardwareDisplayDrawingEngine(uiContext); + case DrawingEngine::Software: + return CreateSoftwareDrawingEngine(uiContext); + case DrawingEngine::SoftwareWithHardwareDisplay: + return CreateHardwareDisplayDrawingEngine(uiContext); #ifndef DISABLE_OPENGL - case DrawingEngine::OpenGL: - return CreateOpenGLDrawingEngine(uiContext); + case DrawingEngine::OpenGL: + return CreateOpenGLDrawingEngine(uiContext); #endif - default: - return nullptr; - } + default: + return nullptr; } - }; - } // namespace Ui -} // namespace OpenRCT2 + } + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.cpp b/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.cpp index fc75168840..bcd74090c7 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.cpp @@ -11,6 +11,8 @@ # include "ApplyPaletteShader.h" +using namespace OpenRCT2::Ui; + namespace { struct VDStruct diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.h b/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.h index c7c94e95b4..a05aea4219 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyPaletteShader.h @@ -12,27 +12,30 @@ #include "GLSLTypes.h" #include "OpenGLShaderProgram.h" -class ApplyPaletteShader final : public OpenGLShaderProgram +namespace OpenRCT2::Ui { -private: - GLuint uTexture; - GLuint uPalette; + class ApplyPaletteShader final : public OpenGLShaderProgram + { + private: + GLuint uTexture; + GLuint uPalette; - GLuint vPosition; - GLuint vTextureCoordinate; + GLuint vPosition; + GLuint vTextureCoordinate; - GLuint _vbo; - GLuint _vao; + GLuint _vbo; + GLuint _vao; -public: - ApplyPaletteShader(); - ~ApplyPaletteShader() override; + public: + ApplyPaletteShader(); + ~ApplyPaletteShader() override; - static void SetTexture(GLuint texture); - void SetPalette(const vec4* glPalette); + static void SetTexture(GLuint texture); + void SetPalette(const vec4* glPalette); - void Draw(); + void Draw(); -private: - void GetLocations(); -}; + private: + void GetLocations(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp index 86451d6917..7bbb1f2f4b 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp @@ -11,6 +11,8 @@ # include "ApplyTransparencyShader.h" +using namespace OpenRCT2::Ui; + namespace { struct VDStruct diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h index 9ef4305460..430ed3903c 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h @@ -11,32 +11,34 @@ #include "GLSLTypes.h" #include "OpenGLShaderProgram.h" - -class ApplyTransparencyShader final : public OpenGLShaderProgram +namespace OpenRCT2::Ui { -private: - GLuint uOpaqueTex; - GLuint uOpaqueDepth; - GLuint uTransparentTex; - GLuint uTransparentDepth; - GLuint uPaletteTex; - GLuint uBlendPaletteTex; + class ApplyTransparencyShader final : public OpenGLShaderProgram + { + private: + GLuint uOpaqueTex; + GLuint uOpaqueDepth; + GLuint uTransparentTex; + GLuint uTransparentDepth; + GLuint uPaletteTex; + GLuint uBlendPaletteTex; - GLuint vPosition; - GLuint vTextureCoordinate; + GLuint vPosition; + GLuint vTextureCoordinate; - GLuint _vbo; - GLuint _vao; + GLuint _vbo; + GLuint _vao; -public: - ApplyTransparencyShader(); - ~ApplyTransparencyShader() override; + public: + ApplyTransparencyShader(); + ~ApplyTransparencyShader() override; - static void SetTextures( - GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex, - GLuint blendPaletteTex); - void Draw(); + static void SetTextures( + GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex, + GLuint blendPaletteTex); + void Draw(); -private: - void GetLocations(); -}; + private: + void GetLocations(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h index d343938eef..e53baea7d3 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h @@ -15,114 +15,116 @@ #include #include - -template class CommandBatch +namespace OpenRCT2::Ui { -private: - std::vector _instances; - size_t _numInstances; + template class CommandBatch + { + private: + std::vector _instances; + size_t _numInstances; -public: - CommandBatch() - : _numInstances(0) - { - } - - [[nodiscard]] bool empty() const // NOLINT(readability-identifier-naming) - { - return _numInstances == 0; - } - void clear() // NOLINT(readability-identifier-naming) - { - _numInstances = 0; - } - T& allocate() // NOLINT(readability-identifier-naming) - { - if (_numInstances + 1 > _instances.size()) + public: + CommandBatch() + : _numInstances(0) { - _instances.resize((_numInstances + 1) << 1); } - return _instances[_numInstances++]; - } - T& insert(const T& value) // NOLINT(readability-identifier-naming) - { - if (_numInstances + 1 > _instances.size()) + + [[nodiscard]] bool empty() const // NOLINT(readability-identifier-naming) { - _instances.resize((_numInstances + 1) << 1); + return _numInstances == 0; + } + void clear() // NOLINT(readability-identifier-naming) + { + _numInstances = 0; + } + T& allocate() // NOLINT(readability-identifier-naming) + { + if (_numInstances + 1 > _instances.size()) + { + _instances.resize((_numInstances + 1) << 1); + } + return _instances[_numInstances++]; + } + T& insert(const T& value) // NOLINT(readability-identifier-naming) + { + if (_numInstances + 1 > _instances.size()) + { + _instances.resize((_numInstances + 1) << 1); + } + return _instances[_numInstances++] = value; + } + [[nodiscard]] size_t size() const // NOLINT(readability-identifier-naming) + { + return _numInstances; + } + const T* data() const // NOLINT(readability-identifier-naming) + { + return _instances.data(); + } + const T& operator[](size_t idx) const + { + return _instances.at(idx); } - return _instances[_numInstances++] = value; - } - [[nodiscard]] size_t size() const // NOLINT(readability-identifier-naming) - { - return _numInstances; - } - const T* data() const // NOLINT(readability-identifier-naming) - { - return _instances.data(); - } - const T& operator[](size_t idx) const - { - return _instances.at(idx); - } - typename std::vector::iterator begin() // NOLINT(readability-identifier-naming) - { - return _instances.begin(); - } - typename std::vector::const_iterator begin() const // NOLINT(readability-identifier-naming) - { - return _instances.cbegin(); - } - typename std::vector::const_iterator cbegin() const // NOLINT(readability-identifier-naming) - { - return _instances.cbegin(); - } - typename std::vector::iterator end() // NOLINT(readability-identifier-naming) - { - return _instances.begin() + _numInstances; - } - typename std::vector::const_iterator end() const // NOLINT(readability-identifier-naming) - { - return _instances.cbegin() + _numInstances; - } - typename std::vector::const_iterator cend() const // NOLINT(readability-identifier-naming) - { - return _instances.cbegin() + _numInstances; - } -}; - -struct DrawLineCommand -{ - ivec4 clip; - ivec4 bounds; - GLuint colour; - GLint depth; -}; - -// Per-instance data for images -struct DrawRectCommand -{ - ivec4 clip; - GLint texColourAtlas; - vec4 texColourBounds; - GLint texMaskAtlas; - vec4 texMaskBounds; - ivec3 palettes; - GLint flags; - GLuint colour; - ivec4 bounds; - GLint depth; - - enum - { - FLAG_NO_TEXTURE = (1u << 2u), - FLAG_MASK = (1u << 3u), - FLAG_CROSS_HATCH = (1u << 4u), - FLAG_TTF_TEXT = (1u << 5u), - // bits 8 to 16 used to store hinting threshold. - FLAG_TTF_HINTING_THRESHOLD_MASK = 0xff00 + typename std::vector::iterator begin() // NOLINT(readability-identifier-naming) + { + return _instances.begin(); + } + typename std::vector::const_iterator begin() const // NOLINT(readability-identifier-naming) + { + return _instances.cbegin(); + } + typename std::vector::const_iterator cbegin() const // NOLINT(readability-identifier-naming) + { + return _instances.cbegin(); + } + typename std::vector::iterator end() // NOLINT(readability-identifier-naming) + { + return _instances.begin() + _numInstances; + } + typename std::vector::const_iterator end() const // NOLINT(readability-identifier-naming) + { + return _instances.cbegin() + _numInstances; + } + typename std::vector::const_iterator cend() const // NOLINT(readability-identifier-naming) + { + return _instances.cbegin() + _numInstances; + } }; -}; -using LineCommandBatch = CommandBatch; -using RectCommandBatch = CommandBatch; + struct DrawLineCommand + { + ivec4 clip; + ivec4 bounds; + GLuint colour; + GLint depth; + }; + + // Per-instance data for images + struct DrawRectCommand + { + ivec4 clip; + GLint texColourAtlas; + vec4 texColourBounds; + GLint texMaskAtlas; + vec4 texMaskBounds; + ivec3 palettes; + GLint flags; + GLuint colour; + ivec4 bounds; + GLint depth; + + enum + { + FLAG_NO_TEXTURE = (1u << 2u), + FLAG_MASK = (1u << 3u), + FLAG_CROSS_HATCH = (1u << 4u), + FLAG_TTF_TEXT = (1u << 5u), + // bits 8 to 16 used to store hinting threshold. + FLAG_TTF_HINTING_THRESHOLD_MASK = 0xff00 + }; + }; + + using LineCommandBatch = CommandBatch; + using RectCommandBatch = CommandBatch; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.cpp b/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.cpp index c5f81310de..2b687d764e 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.cpp @@ -13,6 +13,8 @@ # include "OpenGLFramebuffer.h" +using namespace OpenRCT2::Ui; + namespace { struct VDStruct diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.h b/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.h index 6ddaa94b53..0150b1ad7a 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawLineShader.h @@ -12,30 +12,32 @@ #include "DrawCommands.h" #include "GLSLTypes.h" #include "OpenGLShaderProgram.h" - -class DrawLineShader final : public OpenGLShaderProgram +namespace OpenRCT2::Ui { -private: - GLuint uScreenSize; + class DrawLineShader final : public OpenGLShaderProgram + { + private: + GLuint uScreenSize; - GLuint vClip; - GLuint vBounds; - GLuint vColour; - GLuint vDepth; + GLuint vClip; + GLuint vBounds; + GLuint vColour; + GLuint vDepth; - GLuint vVertMat; + GLuint vVertMat; - GLuint _vbo; - GLuint _vboInstances; - GLuint _vao; + GLuint _vbo; + GLuint _vboInstances; + GLuint _vao; -public: - DrawLineShader(); - ~DrawLineShader() override; + public: + DrawLineShader(); + ~DrawLineShader() override; - void SetScreenSize(int32_t width, int32_t height); - void DrawInstances(const LineCommandBatch& instances); + void SetScreenSize(int32_t width, int32_t height); + void DrawInstances(const LineCommandBatch& instances); -private: - void GetLocations(); -}; + private: + void GetLocations(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp index 5b760f7da5..ed43dddb34 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.cpp @@ -11,6 +11,8 @@ # include "DrawRectShader.h" +using namespace OpenRCT2::Ui; + namespace { struct VDStruct diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h index 76a8a83335..bf4dd07668 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawRectShader.h @@ -14,49 +14,51 @@ #include "OpenGLShaderProgram.h" #include - -class DrawRectShader final : public OpenGLShaderProgram +namespace OpenRCT2::Ui { -private: - GLuint uScreenSize; - GLuint uTexture; - GLuint uPaletteTex; + class DrawRectShader final : public OpenGLShaderProgram + { + private: + GLuint uScreenSize; + GLuint uTexture; + GLuint uPaletteTex; - GLuint uPeelingTex; - GLuint uPeeling; + GLuint uPeelingTex; + GLuint uPeeling; - GLuint vVertMat; - GLuint vVertVec; + GLuint vVertMat; + GLuint vVertVec; - GLuint vClip; - GLuint vTexColourAtlas; - GLuint vTexColourBounds; - GLuint vTexMaskAtlas; - GLuint vTexMaskBounds; - GLuint vPalettes; - GLuint vFlags; - GLuint vColour; - GLuint vBounds; - GLuint vDepth; + GLuint vClip; + GLuint vTexColourAtlas; + GLuint vTexColourBounds; + GLuint vTexMaskAtlas; + GLuint vTexMaskBounds; + GLuint vPalettes; + GLuint vFlags; + GLuint vColour; + GLuint vBounds; + GLuint vDepth; - GLuint _vbo; - GLuint _vboInstances; - GLuint _vao; + GLuint _vbo; + GLuint _vboInstances; + GLuint _vao; - GLsizei _instanceCount = 0; - size_t _maxInstancesBufferSize; + GLsizei _instanceCount = 0; + size_t _maxInstancesBufferSize; -public: - DrawRectShader(); - ~DrawRectShader() override; + public: + DrawRectShader(); + ~DrawRectShader() override; - void SetScreenSize(int32_t width, int32_t height); - void EnablePeeling(GLuint peelingTex); - void DisablePeeling(); + void SetScreenSize(int32_t width, int32_t height); + void EnablePeeling(GLuint peelingTex); + void DisablePeeling(); - void SetInstances(const RectCommandBatch& instances); - void DrawInstances(); + void SetInstances(const RectCommandBatch& instances); + void DrawInstances(); -private: - void GetLocations(); -}; + private: + void GetLocations(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/GLSLTypes.h b/src/openrct2-ui/drawing/engines/opengl/GLSLTypes.h index 96dba238c8..624c295550 100644 --- a/src/openrct2-ui/drawing/engines/opengl/GLSLTypes.h +++ b/src/openrct2-ui/drawing/engines/opengl/GLSLTypes.h @@ -13,100 +13,102 @@ #include -#pragma pack(push, 1) - -namespace detail +namespace OpenRCT2::Ui { - template struct Vec2 +#pragma pack(push, 1) + namespace detail { - using ValueType = T_; - - union + template struct Vec2 { - ValueType x; - ValueType s; - ValueType r; + using ValueType = T_; + + union + { + ValueType x; + ValueType s; + ValueType r; + }; + union + { + ValueType y; + ValueType t; + ValueType g; + }; }; - union + + template struct Vec2; + template struct Vec2; + + template struct Vec3 { - ValueType y; - ValueType t; - ValueType g; + using ValueType = T_; + + union + { + ValueType x; + ValueType s; + ValueType r; + }; + union + { + ValueType y; + ValueType t; + ValueType g; + }; + union + { + ValueType z; + ValueType p; + ValueType b; + }; }; - }; - template struct Vec2; - template struct Vec2; + template struct Vec3; + template struct Vec3; - template struct Vec3 - { - using ValueType = T_; - - union + template struct Vec4 { - ValueType x; - ValueType s; - ValueType r; + using ValueType = T_; + + union + { + ValueType x; + ValueType s; + ValueType r; + }; + union + { + ValueType y; + ValueType t; + ValueType g; + }; + union + { + ValueType z; + ValueType p; + ValueType b; + }; + union + { + ValueType w; + ValueType q; + ValueType a; + }; }; - union - { - ValueType y; - ValueType t; - ValueType g; - }; - union - { - ValueType z; - ValueType p; - ValueType b; - }; - }; - template struct Vec3; - template struct Vec3; + template struct Vec4; + template struct Vec4; - template struct Vec4 - { - using ValueType = T_; + } // namespace detail - union - { - ValueType x; - ValueType s; - ValueType r; - }; - union - { - ValueType y; - ValueType t; - ValueType g; - }; - union - { - ValueType z; - ValueType p; - ValueType b; - }; - union - { - ValueType w; - ValueType q; - ValueType a; - }; - }; + using vec2 = detail::Vec2; + using ivec2 = detail::Vec2; - template struct Vec4; - template struct Vec4; + using vec3 = detail::Vec3; + using ivec3 = detail::Vec3; -} // namespace detail - -using vec2 = detail::Vec2; -using ivec2 = detail::Vec2; - -using vec3 = detail::Vec3; -using ivec3 = detail::Vec3; - -using vec4 = detail::Vec4; -using ivec4 = detail::Vec4; + using vec4 = detail::Vec4; + using ivec4 = detail::Vec4; #pragma pack(pop) +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.cpp index 7e074e29cb..d54f1c70cc 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.cpp @@ -38,7 +38,9 @@ static const char* TryLoadAllProcAddresses() # endif /* #if OPENGL_NO_LINK */ -namespace OpenGLState +using namespace OpenRCT2::Ui; + +namespace OpenRCT2::Ui::OpenGLState { uint16_t ActiveTexture; GLuint CurrentProgram; @@ -48,7 +50,7 @@ namespace OpenGLState ActiveTexture = UINT16_MAX; CurrentProgram = UINT32_MAX; } -} // namespace OpenGLState +} // namespace OpenRCT2::Ui::OpenGLState void OpenGLAPI::SetTexture(uint16_t index, GLenum type, GLuint texture) { diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h index 86e3c1be12..8791fb6567 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLAPI.h @@ -113,26 +113,29 @@ using PFNGLGETTEXIMAGEPROC = void(APIENTRYP)(GLenum target, GLint level, GLenum #endif /* OPENGL_NO_LINK */ -inline void CheckGLError() +namespace OpenRCT2::Ui { - GLenum error = glGetError(); - while (error != GL_NO_ERROR) + inline void CheckGLError() { - LOG_ERROR("OpenGL Error 0x%04X", error); - error = glGetError(); + GLenum error = glGetError(); + while (error != GL_NO_ERROR) + { + LOG_ERROR("OpenGL Error 0x%04X", error); + error = glGetError(); + } } -} -namespace OpenGLAPI -{ - bool Initialise(); - void SetTexture(uint16_t index, GLenum type, GLuint texture); -} // namespace OpenGLAPI + namespace OpenGLAPI + { + bool Initialise(); + void SetTexture(uint16_t index, GLenum type, GLuint texture); + } // namespace OpenGLAPI -namespace OpenGLState -{ - extern uint16_t ActiveTexture; - extern GLuint CurrentProgram; + namespace OpenGLState + { + extern uint16_t ActiveTexture; + extern GLuint CurrentProgram; - void Reset(); -} // namespace OpenGLState + void Reset(); + } // namespace OpenGLState +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp index 70771ef501..f1845cbdfa 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp @@ -16,6 +16,8 @@ # include # include +using namespace OpenRCT2::Ui; + constexpr GLuint BACKBUFFER_ID = 0; OpenGLFramebuffer::OpenGLFramebuffer(SDL_Window* window) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h index c13971fbc4..6999f997d9 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h @@ -16,49 +16,51 @@ #include struct SDL_Window; - -class OpenGLFramebuffer +namespace OpenRCT2::Ui { -private: - GLuint _id; - GLuint _texture; - GLuint _depth; - int32_t _width; - int32_t _height; - -public: - explicit OpenGLFramebuffer(SDL_Window* window); - OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true, bool word = false); - ~OpenGLFramebuffer(); - - OpenGLFramebuffer(const OpenGLFramebuffer&) = delete; - OpenGLFramebuffer& operator=(const OpenGLFramebuffer&) = delete; - - GLuint GetWidth() const + class OpenGLFramebuffer { - return _width; - } - GLuint GetHeight() const - { - return _height; - } - GLuint GetTexture() const - { - return _texture; - } - GLuint GetDepthTexture() const - { - return _depth; - } + private: + GLuint _id; + GLuint _texture; + GLuint _depth; + int32_t _width; + int32_t _height; - void Bind() const; - void BindDraw() const; - void BindRead() const; - void GetPixels(DrawPixelInfo& dpi) const; + public: + explicit OpenGLFramebuffer(SDL_Window* window); + OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true, bool word = false); + ~OpenGLFramebuffer(); - void SwapColourBuffer(OpenGLFramebuffer& other); - GLuint SwapDepthTexture(GLuint depth); - void Copy(OpenGLFramebuffer& src, GLenum filter); + OpenGLFramebuffer(const OpenGLFramebuffer&) = delete; + OpenGLFramebuffer& operator=(const OpenGLFramebuffer&) = delete; - static GLuint CreateDepthTexture(int32_t width, int32_t height); -}; + GLuint GetWidth() const + { + return _width; + } + GLuint GetHeight() const + { + return _height; + } + GLuint GetTexture() const + { + return _texture; + } + GLuint GetDepthTexture() const + { + return _depth; + } + + void Bind() const; + void BindDraw() const; + void BindRead() const; + void GetPixels(DrawPixelInfo& dpi) const; + + void SwapColourBuffer(OpenGLFramebuffer& other); + GLuint SwapDepthTexture(GLuint depth); + void Copy(OpenGLFramebuffer& src, GLenum filter); + + static GLuint CreateDepthTexture(int32_t width, int32_t height); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.cpp index 8647c110f3..7e9278087d 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.cpp @@ -18,7 +18,7 @@ # include # include -using namespace OpenRCT2; +using namespace OpenRCT2::Ui; OpenGLShader::OpenGLShader(const char* name, GLenum type) : _type(type) diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.h index 1cded5b523..141276f7cc 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLShaderProgram.h @@ -14,43 +14,45 @@ #include #include #include - -class OpenGLShader final +namespace OpenRCT2::Ui { -private: - static constexpr uint64_t MaxSourceSize = 8 * 1024 * 1024; // 8 MiB + class OpenGLShader final + { + private: + static constexpr uint64_t MaxSourceSize = 8 * 1024 * 1024; // 8 MiB - GLenum _type; - GLuint _id = 0; + GLenum _type; + GLuint _id = 0; -public: - OpenGLShader(const char* name, GLenum type); - ~OpenGLShader(); + public: + OpenGLShader(const char* name, GLenum type); + ~OpenGLShader(); - GLuint GetShaderId(); + GLuint GetShaderId(); -private: - std::string GetPath(const std::string& name); - static std::string ReadSourceCode(const std::string& path); -}; + private: + std::string GetPath(const std::string& name); + static std::string ReadSourceCode(const std::string& path); + }; -class OpenGLShaderProgram -{ -private: - GLuint _id = 0; - std::unique_ptr _vertexShader; - std::unique_ptr _fragmentShader; + class OpenGLShaderProgram + { + private: + GLuint _id = 0; + std::unique_ptr _vertexShader; + std::unique_ptr _fragmentShader; -public: - explicit OpenGLShaderProgram(const char* name); - explicit OpenGLShaderProgram(const OpenGLShaderProgram&) = delete; - explicit OpenGLShaderProgram(OpenGLShaderProgram&&) = default; - virtual ~OpenGLShaderProgram(); + public: + explicit OpenGLShaderProgram(const char* name); + explicit OpenGLShaderProgram(const OpenGLShaderProgram&) = delete; + explicit OpenGLShaderProgram(OpenGLShaderProgram&&) = default; + virtual ~OpenGLShaderProgram(); - GLuint GetAttributeLocation(const char* name); - GLuint GetUniformLocation(const char* name); - void Use(); + GLuint GetAttributeLocation(const char* name); + GLuint GetUniformLocation(const char* name); + void Use(); -private: - bool Link(); -}; + private: + bool Link(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp index bdccec25c5..cf44c003b5 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp @@ -13,6 +13,8 @@ # include "OpenGLFramebuffer.h" +using namespace OpenRCT2::Ui; + constexpr GLfloat depthValue[1] = { 1.0f }; constexpr GLfloat depthValueTransparent[1] = { 0.0f }; constexpr GLuint indexValue[4] = { 0, 0, 0, 0 }; diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h index c13d5fb5a9..cfc23ded77 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h @@ -14,44 +14,46 @@ #include "OpenGLFramebuffer.h" #include - -/** - * Class to maintain two different framebuffers where the active framebuffer - * will swap between the two, copying the other's pixels in the process for - * performing pre-processing filters. - * - * When you need to bind the current frame to a shader, call SwapCopy and - * then bind the value of GetSourceTexture to your shader. - */ -class SwapFramebuffer final +namespace OpenRCT2::Ui { -private: - OpenGLFramebuffer _opaqueFramebuffer; - OpenGLFramebuffer _transparentFramebuffer; - OpenGLFramebuffer _mixFramebuffer; - GLuint _backDepth; + /** + * Class to maintain two different framebuffers where the active framebuffer + * will swap between the two, copying the other's pixels in the process for + * performing pre-processing filters. + * + * When you need to bind the current frame to a shader, call SwapCopy and + * then bind the value of GetSourceTexture to your shader. + */ + class SwapFramebuffer final + { + private: + OpenGLFramebuffer _opaqueFramebuffer; + OpenGLFramebuffer _transparentFramebuffer; + OpenGLFramebuffer _mixFramebuffer; + GLuint _backDepth; -public: - SwapFramebuffer(int32_t width, int32_t height); - ~SwapFramebuffer(); + public: + SwapFramebuffer(int32_t width, int32_t height); + ~SwapFramebuffer(); - const OpenGLFramebuffer& GetFinalFramebuffer() const - { - return _opaqueFramebuffer; - } - GLuint GetBackDepthTexture() const - { - return _backDepth; - } - void BindOpaque() - { - _opaqueFramebuffer.Bind(); - } - void BindTransparent() - { - _transparentFramebuffer.Bind(); - } + const OpenGLFramebuffer& GetFinalFramebuffer() const + { + return _opaqueFramebuffer; + } + GLuint GetBackDepthTexture() const + { + return _backDepth; + } + void BindOpaque() + { + _opaqueFramebuffer.Bind(); + } + void BindTransparent() + { + _transparentFramebuffer.Bind(); + } - void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex); - void Clear(); -}; + void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex); + void Clear(); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp index c66173d30e..bbfad0be1e 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp @@ -19,6 +19,8 @@ # include # include +using namespace OpenRCT2::Ui; + constexpr uint32_t UNUSED_INDEX = 0xFFFFFFFF; TextureCache::TextureCache() diff --git a/src/openrct2-ui/drawing/engines/opengl/TextureCache.h b/src/openrct2-ui/drawing/engines/opengl/TextureCache.h index da3df3d33b..097e4f98b9 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TextureCache.h +++ b/src/openrct2-ui/drawing/engines/opengl/TextureCache.h @@ -29,220 +29,223 @@ struct DrawPixelInfo; struct PaletteMap; enum class FilterPaletteID : int32_t; -struct GlyphId +namespace OpenRCT2::Ui { - ImageIndex Image; - uint64_t Palette; - - struct Hash + struct GlyphId { - size_t operator()(const GlyphId& k) const + ImageIndex Image; + uint64_t Palette; + + struct Hash { - size_t hash = k.Image * 7; - hash += (k.Palette & 0xFFFFFFFFUL) * 13; - hash += (k.Palette >> 32uL) * 23; - return hash; + size_t operator()(const GlyphId& k) const + { + size_t hash = k.Image * 7; + hash += (k.Palette & 0xFFFFFFFFUL) * 13; + hash += (k.Palette >> 32uL) * 23; + return hash; + } + }; + + struct Equal + { + bool operator()(const GlyphId& lhs, const GlyphId& rhs) const + { + return lhs.Image == rhs.Image && lhs.Palette == rhs.Palette; + } + }; + }; + + // This is the maximum width and height of each atlas, basically the + // granularity at which new atlases are allocated (2048 -> 4 MB of VRAM) + constexpr int32_t TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; + + // Pixel dimensions of smallest supported slots in texture atlases + // Must be a power of 2! + constexpr int32_t TEXTURE_CACHE_SMALLEST_SLOT = 32; + + struct BasicTextureInfo + { + GLuint index; + vec4 normalizedBounds; + }; + + // Location of an image (texture atlas index, slot and normalized coordinates) + struct AtlasTextureInfo : public BasicTextureInfo + { + GLuint slot; + ivec4 bounds; + ImageIndex image; + }; + + // Represents a texture atlas that images of a given maximum size can be allocated from + // Atlases are all stored in the same 2D texture array, occupying the specified index + // Slots in atlases are always squares. + class Atlas final + { + private: + GLuint _index = 0; + int32_t _imageSize = 0; + int32_t _atlasWidth = 0; + int32_t _atlasHeight = 0; + std::vector _freeSlots; + + int32_t _cols = 0; + int32_t _rows = 0; + + public: + Atlas(GLuint index, int32_t imageSize) + : _index(index) + , _imageSize(imageSize) + { + } + + void Initialise(int32_t atlasWidth, int32_t atlasHeight) + { + _atlasWidth = atlasWidth; + _atlasHeight = atlasHeight; + + _cols = std::max(1, _atlasWidth / _imageSize); + _rows = std::max(1, _atlasHeight / _imageSize); + + _freeSlots.resize(_cols * _rows); + for (size_t i = 0; i < _freeSlots.size(); i++) + { + _freeSlots[i] = static_cast(i); + } + } + + AtlasTextureInfo Allocate(int32_t actualWidth, int32_t actualHeight) + { + assert(!_freeSlots.empty()); + + GLuint slot = _freeSlots.back(); + _freeSlots.pop_back(); + + auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight); + + AtlasTextureInfo info{}; + info.index = _index; + info.slot = slot; + info.bounds = bounds; + info.normalizedBounds = NormalizeCoordinates(bounds); + + return info; + } + + void Free(const AtlasTextureInfo& info) + { + assert(_index == info.index); + + _freeSlots.push_back(info.slot); + } + + // Checks if specified image would be tightly packed in this atlas + // by checking if it is within the right power of 2 range + [[nodiscard]] bool IsImageSuitable(int32_t actualWidth, int32_t actualHeight) const + { + int32_t imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight); + int32_t atlasOrder = log2(_imageSize); + + return imageOrder == atlasOrder; + } + + [[nodiscard]] int32_t GetFreeSlots() const + { + return static_cast(_freeSlots.size()); + } + + static int32_t CalculateImageSizeOrder(int32_t actualWidth, int32_t actualHeight) + { + int32_t actualSize = std::max(actualWidth, actualHeight); + + if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT) + { + actualSize = TEXTURE_CACHE_SMALLEST_SLOT; + } + + return static_cast(ceil(log2f(static_cast(actualSize)))); + } + + private: + [[nodiscard]] ivec4 GetSlotCoordinates(GLuint slot, int32_t actualWidth, int32_t actualHeight) const + { + int32_t row = slot / _cols; + int32_t col = slot % _cols; + + return ivec4{ + _imageSize * col, + _imageSize * row, + _imageSize * col + actualWidth, + _imageSize * row + actualHeight, + }; + } + + [[nodiscard]] vec4 NormalizeCoordinates(const ivec4& coords) const + { + return vec4{ + coords.x / static_cast(_atlasWidth), + coords.y / static_cast(_atlasHeight), + coords.z / static_cast(_atlasWidth), + coords.w / static_cast(_atlasHeight), + }; } }; - struct Equal + class TextureCache final { - bool operator()(const GlyphId& lhs, const GlyphId& rhs) const - { - return lhs.Image == rhs.Image && lhs.Palette == rhs.Palette; - } - }; -}; + private: + bool _initialized = false; -// This is the maximum width and height of each atlas, basically the -// granularity at which new atlases are allocated (2048 -> 4 MB of VRAM) -constexpr int32_t TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; + GLuint _atlasesTexture = 0; + GLint _atlasesTextureDimensions = 0; + GLuint _atlasesTextureCapacity = 0; + GLuint _atlasesTextureIndices = 0; + GLint _atlasesTextureIndicesLimit = 0; + std::vector _atlases; + std::unordered_map _glyphTextureMap; + std::vector _textureCache; + std::array _indexMap; -// Pixel dimensions of smallest supported slots in texture atlases -// Must be a power of 2! -constexpr int32_t TEXTURE_CACHE_SMALLEST_SLOT = 32; - -struct BasicTextureInfo -{ - GLuint index; - vec4 normalizedBounds; -}; - -// Location of an image (texture atlas index, slot and normalized coordinates) -struct AtlasTextureInfo : public BasicTextureInfo -{ - GLuint slot; - ivec4 bounds; - ImageIndex image; -}; - -// Represents a texture atlas that images of a given maximum size can be allocated from -// Atlases are all stored in the same 2D texture array, occupying the specified index -// Slots in atlases are always squares. -class Atlas final -{ -private: - GLuint _index = 0; - int32_t _imageSize = 0; - int32_t _atlasWidth = 0; - int32_t _atlasHeight = 0; - std::vector _freeSlots; - - int32_t _cols = 0; - int32_t _rows = 0; - -public: - Atlas(GLuint index, int32_t imageSize) - : _index(index) - , _imageSize(imageSize) - { - } - - void Initialise(int32_t atlasWidth, int32_t atlasHeight) - { - _atlasWidth = atlasWidth; - _atlasHeight = atlasHeight; - - _cols = std::max(1, _atlasWidth / _imageSize); - _rows = std::max(1, _atlasHeight / _imageSize); - - _freeSlots.resize(_cols * _rows); - for (size_t i = 0; i < _freeSlots.size(); i++) - { - _freeSlots[i] = static_cast(i); - } - } - - AtlasTextureInfo Allocate(int32_t actualWidth, int32_t actualHeight) - { - assert(!_freeSlots.empty()); - - GLuint slot = _freeSlots.back(); - _freeSlots.pop_back(); - - auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight); - - AtlasTextureInfo info{}; - info.index = _index; - info.slot = slot; - info.bounds = bounds; - info.normalizedBounds = NormalizeCoordinates(bounds); - - return info; - } - - void Free(const AtlasTextureInfo& info) - { - assert(_index == info.index); - - _freeSlots.push_back(info.slot); - } - - // Checks if specified image would be tightly packed in this atlas - // by checking if it is within the right power of 2 range - [[nodiscard]] bool IsImageSuitable(int32_t actualWidth, int32_t actualHeight) const - { - int32_t imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight); - int32_t atlasOrder = log2(_imageSize); - - return imageOrder == atlasOrder; - } - - [[nodiscard]] int32_t GetFreeSlots() const - { - return static_cast(_freeSlots.size()); - } - - static int32_t CalculateImageSizeOrder(int32_t actualWidth, int32_t actualHeight) - { - int32_t actualSize = std::max(actualWidth, actualHeight); - - if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT) - { - actualSize = TEXTURE_CACHE_SMALLEST_SLOT; - } - - return static_cast(ceil(log2f(static_cast(actualSize)))); - } - -private: - [[nodiscard]] ivec4 GetSlotCoordinates(GLuint slot, int32_t actualWidth, int32_t actualHeight) const - { - int32_t row = slot / _cols; - int32_t col = slot % _cols; - - return ivec4{ - _imageSize * col, - _imageSize * row, - _imageSize * col + actualWidth, - _imageSize * row + actualHeight, - }; - } - - [[nodiscard]] vec4 NormalizeCoordinates(const ivec4& coords) const - { - return vec4{ - coords.x / static_cast(_atlasWidth), - coords.y / static_cast(_atlasHeight), - coords.z / static_cast(_atlasWidth), - coords.w / static_cast(_atlasHeight), - }; - } -}; - -class TextureCache final -{ -private: - bool _initialized = false; - - GLuint _atlasesTexture = 0; - GLint _atlasesTextureDimensions = 0; - GLuint _atlasesTextureCapacity = 0; - GLuint _atlasesTextureIndices = 0; - GLint _atlasesTextureIndicesLimit = 0; - std::vector _atlases; - std::unordered_map _glyphTextureMap; - std::vector _textureCache; - std::array _indexMap; - - GLuint _paletteTexture = 0; - GLuint _blendPaletteTexture = 0; + GLuint _paletteTexture = 0; + GLuint _blendPaletteTexture = 0; #ifndef __MACOSX__ - std::shared_mutex _mutex; - using shared_lock = std::shared_lock; - using unique_lock = std::unique_lock; + std::shared_mutex _mutex; + using shared_lock = std::shared_lock; + using unique_lock = std::unique_lock; #else - std::mutex _mutex; - using shared_lock = std::unique_lock; - using unique_lock = std::unique_lock; + std::mutex _mutex; + using shared_lock = std::unique_lock; + using unique_lock = std::unique_lock; #endif -public: - TextureCache(); - ~TextureCache(); - void InvalidateImage(ImageIndex image); - BasicTextureInfo GetOrLoadImageTexture(const ImageId imageId); - BasicTextureInfo GetOrLoadGlyphTexture(const ImageId imageId, const PaletteMap& paletteMap); - BasicTextureInfo GetOrLoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height); + public: + TextureCache(); + ~TextureCache(); + void InvalidateImage(ImageIndex image); + BasicTextureInfo GetOrLoadImageTexture(const ImageId imageId); + BasicTextureInfo GetOrLoadGlyphTexture(const ImageId imageId, const PaletteMap& paletteMap); + BasicTextureInfo GetOrLoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height); - GLuint GetAtlasesTexture(); - GLuint GetPaletteTexture(); - GLuint GetBlendPaletteTexture(); - static GLint PaletteToY(FilterPaletteID palette); + GLuint GetAtlasesTexture(); + GLuint GetPaletteTexture(); + GLuint GetBlendPaletteTexture(); + static GLint PaletteToY(FilterPaletteID palette); -private: - void CreateTextures(); - void GeneratePaletteTexture(); - void EnlargeAtlasesTexture(GLuint newEntries); - AtlasTextureInfo LoadImageTexture(const ImageId image); - AtlasTextureInfo LoadGlyphTexture(const ImageId image, const PaletteMap& paletteMap); - AtlasTextureInfo AllocateImage(int32_t imageWidth, int32_t imageHeight); - AtlasTextureInfo LoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height); - static DrawPixelInfo GetImageAsDPI(const ImageId imageId); - static DrawPixelInfo GetGlyphAsDPI(const ImageId imageId, const PaletteMap& paletteMap); - void FreeTextures(); + private: + void CreateTextures(); + void GeneratePaletteTexture(); + void EnlargeAtlasesTexture(GLuint newEntries); + AtlasTextureInfo LoadImageTexture(const ImageId image); + AtlasTextureInfo LoadGlyphTexture(const ImageId image, const PaletteMap& paletteMap); + AtlasTextureInfo AllocateImage(int32_t imageWidth, int32_t imageHeight); + AtlasTextureInfo LoadBitmapTexture(ImageIndex image, const void* pixels, size_t width, size_t height); + static DrawPixelInfo GetImageAsDPI(const ImageId imageId); + static DrawPixelInfo GetGlyphAsDPI(const ImageId imageId, const PaletteMap& paletteMap); + void FreeTextures(); - static DrawPixelInfo CreateDPI(int32_t width, int32_t height); - static void DeleteDPI(DrawPixelInfo dpi); -}; + static DrawPixelInfo CreateDPI(int32_t width, int32_t height); + static void DeleteDPI(DrawPixelInfo dpi); + }; +} // namespace OpenRCT2::Ui diff --git a/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp b/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp index aa9db60ee1..bd113014b2 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.cpp @@ -15,194 +15,196 @@ # include # include -/* - * Structure to store locations of vertical bounding box edge. - */ -struct XData +namespace OpenRCT2::Ui { - int32_t xposition; - bool begin; - int32_t top, bottom; -}; -using SweepLine = std::vector; - -/* - * Creates a list of vertical bounding box edges, stored as xdata and sorted - * from left to right. If multiple edges are at the same x coordinate, Then - * edges for boxes to the left will appear before edges for boxes to the right. - */ -static inline SweepLine CreateXList(const RectCommandBatch& transparent) -{ - SweepLine x_sweep; - x_sweep.reserve(transparent.size() * 2); - - for (const DrawRectCommand& command : transparent) + /* + * Structure to store locations of vertical bounding box edge. + */ + struct XData { - int32_t left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z); - int32_t top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w); - int32_t right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z); - int32_t bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w); + int32_t xposition; + bool begin; + int32_t top, bottom; + }; + using SweepLine = std::vector; - assert(left <= right); - assert(top <= bottom); - if (left == right) - continue; - if (top == bottom) - continue; - - x_sweep.push_back({ left, true, top, bottom }); - x_sweep.push_back({ right, false, top, bottom }); - } - - std::sort(x_sweep.begin(), x_sweep.end(), [](const XData& a, const XData& b) -> bool { - if (a.xposition != b.xposition) - return a.xposition < b.xposition; - - return !a.begin && b.begin; - }); - - return x_sweep; -} - -/* - * Structure that stores intervals. YData.count stores how many intervals have - * an endpoint at this position, and YData.depth stores how many intervals - * intersect on the left limit of this point. In other words, IntervalTree - * stores half-closed intervals, with the left endpoint open, and the right - * endpoint closed. The IntervalTree uses std::map because it stores the values - * sorted, and we can traverse it in order using its bidirectional iterators. - */ -struct YData -{ - int32_t count, depth; -}; -using IntervalTree = std::map; - -/* - * Inserts the interval's top endpoint into the interval tree. If the endpoint - * already exists in the interval tree, it stacks the endpoints. - */ -static inline IntervalTree::iterator InsertTopEndpoint(IntervalTree& y_intersect, int32_t top) -{ - auto top_in = y_intersect.insert({ top, { 1, 0 } }); - IntervalTree::iterator top_it = top_in.first; - if (top_in.second) + /* + * Creates a list of vertical bounding box edges, stored as xdata and sorted + * from left to right. If multiple edges are at the same x coordinate, Then + * edges for boxes to the left will appear before edges for boxes to the right. + */ + static inline SweepLine CreateXList(const RectCommandBatch& transparent) { - IntervalTree::iterator top_next = std::next(top_it); - if (top_next != y_intersect.end()) + SweepLine x_sweep; + x_sweep.reserve(transparent.size() * 2); + + for (const DrawRectCommand& command : transparent) { - top_it->second.depth = top_next->second.depth; + int32_t left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z); + int32_t top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w); + int32_t right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z); + int32_t bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w); + + assert(left <= right); + assert(top <= bottom); + if (left == right) + continue; + if (top == bottom) + continue; + + x_sweep.push_back({ left, true, top, bottom }); + x_sweep.push_back({ right, false, top, bottom }); } - } - else - { - ++top_it->second.count; - } - return top_it; -} -/* - * Inserts the interval's bottom endpoint into the interval tree. If the - * endpoint already exists in the interval tree, it stacks the endpoint. - * This function can produce a new maximum depth. - */ -static inline IntervalTree::iterator InsertBottomEndpoint(IntervalTree& y_intersect, int32_t bottom) -{ - auto bottom_in = y_intersect.insert({ bottom, { 1, 1 } }); - IntervalTree::iterator bottom_it = bottom_in.first; - if (bottom_in.second) + std::sort(x_sweep.begin(), x_sweep.end(), [](const XData& a, const XData& b) -> bool { + if (a.xposition != b.xposition) + return a.xposition < b.xposition; + + return !a.begin && b.begin; + }); + + return x_sweep; + } + + /* + * Structure that stores intervals. YData.count stores how many intervals have + * an endpoint at this position, and YData.depth stores how many intervals + * intersect on the left limit of this point. In other words, IntervalTree + * stores half-closed intervals, with the left endpoint open, and the right + * endpoint closed. The IntervalTree uses std::map because it stores the values + * sorted, and we can traverse it in order using its bidirectional iterators. + */ + struct YData { - IntervalTree::iterator bottom_next = std::next(bottom_it); - if (bottom_next != y_intersect.end()) + int32_t count, depth; + }; + using IntervalTree = std::map; + + /* + * Inserts the interval's top endpoint into the interval tree. If the endpoint + * already exists in the interval tree, it stacks the endpoints. + */ + static inline IntervalTree::iterator InsertTopEndpoint(IntervalTree& y_intersect, int32_t top) + { + auto top_in = y_intersect.insert({ top, { 1, 0 } }); + IntervalTree::iterator top_it = top_in.first; + if (top_in.second) { - bottom_it->second.depth = bottom_next->second.depth + 1; - } - } - else - { - ++bottom_it->second.count; - ++bottom_it->second.depth; - } - return bottom_it; -} - -/* - * Removes the interval's top endpoint, handling stacked endpoints. - */ -static inline void RemoveTopEndpoint(IntervalTree& y_intersect, IntervalTree::iterator top_it) -{ - if (top_it->second.count == 1) - { - y_intersect.erase(top_it); - } - else - { - --top_it->second.count; - } -} - -/* - * Removes the interval's bottom endpoint, handling stacked endpoints. - */ -static inline void RemoveBottomEndpoint(IntervalTree& y_intersect, IntervalTree::iterator bottom_it) -{ - if (bottom_it->second.count == 1) - { - y_intersect.erase(bottom_it); - } - else - { - --bottom_it->second.count; - --bottom_it->second.depth; - } -} - -/* - * Determines an approximation of the number of depth peeling iterations needed - * to render the command batch. It will never underestimate the number of - * iterations, but it can overestimate, usually by no more than +2. - */ -int32_t MaxTransparencyDepth(const RectCommandBatch& transparent) -{ - int32_t max_depth = 1; - SweepLine x_sweep = CreateXList(transparent); - IntervalTree y_intersect{}; - - for (const XData& x : x_sweep) - { - if (x.begin) - { - IntervalTree::iterator top_it = InsertTopEndpoint(y_intersect, x.top); - IntervalTree::iterator bottom_it = InsertBottomEndpoint(y_intersect, x.bottom); - max_depth = std::max(max_depth, bottom_it->second.depth); - - /* - * Increment the depth for endpoings that intersect this interval - */ - for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it) + IntervalTree::iterator top_next = std::next(top_it); + if (top_next != y_intersect.end()) { - max_depth = std::max(max_depth, ++it->second.depth); + top_it->second.depth = top_next->second.depth; } } else { - IntervalTree::iterator top_it = y_intersect.find(x.top); - IntervalTree::iterator bottom_it = y_intersect.find(x.bottom); + ++top_it->second.count; + } + return top_it; + } - /* - * Decrement the depth for endpoings that intersected this interval - */ - for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it) + /* + * Inserts the interval's bottom endpoint into the interval tree. If the + * endpoint already exists in the interval tree, it stacks the endpoint. + * This function can produce a new maximum depth. + */ + static inline IntervalTree::iterator InsertBottomEndpoint(IntervalTree& y_intersect, int32_t bottom) + { + auto bottom_in = y_intersect.insert({ bottom, { 1, 1 } }); + IntervalTree::iterator bottom_it = bottom_in.first; + if (bottom_in.second) + { + IntervalTree::iterator bottom_next = std::next(bottom_it); + if (bottom_next != y_intersect.end()) { - --it->second.depth; + bottom_it->second.depth = bottom_next->second.depth + 1; } + } + else + { + ++bottom_it->second.count; + ++bottom_it->second.depth; + } + return bottom_it; + } - RemoveTopEndpoint(y_intersect, top_it); - RemoveBottomEndpoint(y_intersect, bottom_it); + /* + * Removes the interval's top endpoint, handling stacked endpoints. + */ + static inline void RemoveTopEndpoint(IntervalTree& y_intersect, IntervalTree::iterator top_it) + { + if (top_it->second.count == 1) + { + y_intersect.erase(top_it); + } + else + { + --top_it->second.count; } } - return max_depth; -} + /* + * Removes the interval's bottom endpoint, handling stacked endpoints. + */ + static inline void RemoveBottomEndpoint(IntervalTree& y_intersect, IntervalTree::iterator bottom_it) + { + if (bottom_it->second.count == 1) + { + y_intersect.erase(bottom_it); + } + else + { + --bottom_it->second.count; + --bottom_it->second.depth; + } + } + /* + * Determines an approximation of the number of depth peeling iterations needed + * to render the command batch. It will never underestimate the number of + * iterations, but it can overestimate, usually by no more than +2. + */ + int32_t MaxTransparencyDepth(const RectCommandBatch& transparent) + { + int32_t max_depth = 1; + SweepLine x_sweep = CreateXList(transparent); + IntervalTree y_intersect{}; + + for (const XData& x : x_sweep) + { + if (x.begin) + { + IntervalTree::iterator top_it = InsertTopEndpoint(y_intersect, x.top); + IntervalTree::iterator bottom_it = InsertBottomEndpoint(y_intersect, x.bottom); + max_depth = std::max(max_depth, bottom_it->second.depth); + + /* + * Increment the depth for endpoings that intersect this interval + */ + for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it) + { + max_depth = std::max(max_depth, ++it->second.depth); + } + } + else + { + IntervalTree::iterator top_it = y_intersect.find(x.top); + IntervalTree::iterator bottom_it = y_intersect.find(x.bottom); + + /* + * Decrement the depth for endpoings that intersected this interval + */ + for (IntervalTree::iterator it = std::next(top_it); it != bottom_it && it != std::end(y_intersect); ++it) + { + --it->second.depth; + } + + RemoveTopEndpoint(y_intersect, top_it); + RemoveBottomEndpoint(y_intersect, bottom_it); + } + } + + return max_depth; + } +} // namespace OpenRCT2::Ui #endif /* DISABLE_OPENGL */ diff --git a/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h b/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h index 053b36f538..3ae4bb017b 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h +++ b/src/openrct2-ui/drawing/engines/opengl/TransparencyDepth.h @@ -13,9 +13,12 @@ #include -/* - * Determines an approximation of the number of depth peeling iterations needed - * to render the command batch. It will never underestimate the number of - * iterations, but it can overestimate, usually by no more than +2. - */ -int32_t MaxTransparencyDepth(const RectCommandBatch& transparent); +namespace OpenRCT2::Ui +{ + /* + * Determines an approximation of the number of depth peeling iterations needed + * to render the command batch. It will never underestimate the number of + * iterations, but it can overestimate, usually by no more than +2. + */ + int32_t MaxTransparencyDepth(const RectCommandBatch& transparent); +} // namespace OpenRCT2::Ui