diff --git a/data/shaders/applytransparency.frag b/data/shaders/applytransparency.frag index faa5f770d1..77656804fe 100644 --- a/data/shaders/applytransparency.frag +++ b/data/shaders/applytransparency.frag @@ -5,6 +5,7 @@ uniform sampler2D uOpaqueDepth; uniform usampler2D uTransparentTex; uniform sampler2D uTransparentDepth; uniform usampler2D uPaletteTex; +uniform usampler2D uBlendPaletteTex; in vec2 fTextureCoordinate; @@ -21,6 +22,21 @@ void main() { transparent = 0u; } - - oColour = texture(uPaletteTex, vec2(opaque, transparent) / 256.f).r; + + uint blendColour = (transparent & 0xff00u) >> 8; + if(blendColour > 0u) + { + if((transparent & 0x00ffu) != 0u) + { + oColour = blendColour; + } + else + { + oColour = texture(uBlendPaletteTex, vec2(opaque, blendColour) / 256.f).r; + } + } + else + { + oColour = texture(uPaletteTex, vec2(opaque, transparent) / 256.f).r; + } } diff --git a/data/shaders/drawrect.frag b/data/shaders/drawrect.frag index f5a26749bd..b09983ba85 100644 --- a/data/shaders/drawrect.frag +++ b/data/shaders/drawrect.frag @@ -48,7 +48,21 @@ void main() } else { - texel = fColour; + uint hint_thresh = uint(fFlags & 0xff00) >> 8; + if(hint_thresh > 0u) + { + bool solidColor = texel > 180u; + texel = (texel > hint_thresh) ? fColour : 0u; + texel = texel << 8; + if(solidColor) + { + texel += 1u; + } + } + else + { + texel = fColour; + } } } else diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 788b574062..96fe242970 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -8,19 +8,21 @@ - Feature: [#20825] Made setting the game speed a game action. - Feature: [#20853] [Plugin] Add “BaseTileElement.owner” which is saved in the park file. - Change: [#20790] Default ride price set to free if park charges for entry. +- Fix: [#15293] TTF fonts don’t format correctly with OpenGL. - Fix: [#16453] Tile inspector invisibility shortcut does not use a game action. - Fix: [#17774] Misplaced/missing land and construction rights tiles in RCT1 & RCT2 scenarios. - Fix: [#18199] Dots in the game save's name no longer get truncated. - Fix: [#19722] “Forbid tree removal” restriction doesn't forbid removal of large scenery tree items. - Fix: [#20253] Crash when displaying a Lay-Down RC’s half loop. - Fix: [#20356] Cannot set tertiary colour on small scenery. +- Fix: [#20624] Scrolling text glitches after language is changed. - Fix: [#20679] Android: game crashes at launch. - Fix: [#20737] Spent money in player window underflows when getting refunds. - Fix: [#20747] Staff speed cheat not applying to newly hired staff, UI not showing the current applied speed. - Fix: [#20778] [Plugin] Incorrect target api when executing custom actions. - Fix: [#20807] Tertiary colour not copied with small scenery. - Fix: [#20964] Crash when player connects to server with a group assigned that no longer exists. -- Fix: [#20624] Scrolling text glitches after language is changed. +- Fix: [#20995] TTF fonts don’t support hinting, outlines, or insets with OpenGL. 0.4.6 (2023-09-03) ------------------------------------------------------------------------ diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp index 6a06d3eeb6..0d5a926afd 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.cpp @@ -54,6 +54,7 @@ ApplyTransparencyShader::ApplyTransparencyShader() glUniform1i(uTransparentTex, 2); glUniform1i(uTransparentDepth, 3); glUniform1i(uPaletteTex, 4); + glUniform1i(uBlendPaletteTex, 5); } ApplyTransparencyShader::~ApplyTransparencyShader() @@ -69,19 +70,22 @@ void ApplyTransparencyShader::GetLocations() uTransparentTex = GetUniformLocation("uTransparentTex"); uTransparentDepth = GetUniformLocation("uTransparentDepth"); uPaletteTex = GetUniformLocation("uPaletteTex"); + uBlendPaletteTex = GetUniformLocation("uBlendPaletteTex"); vPosition = GetAttributeLocation("vPosition"); vTextureCoordinate = GetAttributeLocation("vTextureCoordinate"); } void ApplyTransparencyShader::SetTextures( - GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex) + GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex, + GLuint blendPaletteTex) { OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, opaqueTex); OpenGLAPI::SetTexture(1, GL_TEXTURE_2D, opaqueDepth); OpenGLAPI::SetTexture(2, GL_TEXTURE_2D, transparentTex); OpenGLAPI::SetTexture(3, GL_TEXTURE_2D, transparentDepth); OpenGLAPI::SetTexture(4, GL_TEXTURE_2D, paletteTex); + OpenGLAPI::SetTexture(5, GL_TEXTURE_2D, blendPaletteTex); } void ApplyTransparencyShader::Draw() diff --git a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h index b655324f29..14d545c990 100644 --- a/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h +++ b/src/openrct2-ui/drawing/engines/opengl/ApplyTransparencyShader.h @@ -20,6 +20,7 @@ private: GLuint uTransparentTex; GLuint uTransparentDepth; GLuint uPaletteTex; + GLuint uBlendPaletteTex; GLuint vPosition; GLuint vTextureCoordinate; @@ -32,7 +33,8 @@ public: ~ApplyTransparencyShader() override; static void SetTextures( - GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex); + GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex, + GLuint blendPaletteTex); void Draw(); private: diff --git a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h index 2becc8f8bb..ab2b3915bf 100644 --- a/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h +++ b/src/openrct2-ui/drawing/engines/opengl/DrawCommands.h @@ -119,6 +119,8 @@ struct DrawRectCommand 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 }; }; diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp index b18a8f4e42..155e6fa8fe 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -23,7 +23,6 @@ # include # include -# include # include # include # include @@ -112,7 +111,7 @@ public: void DrawGlyph(DrawPixelInfo* dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& palette) override; void DrawTTFBitmap( DrawPixelInfo* dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, int32_t x, - int32_t y) override; + int32_t y, uint8_t hinting_threshold) override; void FlushCommandBuffers(); @@ -910,7 +909,7 @@ void OpenGLDrawingContext::DrawGlyph(DrawPixelInfo* dpi, const ImageId image, in void OpenGLDrawingContext::DrawTTFBitmap( DrawPixelInfo* dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, int32_t x, - int32_t y) + int32_t y, uint8_t hinting_threshold) { CalculcateClipping(dpi); @@ -977,15 +976,15 @@ void OpenGLDrawingContext::DrawTTFBitmap( command.bounds = { left + 1, top + 1, right + 1, bottom + 1 }; command.depth = _drawCount++; } - - DrawRectCommand& command = _commandBuffers.rects.allocate(); + auto& cmdBuf = hinting_threshold > 0 ? _commandBuffers.transparent : _commandBuffers.rects; + DrawRectCommand& command = cmdBuf.allocate(); command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom }; command.texColourAtlas = texture.index; command.texColourBounds = texture.normalizedBounds; command.texMaskAtlas = 0; command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f }; command.palettes = { 0, 0, 0 }; - command.flags = DrawRectCommand::FLAG_TTF_TEXT; + command.flags = DrawRectCommand::FLAG_TTF_TEXT | (hinting_threshold << 8); command.colour = info->palette[1]; command.bounds = { left, top, right, bottom }; command.depth = _drawCount++; @@ -1061,7 +1060,8 @@ void OpenGLDrawingContext::HandleTransparency() _drawRectShader->Use(); _drawRectShader->DrawInstances(); - _swapFramebuffer->ApplyTransparency(*_applyTransparencyShader, _textureCache->GetPaletteTexture()); + _swapFramebuffer->ApplyTransparency( + *_applyTransparencyShader, _textureCache->GetPaletteTexture(), _textureCache->GetBlendPaletteTexture()); } _commandBuffers.transparent.clear(); diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp index 6fb950c7df..f9129d4321 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.cpp @@ -26,7 +26,7 @@ OpenGLFramebuffer::OpenGLFramebuffer(SDL_Window* window) SDL_GL_GetDrawableSize(window, &_width, &_height); } -OpenGLFramebuffer::OpenGLFramebuffer(int32_t width, int32_t height, bool depth, bool integer) +OpenGLFramebuffer::OpenGLFramebuffer(int32_t width, int32_t height, bool depth, bool integer, bool word) { _width = width; _height = height; @@ -35,7 +35,9 @@ OpenGLFramebuffer::OpenGLFramebuffer(int32_t width, int32_t height, bool depth, glBindTexture(GL_TEXTURE_2D, _texture); if (integer) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, width, height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + int internalFormat = word ? GL_R16UI : GL_R8UI; + int type = word ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE; + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RED_INTEGER, type, nullptr); } else { diff --git a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h index 7be132d526..0a1f07fec5 100644 --- a/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/OpenGLFramebuffer.h @@ -28,7 +28,7 @@ private: public: explicit OpenGLFramebuffer(SDL_Window* window); - OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true); + OpenGLFramebuffer(int32_t width, int32_t height, bool depth = true, bool integer = true, bool word = false); ~OpenGLFramebuffer(); OpenGLFramebuffer(const OpenGLFramebuffer&) = delete; diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp index 4a49bc6350..307b547791 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.cpp @@ -19,7 +19,7 @@ constexpr GLuint indexValue[4] = { 0, 0, 0, 0 }; SwapFramebuffer::SwapFramebuffer(int32_t width, int32_t height) : _opaqueFramebuffer(width, height) - , _transparentFramebuffer(width, height) + , _transparentFramebuffer(width, height, true, true, true) , _mixFramebuffer(width, height, false) , _backDepth(OpenGLFramebuffer::CreateDepthTexture(width, height)) { @@ -32,14 +32,14 @@ SwapFramebuffer::~SwapFramebuffer() glDeleteTextures(1, &_backDepth); } -void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex) +void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex) { _mixFramebuffer.Bind(); glDisable(GL_DEPTH_TEST); shader.Use(); shader.SetTextures( _opaqueFramebuffer.GetTexture(), _opaqueFramebuffer.GetDepthTexture(), _transparentFramebuffer.GetTexture(), - _transparentFramebuffer.GetDepthTexture(), paletteTex); + _transparentFramebuffer.GetDepthTexture(), paletteTex, blendPaletteTex); shader.Draw(); _backDepth = _transparentFramebuffer.SwapDepthTexture(_backDepth); diff --git a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h index db1e0f031a..97facb813b 100644 --- a/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h +++ b/src/openrct2-ui/drawing/engines/opengl/SwapFramebuffer.h @@ -52,6 +52,6 @@ public: _transparentFramebuffer.Bind(); } - void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex); + void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex); void Clear(); }; diff --git a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp index 5791d2ae23..a7a24e7388 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp +++ b/src/openrct2-ui/drawing/engines/opengl/TextureCache.cpp @@ -13,6 +13,7 @@ # include # include +# include # include # include # include @@ -193,6 +194,18 @@ void TextureCache::CreateTextures() glPixelStorei(GL_UNPACK_ALIGNMENT, 1); GeneratePaletteTexture(); + auto blendArray = GetBlendColourMap(); + if (blendArray != nullptr) + { + glGenTextures(1, &_blendPaletteTexture); + glBindTexture(GL_TEXTURE_2D, _blendPaletteTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_R8UI, PALETTE_SIZE, PALETTE_SIZE, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, blendArray); + } + _initialized = true; _atlasesTextureIndices = 0; _atlasesTextureCapacity = 0; @@ -414,6 +427,11 @@ GLuint TextureCache::GetPaletteTexture() return _paletteTexture; } +GLuint TextureCache::GetBlendPaletteTexture() +{ + return _blendPaletteTexture; +} + GLint TextureCache::PaletteToY(FilterPaletteID palette) { return palette > FilterPaletteID::PaletteWater ? EnumValue(palette) + 5 : EnumValue(palette) + 1; diff --git a/src/openrct2-ui/drawing/engines/opengl/TextureCache.h b/src/openrct2-ui/drawing/engines/opengl/TextureCache.h index a16a03b4fc..26c8c9bc54 100644 --- a/src/openrct2-ui/drawing/engines/opengl/TextureCache.h +++ b/src/openrct2-ui/drawing/engines/opengl/TextureCache.h @@ -206,6 +206,7 @@ private: std::array _indexMap; GLuint _paletteTexture = 0; + GLuint _blendPaletteTexture = 0; #ifndef __MACOSX__ std::shared_mutex _mutex; @@ -227,6 +228,7 @@ public: GLuint GetAtlasesTexture(); GLuint GetPaletteTexture(); + GLuint GetBlendPaletteTexture(); static GLint PaletteToY(FilterPaletteID palette); private: diff --git a/src/openrct2/drawing/Drawing.String.cpp b/src/openrct2/drawing/Drawing.String.cpp index 86cee0a5ee..303283877f 100644 --- a/src/openrct2/drawing/Drawing.String.cpp +++ b/src/openrct2/drawing/Drawing.String.cpp @@ -541,19 +541,21 @@ static void TTFDrawStringRawTTF(DrawPixelInfo& dpi, std::string_view text, TextD if (OpenRCT2::GetContext()->GetDrawingEngineType() == DrawingEngine::OpenGL) { - // if(use_hinting) return; // Not implemented yet. auto baseId = uint32_t(0x7FFFF) - 1024; auto imageId = baseId + _ttfGlId; auto drawingEngine = dpi.DrawingEngine; auto drawingContext = drawingEngine->GetDrawingContext(); + uint8_t hint_thresh = use_hinting ? fontDesc->hinting_threshold : 0; drawingEngine->InvalidateImage(imageId); - drawingContext->DrawTTFBitmap(&dpi, info, imageId, surface->pixels, surface->pitch, surface->h, drawX, drawY); + drawingContext->DrawTTFBitmap( + &dpi, info, imageId, surface->pixels, surface->pitch, surface->h, drawX, drawY, hint_thresh); _ttfGlId++; if (_ttfGlId >= 1023) { _ttfGlId = 0; } + info->x += width; return; } diff --git a/src/openrct2/drawing/IDrawingContext.h b/src/openrct2/drawing/IDrawingContext.h index 096fdb0f69..a7966565db 100644 --- a/src/openrct2/drawing/IDrawingContext.h +++ b/src/openrct2/drawing/IDrawingContext.h @@ -34,7 +34,7 @@ namespace OpenRCT2::Drawing DrawPixelInfo* dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& palette) abstract; virtual void DrawTTFBitmap( DrawPixelInfo* dpi, TextDrawInfo* info, ImageIndex image, const void* pixels, int32_t width, int32_t height, - int32_t x, int32_t y) abstract; + int32_t x, int32_t y, uint8_t hinting_threshold) abstract; }; } // namespace OpenRCT2::Drawing diff --git a/src/openrct2/drawing/X8DrawingEngine.h b/src/openrct2/drawing/X8DrawingEngine.h index a11aa9d8c8..df545fa2a2 100644 --- a/src/openrct2/drawing/X8DrawingEngine.h +++ b/src/openrct2/drawing/X8DrawingEngine.h @@ -149,7 +149,7 @@ namespace OpenRCT2 DrawPixelInfo* dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& paletteMap) override; void DrawTTFBitmap( DrawPixelInfo* dpi, TextDrawInfo* info, uint32_t image, const void* pixels, int32_t width, int32_t height, - int32_t x, int32_t y) override + int32_t x, int32_t y, uint8_t hinting_threshold) override { } }; diff --git a/src/openrct2/interface/Colour.cpp b/src/openrct2/interface/Colour.cpp index db80e464de..f3e2e7b49a 100644 --- a/src/openrct2/interface/Colour.cpp +++ b/src/openrct2/interface/Colour.cpp @@ -130,7 +130,9 @@ namespace Colour } // namespace Colour #ifndef NO_TTF -static uint8_t BlendColourMap[PALETTE_COUNT][PALETTE_COUNT] = { 0 }; +static BlendColourMapType BlendColourMap = { 0 }; + +static bool BlendColourMapInitialised = false; static uint8_t FindClosestPaletteIndex(uint8_t red, uint8_t green, uint8_t blue) { @@ -152,21 +154,44 @@ static uint8_t FindClosestPaletteIndex(uint8_t red, uint8_t green, uint8_t blue) return closest; } +static void InitBlendColourMap() +{ + for (int i = 0; i < PALETTE_SIZE; i++) + { + for (int j = i; j < PALETTE_SIZE; j++) + { + uint8_t red = (gPalette[i].Red + gPalette[j].Red) / 2; + uint8_t green = (gPalette[i].Green + gPalette[j].Green) / 2; + uint8_t blue = (gPalette[i].Blue + gPalette[j].Blue) / 2; + + auto colour = FindClosestPaletteIndex(red, green, blue); + BlendColourMap[i][j] = colour; + BlendColourMap[j][i] = colour; + } + } + BlendColourMapInitialised = true; +} + +BlendColourMapType* GetBlendColourMap() +{ + if (!BlendColourMapInitialised) + { + InitBlendColourMap(); + } + return &BlendColourMap; +} + uint8_t BlendColours(const uint8_t paletteIndex1, const uint8_t paletteIndex2) { - const uint8_t cMin = std::min(paletteIndex1, paletteIndex2); - const uint8_t cMax = std::max(paletteIndex1, paletteIndex2); - - if (BlendColourMap[cMin][cMax] != 0) + if (!BlendColourMapInitialised) { - return BlendColourMap[cMin][cMax]; + InitBlendColourMap(); } - - uint8_t red = (gPalette[cMin].Red + gPalette[cMax].Red) / 2; - uint8_t green = (gPalette[cMin].Green + gPalette[cMax].Green) / 2; - uint8_t blue = (gPalette[cMin].Blue + gPalette[cMax].Blue) / 2; - - BlendColourMap[cMin][cMax] = FindClosestPaletteIndex(red, green, blue); - return BlendColourMap[cMin][cMax]; + return BlendColourMap[paletteIndex1][paletteIndex2]; +} +#else +BlendColourMapType* GetBlendColourMap() +{ + return nullptr; } #endif diff --git a/src/openrct2/interface/Colour.h b/src/openrct2/interface/Colour.h index 57eb414a70..083b07fd16 100644 --- a/src/openrct2/interface/Colour.h +++ b/src/openrct2/interface/Colour.h @@ -252,3 +252,6 @@ namespace Colour #ifndef NO_TTF uint8_t BlendColours(const uint8_t paletteIndex1, const uint8_t paletteIndex2); #endif + +typedef uint8_t BlendColourMapType[PALETTE_COUNT][PALETTE_COUNT]; +BlendColourMapType* GetBlendColourMap(); \ No newline at end of file