1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2025-12-10 09:32:29 +01:00

Fix #21824, #22820: OpenGL draws downscaled and masked sprites wrong

This commit is contained in:
mix
2025-04-03 23:01:40 +01:00
committed by GitHub
parent 9fb0ba0f3d
commit 69016f546e
9 changed files with 119 additions and 88 deletions

View File

@@ -13,14 +13,19 @@ uniform usampler2D uPaletteTex;
uniform sampler2D uPeelingTex;
uniform bool uPeeling;
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;
flat in int fFlags;
flat in uint fColour;
in vec3 fTexColour;
in vec3 fTexMask;
flat in vec4 fTexColour;
flat in vec4 fTexMask;
flat in vec3 fPalettes;
in vec2 fPosition;
flat in vec2 fPosition;
in vec3 fPeelPos;
flat in float fZoom;
flat in int fTexColourAtlas;
flat in int fTexMaskAtlas;
// clang-format on
out uint oColour;
@@ -36,10 +41,14 @@ void main()
}
}
vec2 position = (gl_FragCoord.xy - fPosition) * fZoom;
uint texel;
if ((fFlags & FLAG_NO_TEXTURE) == 0)
{
texel = texture(uTexture, fTexColour).r;
float colourU = (fTexColour.x + position.x) / fTexColour.z;
float colourV = (fTexColour.y + position.y) / fTexColour.w;
texel = texture(uTexture, vec3(colourU, colourV, fTexColourAtlas)).r;
if (texel == 0u)
{
discard;
@@ -93,8 +102,8 @@ void main()
if ((fFlags & FLAG_CROSS_HATCH) != 0)
{
int posSum = int(fPosition.x) + int(fPosition.y);
if ((posSum % 2) == 0)
int posSum = int(position.x) + int(position.y);
if ((posSum % 2) != 0)
{
discard;
}
@@ -102,7 +111,9 @@ void main()
if ((fFlags & FLAG_MASK) != 0)
{
uint mask = texture(uTexture, fTexMask).r;
float maskU = (fTexMask.x + position.x) / fTexMask.z;
float maskV = (fTexMask.y + position.y) / fTexMask.w;
uint mask = texture(uTexture, vec3(maskU, maskV, fTexMaskAtlas)).r;
if (mask == 0u)
{
discard;

View File

@@ -8,25 +8,29 @@ uniform ivec2 uScreenSize;
// clang-format off
in ivec4 vClip;
in int vTexColourAtlas;
in vec4 vTexColourBounds;
in vec4 vTexColourCoords;
in int vTexMaskAtlas;
in vec4 vTexMaskBounds;
in vec4 vTexMaskCoords;
in ivec3 vPalettes;
in int vFlags;
in uint vColour;
in ivec4 vBounds;
in int vDepth;
in float vZoom;
in mat4x2 vVertMat;
in vec2 vVertVec;
out vec2 fPosition;
flat out vec2 fPosition;
out vec3 fPeelPos;
flat out int fFlags;
flat out uint fColour;
out vec3 fTexColour;
out vec3 fTexMask;
flat out vec4 fTexColour;
flat out vec4 fTexMask;
flat out vec3 fPalettes;
flat out float fZoom;
flat out int fTexColourAtlas;
flat out int fTexMaskAtlas;
// clang-format on
void main()
@@ -35,10 +39,13 @@ void main()
vec2 m = clamp(
((vVertMat * vec4(vClip)) - (vVertMat * vec4(vBounds))) / vec2(vBounds.zw - vBounds.xy) + vVertVec, 0.0, 1.0);
vec2 pos = mix(vec2(vBounds.xy), vec2(vBounds.zw), m);
fTexColour = vec3(mix(vTexColourBounds.xy, vTexColourBounds.zw, m), vTexColourAtlas);
fTexMask = vec3(mix(vTexMaskBounds.xy, vTexMaskBounds.zw, m), vTexMaskAtlas);
fTexColour = vTexColourCoords;
fTexMask = vTexMaskCoords;
fPosition = pos;
fPosition = vBounds.xy;
fZoom = vZoom;
fTexColourAtlas = vTexColourAtlas;
fTexMaskAtlas = vTexMaskAtlas;
// Transform screen coordinates to texture coordinates
float depth = 1.0 - (float(vDepth) + 1.0) * DEPTH_INCREMENT;

View File

@@ -20,7 +20,10 @@
- Fix: [#18169] CJK, Arabic and Vietnamese display all text as ??? on Android.
- Fix: [#18309] Flying and Multi Dimension trains glitch when changing between inverted and uninverted track when uncap fps is on.
- Fix: [#19506] Queue paths can be placed on level crossings by replacing an existing regular path.
- Fix: [#21803] The park fence is drawn differently in OpenGL compared to software rendering when zoomed out.
- Fix: [#21824] Some sprites are drawn incorrectly when zoomed out in OpenGL rendering.
- Fix: [#21908] Ride mode warnings when hovering track designs.
- Fix: [#22820] OpenGL does not draw masked sprites correctly.
- Fix: [#22961] Clicking on the construction preview places duplicate flat rides and stalls.
- Fix: [#23359] Scripting: Add car.moveToTrack, an easier API than setting car.trackLocation directly.
- Fix: [#23443] New GOG version of RCT2 is not extracted correctly.

View File

@@ -112,6 +112,7 @@ namespace OpenRCT2::Ui
GLuint colour;
ivec4 bounds;
GLint depth;
GLfloat zoom;
enum
{

View File

@@ -64,12 +64,12 @@ DrawRectShader::DrawRectShader()
vTexColourAtlas, 1, GL_INT, sizeof(DrawRectCommand),
reinterpret_cast<void*>(offsetof(DrawRectCommand, texColourAtlas)));
glVertexAttribPointer(
vTexColourBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawRectCommand),
vTexColourCoords, 4, GL_FLOAT, GL_FALSE, sizeof(DrawRectCommand),
reinterpret_cast<void*>(offsetof(DrawRectCommand, texColourBounds)));
glVertexAttribIPointer(
vTexMaskAtlas, 1, GL_INT, sizeof(DrawRectCommand), reinterpret_cast<void*>(offsetof(DrawRectCommand, texMaskAtlas)));
glVertexAttribPointer(
vTexMaskBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawRectCommand),
vTexMaskCoords, 4, GL_FLOAT, GL_FALSE, sizeof(DrawRectCommand),
reinterpret_cast<void*>(offsetof(DrawRectCommand, texMaskBounds)));
glVertexAttribIPointer(
vPalettes, 3, GL_INT, sizeof(DrawRectCommand), reinterpret_cast<void*>(offsetof(DrawRectCommand, palettes)));
@@ -81,6 +81,8 @@ DrawRectShader::DrawRectShader()
vBounds, 4, GL_INT, sizeof(DrawRectCommand), reinterpret_cast<void*>(offsetof(DrawRectCommand, bounds)));
glVertexAttribIPointer(
vDepth, 1, GL_INT, sizeof(DrawRectCommand), reinterpret_cast<void*>(offsetof(DrawRectCommand, depth)));
glVertexAttribPointer(
vZoom, 1, GL_FLOAT, GL_FALSE, sizeof(DrawRectCommand), reinterpret_cast<void*>(offsetof(DrawRectCommand, zoom)));
glEnableVertexAttribArray(vVertMat + 0);
glEnableVertexAttribArray(vVertMat + 1);
@@ -90,25 +92,27 @@ DrawRectShader::DrawRectShader()
glEnableVertexAttribArray(vClip);
glEnableVertexAttribArray(vTexColourAtlas);
glEnableVertexAttribArray(vTexColourBounds);
glEnableVertexAttribArray(vTexColourCoords);
glEnableVertexAttribArray(vTexMaskAtlas);
glEnableVertexAttribArray(vTexMaskBounds);
glEnableVertexAttribArray(vTexMaskCoords);
glEnableVertexAttribArray(vPalettes);
glEnableVertexAttribArray(vFlags);
glEnableVertexAttribArray(vColour);
glEnableVertexAttribArray(vBounds);
glEnableVertexAttribArray(vDepth);
glEnableVertexAttribArray(vZoom);
glVertexAttribDivisor(vClip, 1);
glVertexAttribDivisor(vTexColourAtlas, 1);
glVertexAttribDivisor(vTexColourBounds, 1);
glVertexAttribDivisor(vTexColourCoords, 1);
glVertexAttribDivisor(vTexMaskAtlas, 1);
glVertexAttribDivisor(vTexMaskBounds, 1);
glVertexAttribDivisor(vTexMaskCoords, 1);
glVertexAttribDivisor(vPalettes, 1);
glVertexAttribDivisor(vFlags, 1);
glVertexAttribDivisor(vColour, 1);
glVertexAttribDivisor(vBounds, 1);
glVertexAttribDivisor(vDepth, 1);
glVertexAttribDivisor(vZoom, 1);
Use();
glUniform1i(uTexture, 0);
@@ -136,14 +140,15 @@ void DrawRectShader::GetLocations()
vClip = GetAttributeLocation("vClip");
vTexColourAtlas = GetAttributeLocation("vTexColourAtlas");
vTexColourBounds = GetAttributeLocation("vTexColourBounds");
vTexColourCoords = GetAttributeLocation("vTexColourCoords");
vTexMaskAtlas = GetAttributeLocation("vTexMaskAtlas");
vTexMaskBounds = GetAttributeLocation("vTexMaskBounds");
vTexMaskCoords = GetAttributeLocation("vTexMaskCoords");
vPalettes = GetAttributeLocation("vPalettes");
vFlags = GetAttributeLocation("vFlags");
vColour = GetAttributeLocation("vColour");
vBounds = GetAttributeLocation("vBounds");
vDepth = GetAttributeLocation("vDepth");
vZoom = GetAttributeLocation("vZoom");
vVertMat = GetAttributeLocation("vVertMat");
vVertVec = GetAttributeLocation("vVertVec");

View File

@@ -31,14 +31,15 @@ namespace OpenRCT2::Ui
GLuint vClip;
GLuint vTexColourAtlas;
GLuint vTexColourBounds;
GLuint vTexColourCoords;
GLuint vTexMaskAtlas;
GLuint vTexMaskBounds;
GLuint vTexMaskCoords;
GLuint vPalettes;
GLuint vFlags;
GLuint vColour;
GLuint vBounds;
GLuint vDepth;
GLuint vZoom;
GLuint _vbo;
GLuint _vboInstances;

View File

@@ -534,6 +534,7 @@ void OpenGLDrawingContext::FillRect(
command.bounds = { left, top, right + 1, bottom + 1 };
command.flags = DrawRectCommand::FLAG_NO_TEXTURE;
command.depth = _drawCount++;
command.zoom = 1.0f;
if (colour & 0x1000000)
{
@@ -569,6 +570,7 @@ void OpenGLDrawingContext::FilterRect(
command.bounds = { left, top, right + 1, bottom + 1 };
command.flags = DrawRectCommand::FLAG_NO_TEXTURE;
command.depth = _drawCount++;
command.zoom = 1.0f;
}
// Compute the bit code for a point p relative to the clip rectangle defined by topLeft and bottomRight
@@ -676,7 +678,13 @@ void OpenGLDrawingContext::DrawLine(DrawPixelInfo& dpi, uint32_t colour, const S
command.depth = _drawCount++;
}
void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId, int32_t x, int32_t y)
static auto EuclideanRemainder(const auto a, const auto b)
{
const auto r = a % b;
return r >= 0 ? r : r + b;
};
void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId, const int32_t x, const int32_t y)
{
auto g1Element = GfxGetG1Element(imageId);
if (g1Element == nullptr)
@@ -705,48 +713,33 @@ void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId,
}
}
auto texture = _textureCache->GetOrLoadImageTexture(imageId);
int32_t left = x + g1Element->x_offset;
int32_t top = y + g1Element->y_offset;
int32_t zoom_mask;
if (dpi.zoom_level >= ZoomLevel{ 0 })
zoom_mask = dpi.zoom_level.ApplyTo(0xFFFFFFFF);
else
zoom_mask = 0xFFFFFFFF;
if (dpi.zoom_level != ZoomLevel{ 0 } && (g1Element->flags & G1_FLAG_RLE_COMPRESSION))
int32_t xModifier = 0;
int32_t yModifier = 0;
int32_t widthModifier = 0;
if (dpi.zoom_level > ZoomLevel{ 0 })
{
top -= ~zoom_mask;
const int32_t interval = dpi.zoom_level.ApplyTo(1);
xModifier = EuclideanRemainder(left, interval);
xModifier = xModifier ? interval - xModifier : 0;
yModifier = EuclideanRemainder(top, interval);
widthModifier = EuclideanRemainder(left + g1Element->width, interval);
widthModifier = widthModifier ? interval - widthModifier : 0;
texture.coords.x += xModifier;
texture.coords.y += (interval - 1) - yModifier;
}
if (!(g1Element->flags & G1_FLAG_RLE_COMPRESSION))
{
top &= zoom_mask;
left += ~zoom_mask;
}
left &= zoom_mask;
int32_t right = left + g1Element->width;
int32_t bottom = top + g1Element->height;
if (dpi.zoom_level != ZoomLevel{ 0 } && (g1Element->flags & G1_FLAG_RLE_COMPRESSION))
{
bottom += top & ~zoom_mask;
}
if (left > right)
{
std::swap(left, right);
}
if (top > bottom)
{
std::swap(top, bottom);
}
left = dpi.zoom_level.ApplyInversedTo(left);
left = dpi.zoom_level.ApplyInversedTo(left + xModifier);
top = dpi.zoom_level.ApplyInversedTo(top);
right = dpi.zoom_level.ApplyInversedTo(right);
bottom = dpi.zoom_level.ApplyInversedTo(bottom);
int32_t right = left + dpi.zoom_level.ApplyInversedTo(g1Element->width + widthModifier);
int32_t bottom = top + dpi.zoom_level.ApplyInversedTo(g1Element->height + yModifier);
const ScreenRect clip = CalculateClipping(dpi);
left += clip.GetLeft() - dpi.x;
@@ -754,7 +747,8 @@ void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId,
right += clip.GetLeft() - dpi.x;
bottom += clip.GetTop() - dpi.y;
const auto texture = _textureCache->GetOrLoadImageTexture(imageId);
const float zoom = dpi.zoom_level >= ZoomLevel{ 0 } ? static_cast<float>(dpi.zoom_level.ApplyTo(1))
: 1.0f / static_cast<float>(dpi.zoom_level.ApplyInversedTo(1));
int paletteCount;
ivec3 palettes{};
@@ -794,14 +788,15 @@ void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId,
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = texture.index;
command.texMaskBounds = texture.normalizedBounds;
command.texMaskBounds = texture.coords;
command.palettes = palettes;
command.colour = palettes.x - (special ? 1 : 0);
command.bounds = { left, top, right, bottom };
command.flags = special ? 0 : DrawRectCommand::FLAG_NO_TEXTURE | DrawRectCommand::FLAG_MASK;
command.depth = _drawCount++;
command.zoom = zoom;
}
else
{
@@ -809,14 +804,15 @@ void OpenGLDrawingContext::DrawSprite(DrawPixelInfo& dpi, const ImageId imageId,
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.texMaskBounds = { 0.0f, 0.0f, texture.coords.z, texture.coords.w };
command.palettes = palettes;
command.colour = 0;
command.bounds = { left, top, right, bottom };
command.flags = paletteCount;
command.depth = _drawCount++;
command.zoom = zoom;
}
}
@@ -863,18 +859,22 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(
right += clip.GetLeft() - dpi.x;
bottom += clip.GetTop() - dpi.y;
const float zoom = dpi.zoom_level >= ZoomLevel{ 0 } ? static_cast<float>(dpi.zoom_level.ApplyTo(1))
: 1.0f / static_cast<float>(dpi.zoom_level.ApplyInversedTo(1));
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = textureColour.index;
command.texColourBounds = textureColour.normalizedBounds;
command.texColourBounds = textureColour.coords;
command.texMaskAtlas = textureMask.index;
command.texMaskBounds = textureMask.normalizedBounds;
command.texMaskBounds = textureMask.coords;
command.palettes = { 0, 0, 0 };
command.flags = DrawRectCommand::FLAG_MASK;
command.colour = 0;
command.bounds = { left, top, right, bottom };
command.depth = _drawCount++;
command.zoom = zoom;
}
void OpenGLDrawingContext::DrawSpriteSolid(DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, uint8_t colour)
@@ -918,12 +918,13 @@ void OpenGLDrawingContext::DrawSpriteSolid(DrawPixelInfo& dpi, const ImageId ima
command.texColourAtlas = 0;
command.texColourBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.texMaskAtlas = texture.index;
command.texMaskBounds = texture.normalizedBounds;
command.texMaskBounds = texture.coords;
command.palettes = { 0, 0, 0 };
command.flags = DrawRectCommand::FLAG_NO_TEXTURE | DrawRectCommand::FLAG_MASK;
command.colour = colour & 0xFF;
command.bounds = { left, top, right, bottom };
command.depth = _drawCount++;
command.zoom = 1.0f;
}
void OpenGLDrawingContext::DrawGlyph(DrawPixelInfo& dpi, const ImageId image, int32_t x, int32_t y, const PaletteMap& palette)
@@ -961,11 +962,14 @@ void OpenGLDrawingContext::DrawGlyph(DrawPixelInfo& dpi, const ImageId image, in
right += clip.GetLeft() - dpi.x;
bottom += clip.GetTop() - dpi.y;
const float zoom = dpi.zoom_level >= ZoomLevel{ 0 } ? static_cast<float>(dpi.zoom_level.ApplyTo(1))
: 1.0f / static_cast<float>(dpi.zoom_level.ApplyInversedTo(1));
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.palettes = { 0, 0, 0 };
@@ -973,6 +977,7 @@ void OpenGLDrawingContext::DrawGlyph(DrawPixelInfo& dpi, const ImageId image, in
command.colour = 0;
command.bounds = { left, top, right, bottom };
command.depth = _drawCount++;
command.zoom = zoom;
}
void OpenGLDrawingContext::DrawTTFBitmap(
@@ -1027,7 +1032,7 @@ void OpenGLDrawingContext::DrawTTFBitmap(
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.palettes = { 0, 0, 0 };
@@ -1035,6 +1040,7 @@ void OpenGLDrawingContext::DrawTTFBitmap(
command.colour = info->palette[3];
command.bounds = b;
command.depth = _drawCount++;
command.zoom = 1.0f;
}
}
if (info->flags & TEXT_DRAW_FLAG_INSET)
@@ -1042,7 +1048,7 @@ void OpenGLDrawingContext::DrawTTFBitmap(
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.palettes = { 0, 0, 0 };
@@ -1050,12 +1056,13 @@ void OpenGLDrawingContext::DrawTTFBitmap(
command.colour = info->palette[3];
command.bounds = { left + 1, top + 1, right + 1, bottom + 1 };
command.depth = _drawCount++;
command.zoom = 1.0f;
}
auto& cmdBuf = hintingThreshold > 0 ? _commandBuffers.transparent : _commandBuffers.rects;
DrawRectCommand& command = cmdBuf.allocate();
command.clip = { clip.GetLeft(), clip.GetTop(), clip.GetRight(), clip.GetBottom() };
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texColourBounds = texture.coords;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.palettes = { 0, 0, 0 };
@@ -1063,6 +1070,7 @@ void OpenGLDrawingContext::DrawTTFBitmap(
command.colour = info->palette[1];
command.bounds = { left, top, right, bottom };
command.depth = _drawCount++;
command.zoom = 1.0f;
#endif // NO_TTF
}

View File

@@ -83,7 +83,7 @@ BasicTextureInfo TextureCache::GetOrLoadImageTexture(const ImageId imageId)
const auto& info = _textureCache[index];
return {
info.index,
info.normalizedBounds,
info.coords,
};
}
}
@@ -123,7 +123,7 @@ BasicTextureInfo TextureCache::GetOrLoadGlyphTexture(const ImageId imageId, cons
const auto& info = kvp->second;
return {
info.index,
info.normalizedBounds,
info.coords,
};
}
}
@@ -151,7 +151,7 @@ BasicTextureInfo TextureCache::GetOrLoadBitmapTexture(ImageIndex image, const vo
const auto& info = _textureCache[index];
return {
info.index,
info.normalizedBounds,
info.coords,
};
}
}

View File

@@ -63,7 +63,7 @@ namespace OpenRCT2::Ui
struct BasicTextureInfo
{
GLuint index;
vec4 normalizedBounds;
vec4 coords;
};
// Location of an image (texture atlas index, slot and normalized coordinates)
@@ -124,7 +124,12 @@ namespace OpenRCT2::Ui
info.index = _index;
info.slot = slot;
info.bounds = bounds;
info.normalizedBounds = NormalizeCoordinates(bounds);
info.coords = vec4{
static_cast<float>(bounds.x),
static_cast<float>(bounds.y),
static_cast<float>(_atlasWidth),
static_cast<float>(_atlasHeight),
};
return info;
}
@@ -176,16 +181,6 @@ namespace OpenRCT2::Ui
_imageSize * row + actualHeight,
};
}
[[nodiscard]] vec4 NormalizeCoordinates(const ivec4& coords) const
{
return vec4{
coords.x / static_cast<float>(_atlasWidth),
coords.y / static_cast<float>(_atlasHeight),
coords.z / static_cast<float>(_atlasWidth),
coords.w / static_cast<float>(_atlasHeight),
};
}
};
class TextureCache final