From 5f7a6fb3692befa5b6e5da4eb26b257d5567e8a8 Mon Sep 17 00:00:00 2001 From: duncanspumpkin Date: Sun, 18 Sep 2016 15:40:27 +0100 Subject: [PATCH] Fixed OpenGL palette drawing Added palettes to the texture atlas and now correctly use them to generate images. Transparency semi supported but the colours are not quite correct. --- data/shaders/drawimage.frag | 35 ++++++++++++- data/shaders/drawimage.vert | 6 +++ src/drawing/drawing.h | 1 + src/drawing/engines/opengl/DrawCommands.h | 1 + .../engines/opengl/DrawImageShader.cpp | 8 +++ src/drawing/engines/opengl/DrawImageShader.h | 4 ++ .../engines/opengl/OpenGLDrawingEngine.cpp | 31 +++++++++++ src/drawing/engines/opengl/TextureCache.cpp | 52 ++++++++++++++++++- src/drawing/engines/opengl/TextureCache.h | 5 +- src/drawing/sprite.c | 2 +- src/paint/paint.c | 1 - 11 files changed, 140 insertions(+), 6 deletions(-) diff --git a/data/shaders/drawimage.frag b/data/shaders/drawimage.frag index c4ae8ce042..1559de7277 100644 --- a/data/shaders/drawimage.frag +++ b/data/shaders/drawimage.frag @@ -10,6 +10,8 @@ flat in int fTexColourAtlas; in vec2 fTexColourCoords; flat in int fTexMaskAtlas; in vec2 fTexMaskCoords; +flat in int fTexPaletteAtlas; +flat in vec4 fTexPaletteBounds; flat in int fMask; in vec2 fPosition; @@ -25,7 +27,38 @@ void main() discard; } - vec4 texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexColourAtlas))).r]; + vec4 texel; + + // If remap palette used + if ((fFlags & (1 << 1)) != 0) + { + // z is the size of each x pixel in the atlas + float x = fTexPaletteBounds.x + texture(uTexture, vec3(fTexColourCoords, float(fTexColourAtlas))).r * fTexPaletteBounds.z; + texel = uPalette[texture(uTexture, vec3(x, fTexPaletteBounds.y, float(fTexPaletteAtlas))).r]; + } // If transparent or special transparent + else if ((fFlags & ((1 << 2) | (1 << 3))) != 0) + { + float line = texture(uTexture,vec3(fTexColourCoords, float(fTexColourAtlas))).r; + if (line == 0.0) + { + discard; + } + float alpha = 0.5; + if ((fFlags & (1 << 2)) != 0) + { + alpha = 0.5 + (line - 1.0) / 10.0; + } + + // z is the size of each x pixel in the atlas + float x = fTexPaletteBounds.x + fTexPaletteBounds.z * 50.0; + oColour = vec4(uPalette[texture(uTexture, vec3(x, fTexPaletteBounds.y, float(fTexPaletteAtlas))).r].rgb, alpha); + + return; + } + else + { + texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexColourAtlas))).r]; + } vec4 mask = uPalette[texture(uTexture, vec3(fTexMaskCoords, float(fTexMaskAtlas))).r]; if (fMask != 0) diff --git a/data/shaders/drawimage.vert b/data/shaders/drawimage.vert index 064a5e3e56..4a2b56b59f 100644 --- a/data/shaders/drawimage.vert +++ b/data/shaders/drawimage.vert @@ -7,6 +7,8 @@ in int ivTexColourAtlas; in vec4 ivTexColourBounds; in int ivTexMaskAtlas; in vec4 ivTexMaskBounds; +in int ivTexPaletteAtlas; +in vec4 ivTexPaletteBounds; in int ivFlags; in vec4 ivColour; in ivec4 ivBounds; @@ -23,6 +25,8 @@ flat out int fTexColourAtlas; out vec2 fTexColourCoords; flat out int fTexMaskAtlas; out vec2 fTexMaskCoords; +flat out int fTexPaletteAtlas; +flat out vec4 fTexPaletteBounds; flat out int fMask; void main() @@ -64,6 +68,8 @@ void main() fMask = ivMask; fTexColourAtlas = ivTexColourAtlas; fTexMaskAtlas = ivTexMaskAtlas; + fTexPaletteAtlas = ivTexPaletteAtlas; + fTexPaletteBounds = ivTexPaletteBounds; gl_Position = vec4(pos, 0.0, 1.0); } diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h index 316a13746a..cbab3b8eb3 100644 --- a/src/drawing/drawing.h +++ b/src/drawing/drawing.h @@ -195,6 +195,7 @@ void FASTCALL gfx_draw_sprite_raw_masked(rct_drawpixelinfo *dpi, int x, int y, i void FASTCALL gfx_draw_sprite_solid(rct_drawpixelinfo * dpi, int image, int x, int y, uint8 colour); void FASTCALL gfx_draw_sprite_software(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour); +uint8* FASTCALL gfx_draw_sprite_get_palette(int image_id, uint32 tertiary_colour); void FASTCALL gfx_draw_sprite_palette_set_software(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint8* palette_pointer, uint8* unknown_pointer); void FASTCALL gfx_draw_sprite_raw_masked_software(rct_drawpixelinfo *dpi, int x, int y, int maskImage, int colourImage); diff --git a/src/drawing/engines/opengl/DrawCommands.h b/src/drawing/engines/opengl/DrawCommands.h index d6b8c33fe2..194f3f9eb2 100644 --- a/src/drawing/engines/opengl/DrawCommands.h +++ b/src/drawing/engines/opengl/DrawCommands.h @@ -40,6 +40,7 @@ struct DrawImageCommand { sint32 clip[4]; CachedTextureInfo texMask; CachedTextureInfo texColour; + CachedTextureInfo texPalette; sint32 bounds[4]; bool mask; }; \ No newline at end of file diff --git a/src/drawing/engines/opengl/DrawImageShader.cpp b/src/drawing/engines/opengl/DrawImageShader.cpp index 24af2f6e1f..bc7277d2e6 100644 --- a/src/drawing/engines/opengl/DrawImageShader.cpp +++ b/src/drawing/engines/opengl/DrawImageShader.cpp @@ -40,6 +40,8 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glVertexAttribPointer(vTexColourBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourBounds)); glVertexAttribIPointer(vTexMaskAtlas, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskAtlas)); glVertexAttribPointer(vTexMaskBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texMaskBounds)); + glVertexAttribIPointer(vTexPaletteAtlas, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texPaletteAtlas)); + glVertexAttribPointer(vTexPaletteBounds, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texPaletteBounds)); glVertexAttribIPointer(vFlags, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags)); glVertexAttribPointer(vColour, 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour)); glVertexAttribIPointer(vBounds, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds)); @@ -51,6 +53,8 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glEnableVertexAttribArray(vTexColourBounds); glEnableVertexAttribArray(vTexMaskAtlas); glEnableVertexAttribArray(vTexMaskBounds); + glEnableVertexAttribArray(vTexPaletteAtlas); + glEnableVertexAttribArray(vTexPaletteBounds); glEnableVertexAttribArray(vFlags); glEnableVertexAttribArray(vColour); glEnableVertexAttribArray(vBounds); @@ -61,6 +65,8 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage") glVertexAttribDivisor(vTexColourBounds, 1); glVertexAttribDivisor(vTexMaskAtlas, 1); glVertexAttribDivisor(vTexMaskBounds, 1); + glVertexAttribDivisor(vTexPaletteAtlas, 1); + glVertexAttribDivisor(vTexPaletteBounds, 1); glVertexAttribDivisor(vFlags, 1); glVertexAttribDivisor(vColour, 1); glVertexAttribDivisor(vBounds, 1); @@ -91,6 +97,8 @@ void DrawImageShader::GetLocations() vTexColourBounds = GetAttributeLocation("ivTexColourBounds"); vTexMaskAtlas = GetAttributeLocation("ivTexMaskAtlas"); vTexMaskBounds = GetAttributeLocation("ivTexMaskBounds"); + vTexPaletteAtlas = GetAttributeLocation("ivTexPaletteAtlas"); + vTexPaletteBounds = GetAttributeLocation("ivTexPaletteBounds"); vFlags = GetAttributeLocation("ivFlags"); vColour = GetAttributeLocation("ivColour"); vBounds = GetAttributeLocation("ivBounds"); diff --git a/src/drawing/engines/opengl/DrawImageShader.h b/src/drawing/engines/opengl/DrawImageShader.h index f4609bf581..5444232f88 100644 --- a/src/drawing/engines/opengl/DrawImageShader.h +++ b/src/drawing/engines/opengl/DrawImageShader.h @@ -28,6 +28,8 @@ struct DrawImageInstance { vec4f texColourBounds; int texMaskAtlas; vec4f texMaskBounds; + int texPaletteAtlas; + vec4f texPaletteBounds; int flags; vec4f colour; vec4i bounds; @@ -47,6 +49,8 @@ private: GLuint vTexColourBounds; GLuint vTexMaskAtlas; GLuint vTexMaskBounds; + GLuint vTexPaletteAtlas; + GLuint vTexPaletteBounds; GLuint vFlags; GLuint vColour; GLuint vBounds; diff --git a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp index fd50fdd189..10b6e69f34 100644 --- a/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp +++ b/src/drawing/engines/opengl/OpenGLDrawingEngine.cpp @@ -720,6 +720,28 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t auto texture = _textureCache->GetOrLoadImageTexture(image); command.texColour = texture; + bool special = false; + if (!(image & IMAGE_TYPE_REMAP_2_PLUS) && (image & IMAGE_TYPE_REMAP)) { + if (((image >> 19) & 0x7F) == 32) { + special = true; + } + } + + if (!((image & IMAGE_TYPE_REMAP_2_PLUS) && !(image & IMAGE_TYPE_REMAP))) { + tertiaryColour = 0; + } + + texture = _textureCache->GetOrLoadPaletteTexture(image, tertiaryColour, special); + command.texPalette = texture; + + if (image & IMAGE_TYPE_TRANSPARENT) { + command.flags |= (1 << 3); + } + else if (image & (IMAGE_TYPE_REMAP_2_PLUS | IMAGE_TYPE_REMAP)){ + command.flags |= (1 << 1); + } + command.flags |= special << 2; + command.bounds[0] = left; command.bounds[1] = top; command.bounds[2] = right; @@ -955,6 +977,15 @@ void OpenGLDrawingContext::FlushImages() instance.colour = command.colour; instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]}; instance.mask = command.mask; + instance.texPaletteAtlas = command.texPalette.index; + if (instance.flags != 0) { + instance.texPaletteBounds = { + command.texPalette.normalizedBounds.x, + command.texPalette.normalizedBounds.y, + (command.texPalette.normalizedBounds.z - command.texPalette.normalizedBounds.x) / (float)(command.texPalette.bounds.z - command.texPalette.bounds.x), + (command.texPalette.normalizedBounds.w - command.texPalette.normalizedBounds.y) / (float)(command.texPalette.bounds.w - command.texPalette.bounds.y) + }; + } instances.push_back(instance); } diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index d911db2099..3b424fc213 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -52,14 +52,48 @@ void TextureCache::InvalidateImage(uint32 image) CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image) { - auto kvp = _imageTextureMap.find(image & 0x7FFFF); + image &= 0x7FFFF; + auto kvp = _imageTextureMap.find(image); if (kvp != _imageTextureMap.end()) { return kvp->second; } auto cacheInfo = LoadImageTexture(image); - _imageTextureMap[image & 0x7FFFF] = cacheInfo; + _imageTextureMap[image] = cacheInfo; + + return cacheInfo; +} + +CachedTextureInfo TextureCache::GetOrLoadPaletteTexture(uint32 image, uint32 tertiaryColour, bool special) +{ + if ((image & (IMAGE_TYPE_REMAP | IMAGE_TYPE_REMAP_2_PLUS | IMAGE_TYPE_TRANSPARENT)) == 0) + return CachedTextureInfo{ 0 }; + + uint32 uniquePaletteId = 0; + if (!(image & IMAGE_TYPE_REMAP_2_PLUS)) { + uniquePaletteId = (image >> 19) & 0xFF; + if (!(image & IMAGE_TYPE_TRANSPARENT)) { + uniquePaletteId &= 0x7F; + } + } + else { + uniquePaletteId |= ((image >> 19) & 0x1F); + uniquePaletteId |= ((image >> 24) & 0x1F) << 8; + + if (!(image & IMAGE_TYPE_REMAP)) { + uniquePaletteId |= tertiaryColour << 16; + } + } + + auto kvp = _paletteTextureMap.find(uniquePaletteId); + if (kvp != _paletteTextureMap.end()) + { + return kvp->second; + } + + auto cacheInfo = LoadPaletteTexture(image, tertiaryColour, special); + _paletteTextureMap[uniquePaletteId] = cacheInfo; return cacheInfo; } @@ -141,6 +175,20 @@ CachedTextureInfo TextureCache::LoadImageTexture(uint32 image) return cacheInfo; } +CachedTextureInfo TextureCache::LoadPaletteTexture(uint32 image, uint32 tertiaryColour, bool special) +{ + rct_drawpixelinfo dpi; + dpi.bits = gfx_draw_sprite_get_palette(image, tertiaryColour); + dpi.width = 256; + dpi.height = special ? 5 : 1; + auto cacheInfo = AllocateImage(dpi.width, dpi.height); + + glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi.width, dpi.height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi.bits); + + return cacheInfo; +} + CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette) { rct_drawpixelinfo * dpi = GetGlyphAsDPI(image, palette); diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 864945556c..3092b0aa1f 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -196,6 +196,7 @@ private: std::unordered_map _imageTextureMap; std::unordered_map _glyphTextureMap; + std::unordered_map _paletteTextureMap; SDL_Color _palette[256]; @@ -206,7 +207,8 @@ public: void InvalidateImage(uint32 image); CachedTextureInfo GetOrLoadImageTexture(uint32 image); CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette); - + CachedTextureInfo GetOrLoadPaletteTexture(uint32 image, uint32 tertiaryColour, bool special); + GLuint GetAtlasesTexture(); private: @@ -214,6 +216,7 @@ private: void EnlargeAtlasesTexture(GLuint newEntries); CachedTextureInfo LoadImageTexture(uint32 image); CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette); + CachedTextureInfo LoadPaletteTexture(uint32 image, uint32 tertiaryColour, bool special); CachedTextureInfo AllocateImage(int imageWidth, int imageHeight); void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight); rct_drawpixelinfo * GetImageAsDPI(uint32 image, uint32 tertiaryColour); diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c index 6b74dbe34d..495e6a4c21 100644 --- a/src/drawing/sprite.c +++ b/src/drawing/sprite.c @@ -292,7 +292,7 @@ static void FASTCALL gfx_bmp_sprite_to_buffer(uint8* palette_pointer, uint8* unk return; } -static uint8* FASTCALL gfx_draw_sprite_get_palette(int image_id, uint32 tertiary_colour) { +uint8* FASTCALL gfx_draw_sprite_get_palette(int image_id, uint32 tertiary_colour) { int image_type = (image_id & 0xE0000000); if (image_type == 0) return NULL; diff --git a/src/paint/paint.c b/src/paint/paint.c index a02c6d5965..0bdb09445b 100644 --- a/src/paint/paint.c +++ b/src/paint/paint.c @@ -176,7 +176,6 @@ static paint_struct * sub_9819_c(uint32 image_id, rct_xyz16 offset, rct_xyz16 bo ps->map_x = gPaintMapPosition.x; ps->map_y = gPaintMapPosition.y; ps->mapElement = g_currently_drawn_item; - return ps; }