Added OpenGL TTF hinting

This commit is contained in:
Michael Bernardi 2023-12-03 18:58:28 +01:00
parent f64706e1d9
commit 8c7d1d149a
18 changed files with 129 additions and 37 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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 dont 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 RCs 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 dont support hinting, outlines, or insets with OpenGL.
0.4.6 (2023-09-03)
------------------------------------------------------------------------

View File

@ -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()

View File

@ -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:

View File

@ -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
};
};

View File

@ -23,7 +23,6 @@
# include <SDL.h>
# include <algorithm>
# include <array>
# include <cmath>
# include <openrct2-ui/interface/Window.h>
# include <openrct2/Intro.h>
@ -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();

View File

@ -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
{

View File

@ -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;

View File

@ -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);

View File

@ -52,6 +52,6 @@ public:
_transparentFramebuffer.Bind();
}
void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex);
void ApplyTransparency(ApplyTransparencyShader& shader, GLuint paletteTex, GLuint blendPaletteTex);
void Clear();
};

View File

@ -13,6 +13,7 @@
# include <algorithm>
# include <openrct2/drawing/Drawing.h>
# include <openrct2/interface/Colour.h>
# include <openrct2/util/Util.h>
# include <openrct2/world/Location.hpp>
# include <stdexcept>
@ -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;

View File

@ -206,6 +206,7 @@ private:
std::array<uint32_t, SPR_IMAGE_LIST_END> _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:

View File

@ -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;
}

View File

@ -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

View File

@ -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
{
}
};

View File

@ -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

View File

@ -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();