mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #4147 from Overv/opengl-optimization
Optimise the OpenGL drawing engine by batching the drawing of sprites.
This commit is contained in:
commit
0cd0eb5ec5
|
@ -119,7 +119,6 @@
|
|||
D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; };
|
||||
D41B74731C2125E50080A7B9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D41B74721C2125E50080A7B9 /* Assets.xcassets */; };
|
||||
D43407D61D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */; };
|
||||
D43407D71D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */; };
|
||||
D43407D81D0E14BE00C2B3D4 /* DrawImageShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */; };
|
||||
D43407D91D0E14BE00C2B3D4 /* DrawLineShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */; };
|
||||
D43407DA1D0E14BE00C2B3D4 /* FillRectShader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D43407C81D0E14BE00C2B3D4 /* FillRectShader.cpp */; };
|
||||
|
@ -504,8 +503,6 @@
|
|||
D41B74721C2125E50080A7B9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = distribution/osx/Assets.xcassets; sourceTree = SOURCE_ROOT; };
|
||||
D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopyFramebufferShader.cpp; sourceTree = "<group>"; };
|
||||
D43407C11D0E14BE00C2B3D4 /* CopyFramebufferShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopyFramebufferShader.h; sourceTree = "<group>"; };
|
||||
D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawImageMaskedShader.cpp; sourceTree = "<group>"; };
|
||||
D43407C31D0E14BE00C2B3D4 /* DrawImageMaskedShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawImageMaskedShader.h; sourceTree = "<group>"; };
|
||||
D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawImageShader.cpp; sourceTree = "<group>"; };
|
||||
D43407C51D0E14BE00C2B3D4 /* DrawImageShader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DrawImageShader.h; sourceTree = "<group>"; };
|
||||
D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DrawLineShader.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1300,8 +1297,6 @@
|
|||
children = (
|
||||
D43407C01D0E14BE00C2B3D4 /* CopyFramebufferShader.cpp */,
|
||||
D43407C11D0E14BE00C2B3D4 /* CopyFramebufferShader.h */,
|
||||
D43407C21D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp */,
|
||||
D43407C31D0E14BE00C2B3D4 /* DrawImageMaskedShader.h */,
|
||||
D43407C41D0E14BE00C2B3D4 /* DrawImageShader.cpp */,
|
||||
D43407C51D0E14BE00C2B3D4 /* DrawImageShader.h */,
|
||||
D43407C61D0E14BE00C2B3D4 /* DrawLineShader.cpp */,
|
||||
|
@ -2410,7 +2405,6 @@
|
|||
C686F9311CDBC3B7009F9BFC /* ghost_train.c in Sources */,
|
||||
D44272821CC81B3200D84D28 /* shortcut_key_change.c in Sources */,
|
||||
D442722A1CC81B3200D84D28 /* localisation.c in Sources */,
|
||||
D43407D71D0E14BE00C2B3D4 /* DrawImageMaskedShader.cpp in Sources */,
|
||||
D44272731CC81B3200D84D28 /* new_ride.c in Sources */,
|
||||
D442721A1CC81B3200D84D28 /* console.c in Sources */,
|
||||
D44271FB1CC81B3200D84D28 /* ScreenshotCommands.cpp in Sources */,
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
#version 150
|
||||
|
||||
uniform ivec4 uClip;
|
||||
uniform int uFlags;
|
||||
uniform vec4 uColour;
|
||||
uniform usampler2D uTexture;
|
||||
uniform vec4 uPalette[256];
|
||||
uniform vec4 uPalette[256];
|
||||
uniform usampler2DArray uTexture;
|
||||
|
||||
flat in ivec4 fClip;
|
||||
flat in int fFlags;
|
||||
in vec4 fColour;
|
||||
flat in int fTexColourAtlas;
|
||||
in vec2 fTexColourCoords;
|
||||
flat in int fTexMaskAtlas;
|
||||
in vec2 fTexMaskCoords;
|
||||
flat in int fMask;
|
||||
|
||||
in vec2 fPosition;
|
||||
in vec2 fTextureCoordinate;
|
||||
|
@ -13,19 +19,28 @@ out vec4 oColour;
|
|||
|
||||
void main()
|
||||
{
|
||||
if (fPosition.x < uClip.x || fPosition.x > uClip.z ||
|
||||
fPosition.y < uClip.y || fPosition.y > uClip.w)
|
||||
if (fPosition.x < fClip.x || fPosition.x > fClip.z ||
|
||||
fPosition.y < fClip.y || fPosition.y > fClip.w)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 texel = uPalette[texture(uTexture, fTextureCoordinate).r];
|
||||
if ((uFlags & 1) != 0)
|
||||
vec4 texel = uPalette[texture(uTexture, vec3(fTexColourCoords, float(fTexColourAtlas))).r];
|
||||
vec4 mask = uPalette[texture(uTexture, vec3(fTexMaskCoords, float(fTexMaskAtlas))).r];
|
||||
|
||||
if (fMask != 0)
|
||||
{
|
||||
oColour = vec4(uColour.rgb, uColour.a * texel.a);
|
||||
oColour = texel * mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
oColour = texel;
|
||||
if ((fFlags & 1) != 0)
|
||||
{
|
||||
oColour = vec4(fColour.rgb, fColour.a * texel.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
oColour = texel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,33 +1,53 @@
|
|||
#version 150
|
||||
|
||||
uniform ivec2 uScreenSize;
|
||||
uniform ivec4 uBounds;
|
||||
uniform ivec4 uTextureCoordinates;
|
||||
|
||||
in ivec4 ivClip;
|
||||
in int ivTexColourAtlas;
|
||||
in vec4 ivTexColourBounds;
|
||||
in int ivTexMaskAtlas;
|
||||
in vec4 ivTexMaskBounds;
|
||||
in int ivFlags;
|
||||
in vec4 ivColour;
|
||||
in ivec4 ivBounds;
|
||||
in int ivMask;
|
||||
|
||||
in uint vIndex;
|
||||
|
||||
out vec2 fPosition;
|
||||
out vec2 fTextureCoordinate;
|
||||
out vec2 fTextureCoordinate;
|
||||
out vec2 fPosition;
|
||||
flat out ivec4 fClip;
|
||||
flat out int fFlags;
|
||||
out vec4 fColour;
|
||||
flat out int fTexColourAtlas;
|
||||
out vec2 fTexColourCoords;
|
||||
flat out int fTexMaskAtlas;
|
||||
out vec2 fTexMaskCoords;
|
||||
flat out int fMask;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos;
|
||||
switch (vIndex) {
|
||||
case 0u:
|
||||
pos = uBounds.xy;
|
||||
fTextureCoordinate = uTextureCoordinates.xy;
|
||||
pos = ivBounds.xy;
|
||||
fTexColourCoords = ivTexColourBounds.xy;
|
||||
fTexMaskCoords = ivTexMaskBounds.xy;
|
||||
break;
|
||||
case 1u:
|
||||
pos = uBounds.zy;
|
||||
fTextureCoordinate = uTextureCoordinates.zy;
|
||||
pos = ivBounds.zy;
|
||||
fTexColourCoords = ivTexColourBounds.zy;
|
||||
fTexMaskCoords = ivTexMaskBounds.zy;
|
||||
break;
|
||||
case 2u:
|
||||
pos = uBounds.xw;
|
||||
fTextureCoordinate = uTextureCoordinates.xw;
|
||||
pos = ivBounds.xw;
|
||||
fTexColourCoords = ivTexColourBounds.xw;
|
||||
fTexMaskCoords = ivTexMaskBounds.xw;
|
||||
break;
|
||||
case 3u:
|
||||
pos = uBounds.zw;
|
||||
fTextureCoordinate = uTextureCoordinates.zw;
|
||||
pos = ivBounds.zw;
|
||||
fTexColourCoords = ivTexColourBounds.zw;
|
||||
fTexMaskCoords = ivTexMaskBounds.zw;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -38,5 +58,12 @@ void main()
|
|||
pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0;
|
||||
pos.y *= -1;
|
||||
|
||||
fClip = ivClip;
|
||||
fFlags = ivFlags;
|
||||
fColour = ivColour;
|
||||
fMask = ivMask;
|
||||
fTexColourAtlas = ivTexColourAtlas;
|
||||
fTexMaskAtlas = ivTexMaskAtlas;
|
||||
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#version 150
|
||||
|
||||
uniform ivec4 uClip;
|
||||
uniform usampler2D uTextureMask;
|
||||
uniform usampler2D uTextureColour;
|
||||
uniform vec4 uPalette[256];
|
||||
|
||||
in vec2 fPosition;
|
||||
in vec2 fTextureCoordinate;
|
||||
|
||||
out vec4 oColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (fPosition.x < uClip.x || fPosition.x > uClip.z ||
|
||||
fPosition.y < uClip.y || fPosition.y > uClip.w)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
|
||||
vec4 mask = uPalette[texture(uTextureMask, fTextureCoordinate).r];
|
||||
vec4 colour = uPalette[texture(uTextureColour, fTextureCoordinate).r];
|
||||
oColour = colour * mask;
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
#version 150
|
||||
|
||||
uniform ivec2 uScreenSize;
|
||||
uniform ivec4 uBounds;
|
||||
|
||||
in uint vIndex;
|
||||
|
||||
out vec2 fPosition;
|
||||
out vec2 fTextureCoordinate;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos;
|
||||
switch (vIndex) {
|
||||
case 0u:
|
||||
pos = uBounds.xy;
|
||||
fTextureCoordinate = vec2(0, 0);
|
||||
break;
|
||||
case 1u:
|
||||
pos = uBounds.zy;
|
||||
fTextureCoordinate = vec2(1, 0);
|
||||
break;
|
||||
case 2u:
|
||||
pos = uBounds.xw;
|
||||
fTextureCoordinate = vec2(0, 1);
|
||||
break;
|
||||
case 3u:
|
||||
pos = uBounds.zw;
|
||||
fTextureCoordinate = vec2(1, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
fPosition = pos;
|
||||
|
||||
// Transform screen coordinates to viewport
|
||||
pos.x = (pos.x * (2.0 / uScreenSize.x)) - 1.0;
|
||||
pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0;
|
||||
pos.y *= -1;
|
||||
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
- Feature: Objects directory is scanned recursively.
|
||||
- Improve: Performance and reliability of loading objects.
|
||||
- Improve: Screenshots are now saved with the name of the park and the current date and time.
|
||||
- Improve: More accurate frame rate calculation
|
||||
- Removed: BMP screenshots.
|
||||
- Removed: Intamin and Phoenix easter eggs.
|
||||
- Fix: [#1038] Guest List is out of order.
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
<ClCompile Include="src\drawing\drawing.c" />
|
||||
<ClCompile Include="src\drawing\drawing_fast.cpp" />
|
||||
<ClCompile Include="src\drawing\engines\opengl\CopyFramebufferShader.cpp" />
|
||||
<ClCompile Include="src\drawing\engines\opengl\DrawImageMaskedShader.cpp" />
|
||||
<ClCompile Include="src\drawing\engines\opengl\DrawImageShader.cpp" />
|
||||
<ClCompile Include="src\drawing\engines\opengl\DrawLineShader.cpp" />
|
||||
<ClCompile Include="src\drawing\engines\opengl\FillRectShader.cpp" />
|
||||
|
@ -383,7 +382,7 @@
|
|||
<ClInclude Include="src\drawing\drawing.h" />
|
||||
<ClInclude Include="src\drawing\engines\OpenGLAPI.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\CopyFramebufferShader.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\DrawImageMaskedShader.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\DrawCommands.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\DrawImageShader.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\DrawLineShader.h" />
|
||||
<ClInclude Include="src\drawing\engines\opengl\FillRectShader.h" />
|
||||
|
|
|
@ -41,6 +41,8 @@ interface IDrawingEngine
|
|||
virtual void Resize(uint32 width, uint32 height) abstract;
|
||||
virtual void SetPalette(SDL_Color * colours) abstract;
|
||||
|
||||
virtual void SetUncappedFrameRate(bool uncapped) abstract;
|
||||
|
||||
virtual void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) abstract;
|
||||
virtual void Draw() abstract;
|
||||
virtual void CopyRect(sint32 x, sint32 y, sint32 width, sint32 height, sint32 dx, sint32 dy) abstract;
|
||||
|
|
|
@ -83,6 +83,7 @@ extern "C"
|
|||
try
|
||||
{
|
||||
_drawingEngine->Initialise(gWindow);
|
||||
_drawingEngine->SetUncappedFrameRate(gConfigGeneral.uncap_fps == 1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
@ -164,6 +165,14 @@ extern "C"
|
|||
}
|
||||
}
|
||||
|
||||
void drawing_engine_set_fps_uncapped(bool uncapped)
|
||||
{
|
||||
if (_drawingEngine != nullptr)
|
||||
{
|
||||
_drawingEngine->SetUncappedFrameRate(uncapped);
|
||||
}
|
||||
}
|
||||
|
||||
void gfx_set_dirty_blocks(sint16 left, sint16 top, sint16 right, sint16 bottom)
|
||||
{
|
||||
if (_drawingEngine != nullptr)
|
||||
|
|
|
@ -33,6 +33,7 @@ void drawing_engine_dispose();
|
|||
rct_drawpixelinfo * drawing_engine_get_dpi();
|
||||
bool drawing_engine_has_dirty_optimisations();
|
||||
void drawing_engine_invalidate_image(uint32 image);
|
||||
void drawing_engine_set_fps_uncapped(bool uncapped);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -327,6 +327,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void SetUncappedFrameRate(bool uncapped) override
|
||||
{
|
||||
// Not applicable for this engine
|
||||
}
|
||||
|
||||
void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override
|
||||
{
|
||||
left = Math::Max(left, 0);
|
||||
|
|
|
@ -71,7 +71,7 @@ void CopyFramebufferShader::SetTextureCoordinates(sint32 left, sint32 top, sint3
|
|||
|
||||
void CopyFramebufferShader::SetTexture(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture2D(0, texture);
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
void CopyFramebufferShader::Draw()
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../../../common.h"
|
||||
#include "OpenGLAPI.h"
|
||||
#include "GLSLTypes.h"
|
||||
|
||||
struct DrawRectCommand {
|
||||
uint32 flags;
|
||||
GLuint sourceFramebuffer;
|
||||
vec4f colours[2];
|
||||
sint32 clip[4];
|
||||
sint32 bounds[4];
|
||||
};
|
||||
|
||||
struct DrawLineCommand {
|
||||
vec4f colour;
|
||||
sint32 clip[4];
|
||||
sint32 pos[4];
|
||||
};
|
||||
|
||||
struct DrawImageCommand {
|
||||
uint32 flags;
|
||||
vec4f colour;
|
||||
sint32 clip[4];
|
||||
CachedTextureInfo texMask;
|
||||
CachedTextureInfo texColour;
|
||||
sint32 bounds[4];
|
||||
bool mask;
|
||||
};
|
|
@ -1,99 +0,0 @@
|
|||
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include "DrawImageMaskedShader.h"
|
||||
|
||||
DrawImageMaskedShader::DrawImageMaskedShader() : OpenGLShaderProgram("drawimagemasked")
|
||||
{
|
||||
GetLocations();
|
||||
|
||||
glGenBuffers(1, &_vbo);
|
||||
glGenVertexArrays(1, &_vao);
|
||||
|
||||
GLuint vertices[] = { 0, 1, 2, 2, 1, 3 };
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glEnableVertexAttribArray(vIndex);
|
||||
glVertexAttribIPointer(vIndex, 1, GL_INT, 0, 0);
|
||||
|
||||
Use();
|
||||
glUniform1i(uTextureMask, 0);
|
||||
glUniform1i(uTextureColour, 1);
|
||||
}
|
||||
|
||||
DrawImageMaskedShader::~DrawImageMaskedShader()
|
||||
{
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
glDeleteVertexArrays(1, &_vao);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::GetLocations()
|
||||
{
|
||||
uScreenSize = GetUniformLocation("uScreenSize");
|
||||
uClip = GetUniformLocation("uClip");
|
||||
uBounds = GetUniformLocation("uBounds");
|
||||
uTextureMask = GetUniformLocation("uTextureMask");
|
||||
uTextureColour = GetUniformLocation("uTextureColour");
|
||||
uPalette = GetUniformLocation("uPalette");
|
||||
|
||||
vIndex = GetAttributeLocation("vIndex");
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetScreenSize(sint32 width, sint32 height)
|
||||
{
|
||||
glUniform2i(uScreenSize, width, height);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uClip, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uBounds, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetTextureMask(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture2D(0, texture);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetTextureColour(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture2D(1, texture);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::SetPalette(const vec4f *glPalette)
|
||||
{
|
||||
glUniform4fv(uPalette, 256, (const GLfloat *) glPalette);
|
||||
}
|
||||
|
||||
void DrawImageMaskedShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
SetBounds(left, top, right, bottom);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
|
@ -1,52 +0,0 @@
|
|||
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
||||
/*****************************************************************************
|
||||
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
||||
*
|
||||
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
||||
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* A full copy of the GNU General Public License can be found in licence.txt
|
||||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include <SDL_pixels.h>
|
||||
|
||||
class DrawImageMaskedShader : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
GLuint uClip;
|
||||
GLuint uBounds;
|
||||
GLuint uTextureMask;
|
||||
GLuint uTextureColour;
|
||||
GLuint uPalette;
|
||||
|
||||
GLuint vIndex;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
|
||||
public:
|
||||
DrawImageMaskedShader();
|
||||
~DrawImageMaskedShader() override;
|
||||
|
||||
void SetScreenSize(sint32 width, sint32 height);
|
||||
void SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetTextureMask(GLuint texture);
|
||||
void SetTextureColour(GLuint texture);
|
||||
void SetPalette(const vec4f *glPalette);
|
||||
void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
|
@ -23,6 +23,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
|
|||
GetLocations();
|
||||
|
||||
glGenBuffers(1, &_vbo);
|
||||
glGenBuffers(1, &_vboInstances);
|
||||
glGenVertexArrays(1, &_vao);
|
||||
|
||||
GLuint vertices[] = { 0, 1, 2, 2, 1, 3 };
|
||||
|
@ -30,18 +31,49 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
|
|||
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glEnableVertexAttribArray(vIndex);
|
||||
|
||||
glVertexAttribIPointer(vIndex, 1, GL_INT, 0, nullptr);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboInstances);
|
||||
glVertexAttribIPointer(vClip, 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip));
|
||||
glVertexAttribIPointer(vTexColourAtlas, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texColourAtlas));
|
||||
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(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));
|
||||
glVertexAttribIPointer(vMask, 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, mask));
|
||||
|
||||
glEnableVertexAttribArray(vIndex);
|
||||
glEnableVertexAttribArray(vClip);
|
||||
glEnableVertexAttribArray(vTexColourAtlas);
|
||||
glEnableVertexAttribArray(vTexColourBounds);
|
||||
glEnableVertexAttribArray(vTexMaskAtlas);
|
||||
glEnableVertexAttribArray(vTexMaskBounds);
|
||||
glEnableVertexAttribArray(vFlags);
|
||||
glEnableVertexAttribArray(vColour);
|
||||
glEnableVertexAttribArray(vBounds);
|
||||
glEnableVertexAttribArray(vMask);
|
||||
|
||||
glVertexAttribDivisor(vClip, 1);
|
||||
glVertexAttribDivisor(vTexColourAtlas, 1);
|
||||
glVertexAttribDivisor(vTexColourBounds, 1);
|
||||
glVertexAttribDivisor(vTexMaskAtlas, 1);
|
||||
glVertexAttribDivisor(vTexMaskBounds, 1);
|
||||
glVertexAttribDivisor(vFlags, 1);
|
||||
glVertexAttribDivisor(vColour, 1);
|
||||
glVertexAttribDivisor(vBounds, 1);
|
||||
glVertexAttribDivisor(vMask, 1);
|
||||
|
||||
Use();
|
||||
SetFlags(0);
|
||||
SetTextureCoordinates(0, 0, 1, 1);
|
||||
glUniform1i(uTexture, 0);
|
||||
}
|
||||
|
||||
DrawImageShader::~DrawImageShader()
|
||||
{
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
glDeleteBuffers(1, &_vboInstances);
|
||||
glDeleteVertexArrays(1, &_vao);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
|
@ -50,15 +82,19 @@ DrawImageShader::~DrawImageShader()
|
|||
void DrawImageShader::GetLocations()
|
||||
{
|
||||
uScreenSize = GetUniformLocation("uScreenSize");
|
||||
uClip = GetUniformLocation("uClip");
|
||||
uBounds = GetUniformLocation("uBounds");
|
||||
uTextureCoordinates = GetUniformLocation("uTextureCoordinates");
|
||||
uTexture = GetUniformLocation("uTexture");
|
||||
uColour = GetUniformLocation("uColour");
|
||||
uFlags = GetUniformLocation("uFlags");
|
||||
uPalette = GetUniformLocation("uPalette");
|
||||
|
||||
vIndex = GetAttributeLocation("vIndex");
|
||||
vClip = GetAttributeLocation("ivClip");
|
||||
vTexColourAtlas = GetAttributeLocation("ivTexColourAtlas");
|
||||
vTexColourBounds = GetAttributeLocation("ivTexColourBounds");
|
||||
vTexMaskAtlas = GetAttributeLocation("ivTexMaskAtlas");
|
||||
vTexMaskBounds = GetAttributeLocation("ivTexMaskBounds");
|
||||
vFlags = GetAttributeLocation("ivFlags");
|
||||
vColour = GetAttributeLocation("ivColour");
|
||||
vBounds = GetAttributeLocation("ivBounds");
|
||||
vMask = GetAttributeLocation("ivMask");
|
||||
}
|
||||
|
||||
void DrawImageShader::SetScreenSize(sint32 width, sint32 height)
|
||||
|
@ -66,47 +102,19 @@ void DrawImageShader::SetScreenSize(sint32 width, sint32 height)
|
|||
glUniform2i(uScreenSize, width, height);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uClip, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uBounds, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uTextureCoordinates, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetTexture(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture2D(0, texture);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetColour(vec4f colour)
|
||||
{
|
||||
glUniform4f(uColour, colour.r, colour.g, colour.b, colour.a);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetFlags(uint32 flags)
|
||||
{
|
||||
glUniform1i(uFlags, flags);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetPalette(const vec4f *glPalette)
|
||||
{
|
||||
glUniform4fv(uPalette, 256, (const GLfloat *) glPalette);
|
||||
}
|
||||
|
||||
void DrawImageShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
void DrawImageShader::DrawInstances(const std::vector<DrawImageInstance>& instances)
|
||||
{
|
||||
SetBounds(left, top, right, bottom);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboInstances);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(instances[0]) * instances.size(), instances.data(), GL_STREAM_DRAW);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size());
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -19,22 +19,41 @@
|
|||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include <SDL_pixels.h>
|
||||
#include <vector>
|
||||
|
||||
// Per-instance data for images
|
||||
struct DrawImageInstance {
|
||||
vec4i clip;
|
||||
int texColourAtlas;
|
||||
vec4f texColourBounds;
|
||||
int texMaskAtlas;
|
||||
vec4f texMaskBounds;
|
||||
int flags;
|
||||
vec4f colour;
|
||||
vec4i bounds;
|
||||
int mask;
|
||||
};
|
||||
|
||||
class DrawImageShader : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
GLuint uClip;
|
||||
GLuint uBounds;
|
||||
GLuint uTextureCoordinates;
|
||||
GLuint uTexture;
|
||||
GLuint uColour;
|
||||
GLuint uFlags;
|
||||
GLuint uPalette;
|
||||
|
||||
GLuint vIndex;
|
||||
GLuint vClip;
|
||||
GLuint vTexColourAtlas;
|
||||
GLuint vTexColourBounds;
|
||||
GLuint vTexMaskAtlas;
|
||||
GLuint vTexMaskBounds;
|
||||
GLuint vFlags;
|
||||
GLuint vColour;
|
||||
GLuint vBounds;
|
||||
GLuint vMask;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
|
||||
SDL_Color _palette[256];
|
||||
|
@ -44,14 +63,8 @@ public:
|
|||
~DrawImageShader() override;
|
||||
|
||||
void SetScreenSize(sint32 width, sint32 height);
|
||||
void SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetTexture(GLuint texture);
|
||||
void SetColour(vec4f colour);
|
||||
void SetFlags(uint32 flags);
|
||||
void SetPalette(const vec4f *glPalette);
|
||||
void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void DrawInstances(const std::vector<DrawImageInstance>& instances);
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
|
|
|
@ -87,7 +87,8 @@ void FillRectShader::SetColour(int index, vec4f colour)
|
|||
|
||||
void FillRectShader::SetSourceFramebuffer(GLuint texture)
|
||||
{
|
||||
OpenGLAPI::SetTexture2D(0, texture);
|
||||
_sourceFramebuffer = texture;
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, texture);
|
||||
}
|
||||
|
||||
void FillRectShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
|
@ -98,4 +99,8 @@ void FillRectShader::Draw(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
|||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
}
|
||||
|
||||
GLuint FillRectShader::GetSourceFramebuffer() const {
|
||||
return _sourceFramebuffer;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -36,6 +36,8 @@ private:
|
|||
GLuint _vbo;
|
||||
GLuint _vao;
|
||||
|
||||
GLuint _sourceFramebuffer = 0;
|
||||
|
||||
public:
|
||||
FillRectShader();
|
||||
~FillRectShader() override;
|
||||
|
@ -49,6 +51,8 @@ public:
|
|||
|
||||
void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
|
||||
GLuint GetSourceFramebuffer() const;
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
};
|
||||
|
|
|
@ -68,6 +68,10 @@ static const char * TryLoadAllProcAddresses()
|
|||
SetupOpenGLFunction(glTexImage2D);
|
||||
SetupOpenGLFunction(glTexParameteri);
|
||||
SetupOpenGLFunction(glViewport);
|
||||
SetupOpenGLFunction(glTexSubImage3D);
|
||||
SetupOpenGLFunction(glTexImage3D);
|
||||
SetupOpenGLFunction(glGetIntegerv);
|
||||
SetupOpenGLFunction(glGetTexImage);
|
||||
|
||||
// 2.0+ functions
|
||||
SetupOpenGLFunction(glAttachShader);
|
||||
|
@ -100,12 +104,15 @@ static const char * TryLoadAllProcAddresses()
|
|||
SetupOpenGLFunction(glShaderSource);
|
||||
SetupOpenGLFunction(glUniform1i);
|
||||
SetupOpenGLFunction(glUniform2i);
|
||||
SetupOpenGLFunction(glUniform2f);
|
||||
SetupOpenGLFunction(glUniform4f);
|
||||
SetupOpenGLFunction(glUniform4i);
|
||||
SetupOpenGLFunction(glUniform4fv);
|
||||
SetupOpenGLFunction(glUseProgram);
|
||||
SetupOpenGLFunction(glVertexAttribIPointer);
|
||||
SetupOpenGLFunction(glVertexAttribPointer);
|
||||
SetupOpenGLFunction(glDrawArraysInstanced);
|
||||
SetupOpenGLFunction(glVertexAttribDivisor);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -118,13 +125,13 @@ namespace OpenGLState
|
|||
GLuint CurrentProgram = UINT32_MAX;
|
||||
}
|
||||
|
||||
void OpenGLAPI::SetTexture2D(uint16 index, GLuint texture)
|
||||
void OpenGLAPI::SetTexture(uint16 index, GLenum type, GLuint texture)
|
||||
{
|
||||
if (OpenGLState::ActiveTexture != index)
|
||||
{
|
||||
glActiveTexture(GL_TEXTURE0 + index);
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glBindTexture(type, texture);
|
||||
}
|
||||
|
||||
bool OpenGLAPI::Initialise()
|
||||
|
|
|
@ -40,6 +40,10 @@
|
|||
#define glTexImage2D __static__glTexImage2D
|
||||
#define glTexParameteri __static__glTexParameteri
|
||||
#define glViewport __static__glViewport
|
||||
#define glTexSubImage3D __static__glTexSubImage3D
|
||||
#define glTexImage3D __static__glTexImage3D
|
||||
#define glGetIntegerv __static__glGetIntegerv
|
||||
#define glGetTexImage __static__glGetTexImage
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -67,6 +71,10 @@
|
|||
#undef glTexImage2D
|
||||
#undef glTexParameteri
|
||||
#undef glViewport
|
||||
#undef glTexSubImage3D
|
||||
#undef glTexImage3D
|
||||
#undef glGetIntegerv
|
||||
#undef glGetTexImage
|
||||
|
||||
// 1.1 function signatures
|
||||
typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode);
|
||||
|
@ -87,6 +95,10 @@ typedef void (APIENTRYP PFNGLREADPIXELSPROC )(GLint x, GLint y, GLsizei wid
|
|||
typedef void (APIENTRYP PFNGLTEXIMAGE2DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
|
||||
typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC )(GLenum target, GLenum pname, GLint param);
|
||||
typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data);
|
||||
typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data);
|
||||
typedef void (APIENTRYP PFNGLGETINTERGERVPROC )(GLenum pname, GLint * data);
|
||||
typedef void (APIENTRYP PFNGLGETTEXIMAGEPROC )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid * img);
|
||||
|
||||
#ifdef NO_EXTERN_GLAPI
|
||||
// Defines the function pointers
|
||||
|
@ -118,6 +130,10 @@ GLAPI_DECL PFNGLREADPIXELSPROC glReadPixels GLAP
|
|||
GLAPI_DECL PFNGLTEXIMAGE2DPROC glTexImage2D GLAPI_SET;
|
||||
GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAPI_SET;
|
||||
GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET;
|
||||
GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET;
|
||||
GLAPI_DECL PFNGLTEXIMAGE3DPROC glTexImage3D GLAPI_SET;
|
||||
GLAPI_DECL PFNGLGETINTERGERVPROC glGetIntegerv GLAPI_SET;
|
||||
GLAPI_DECL PFNGLGETTEXIMAGEPROC glGetTexImage GLAPI_SET;
|
||||
|
||||
// 2.0+ function pointers
|
||||
GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET;
|
||||
|
@ -150,12 +166,15 @@ GLAPI_DECL PFNGLLINKPROGRAMPROC glLinkProgram GLAP
|
|||
GLAPI_DECL PFNGLSHADERSOURCEPROC glShaderSource GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM1IPROC glUniform1i GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM2IPROC glUniform2i GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM2FPROC glUniform2f GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM4FPROC glUniform4f GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM4IPROC glUniform4i GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUNIFORM4FVPROC glUniform4fv GLAPI_SET;
|
||||
GLAPI_DECL PFNGLUSEPROGRAMPROC glUseProgram GLAPI_SET;
|
||||
GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAPI_SET;
|
||||
GLAPI_DECL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer GLAPI_SET;
|
||||
GLAPI_DECL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced GLAPI_SET;
|
||||
GLAPI_DECL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor GLAPI_SET;
|
||||
|
||||
#endif /* OPENGL_NO_LINK */
|
||||
|
||||
|
@ -172,7 +191,7 @@ inline void CheckGLError()
|
|||
namespace OpenGLAPI
|
||||
{
|
||||
bool Initialise();
|
||||
void SetTexture2D(uint16 index, GLuint texture);
|
||||
void SetTexture(uint16 index, GLenum type, GLuint texture);
|
||||
}
|
||||
|
||||
namespace OpenGLState
|
||||
|
|
|
@ -34,11 +34,11 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL()
|
|||
#include "OpenGLFramebuffer.h"
|
||||
#include "CopyFramebufferShader.h"
|
||||
#include "DrawImageShader.h"
|
||||
#include "DrawImageMaskedShader.h"
|
||||
#include "DrawLineShader.h"
|
||||
#include "FillRectShader.h"
|
||||
#include "SwapFramebuffer.h"
|
||||
#include "TextureCache.h"
|
||||
#include "DrawCommands.h"
|
||||
|
||||
#include "../../../core/Console.hpp"
|
||||
#include "../../../core/Exception.hpp"
|
||||
|
@ -47,6 +47,7 @@ IDrawingEngine * DrawingEngineFactory::CreateOpenGL()
|
|||
#include "../../IDrawingContext.h"
|
||||
#include "../../IDrawingEngine.h"
|
||||
#include "../../Rain.h"
|
||||
#include "../../../config.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
@ -63,7 +64,7 @@ struct OpenGLVersion
|
|||
GLint Minor;
|
||||
};
|
||||
|
||||
constexpr OpenGLVersion OPENGL_MINIMUM_REQUIRED_VERSION = { 3, 2 };
|
||||
constexpr OpenGLVersion OPENGL_MINIMUM_REQUIRED_VERSION = { 3, 3 };
|
||||
|
||||
static const vec3f TransparentColourTable[144 - 44] =
|
||||
{
|
||||
|
@ -178,7 +179,6 @@ private:
|
|||
rct_drawpixelinfo * _dpi;
|
||||
|
||||
DrawImageShader * _drawImageShader = nullptr;
|
||||
DrawImageMaskedShader * _drawImageMaskedShader = nullptr;
|
||||
DrawLineShader * _drawLineShader = nullptr;
|
||||
FillRectShader * _fillRectShader = nullptr;
|
||||
|
||||
|
@ -191,6 +191,12 @@ private:
|
|||
sint32 _clipRight;
|
||||
sint32 _clipBottom;
|
||||
|
||||
struct {
|
||||
std::vector<DrawRectCommand> rectangles;
|
||||
std::vector<DrawLineCommand> lines;
|
||||
std::vector<DrawImageCommand> images;
|
||||
} _commandBuffers;
|
||||
|
||||
public:
|
||||
explicit OpenGLDrawingContext(OpenGLDrawingEngine * engine);
|
||||
~OpenGLDrawingContext() override;
|
||||
|
@ -210,6 +216,12 @@ public:
|
|||
void DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour) override;
|
||||
void DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette) override;
|
||||
|
||||
void FlushCommandBuffers();
|
||||
|
||||
void FlushRectangles();
|
||||
void FlushLines();
|
||||
void FlushImages();
|
||||
|
||||
void SetDPI(rct_drawpixelinfo * dpi);
|
||||
};
|
||||
|
||||
|
@ -260,6 +272,7 @@ public:
|
|||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, requiredVersion.Major);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, requiredVersion.Minor);
|
||||
|
||||
_context = SDL_GL_CreateContext(_window);
|
||||
if (_context == nullptr)
|
||||
{
|
||||
|
@ -305,6 +318,11 @@ public:
|
|||
_drawingContext->ResetPalette();
|
||||
}
|
||||
|
||||
void SetUncappedFrameRate(bool uncapped) override
|
||||
{
|
||||
SDL_GL_SetSwapInterval(uncapped ? 0 : 1);
|
||||
}
|
||||
|
||||
void Invalidate(sint32 left, sint32 top, sint32 right, sint32 bottom) override
|
||||
{
|
||||
}
|
||||
|
@ -325,11 +343,14 @@ public:
|
|||
|
||||
gfx_draw_pickedup_peep(&_bitsDPI);
|
||||
|
||||
_drawingContext->FlushCommandBuffers();
|
||||
_swapFramebuffer->SwapCopy();
|
||||
|
||||
rct2_draw(&_bitsDPI);
|
||||
}
|
||||
|
||||
_drawingContext->FlushCommandBuffers();
|
||||
|
||||
// Scale up to window
|
||||
_screenFramebuffer->Bind();
|
||||
_copyFramebufferShader->Use();
|
||||
|
@ -490,7 +511,6 @@ OpenGLDrawingContext::OpenGLDrawingContext(OpenGLDrawingEngine * engine)
|
|||
OpenGLDrawingContext::~OpenGLDrawingContext()
|
||||
{
|
||||
delete _drawImageShader;
|
||||
delete _drawImageMaskedShader;
|
||||
delete _drawLineShader;
|
||||
delete _fillRectShader;
|
||||
|
||||
|
@ -505,17 +525,16 @@ IDrawingEngine * OpenGLDrawingContext::GetEngine()
|
|||
void OpenGLDrawingContext::Initialise()
|
||||
{
|
||||
_drawImageShader = new DrawImageShader();
|
||||
_drawImageMaskedShader = new DrawImageMaskedShader();
|
||||
_drawLineShader = new DrawLineShader();
|
||||
_fillRectShader = new FillRectShader();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::Resize(sint32 width, sint32 height)
|
||||
{
|
||||
FlushCommandBuffers();
|
||||
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetScreenSize(width, height);
|
||||
_drawImageMaskedShader->Use();
|
||||
_drawImageMaskedShader->SetScreenSize(width, height);
|
||||
_drawLineShader->Use();
|
||||
_drawLineShader->SetScreenSize(width, height);
|
||||
_fillRectShader->Use();
|
||||
|
@ -524,11 +543,11 @@ void OpenGLDrawingContext::Resize(sint32 width, sint32 height)
|
|||
|
||||
void OpenGLDrawingContext::ResetPalette()
|
||||
{
|
||||
FlushCommandBuffers();
|
||||
|
||||
_textureCache->SetPalette(_engine->Palette);
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetPalette(_engine->GLPalette);
|
||||
_drawImageMaskedShader->Use();
|
||||
_drawImageMaskedShader->SetPalette(_engine->GLPalette);
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::Clear(uint32 colour)
|
||||
|
@ -543,6 +562,10 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint
|
|||
right += _offsetX;
|
||||
bottom += _offsetY;
|
||||
|
||||
DrawRectCommand command = {};
|
||||
|
||||
command.sourceFramebuffer = _fillRectShader->GetSourceFramebuffer();
|
||||
|
||||
vec4f paletteColour[2];
|
||||
paletteColour[0] = _engine->GLPalette[(colour >> 0) & 0xFF];
|
||||
paletteColour[1] = paletteColour[0];
|
||||
|
@ -550,8 +573,7 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint
|
|||
{
|
||||
paletteColour[1].a = 0;
|
||||
|
||||
_fillRectShader->Use();
|
||||
_fillRectShader->SetFlags(0);
|
||||
command.flags = 0;
|
||||
}
|
||||
else if (colour & 0x2000000)
|
||||
{
|
||||
|
@ -568,20 +590,31 @@ void OpenGLDrawingContext::FillRect(uint32 colour, sint32 left, sint32 top, sint
|
|||
paletteColour[1] = paletteColour[0];
|
||||
|
||||
GLuint srcTexture = _engine->SwapCopyReturningSourceTexture();
|
||||
_fillRectShader->Use();
|
||||
_fillRectShader->SetFlags(1);
|
||||
_fillRectShader->SetSourceFramebuffer(srcTexture);
|
||||
command.flags = 1;
|
||||
command.sourceFramebuffer = srcTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fillRectShader->Use();
|
||||
_fillRectShader->SetFlags(0);
|
||||
command.flags = 0;
|
||||
}
|
||||
|
||||
_fillRectShader->SetColour(0, paletteColour[0]);
|
||||
_fillRectShader->SetColour(1, paletteColour[1]);
|
||||
_fillRectShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_fillRectShader->Draw(left, top, right + 1, bottom + 1);
|
||||
command.colours[0] = paletteColour[0];
|
||||
command.colours[1] = paletteColour[1];
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
command.bounds[0] = left;
|
||||
command.bounds[1] = top;
|
||||
command.bounds[2] = right + 1;
|
||||
command.bounds[3] = bottom + 1;
|
||||
|
||||
_commandBuffers.rectangles.push_back(command);
|
||||
|
||||
// Must be rendered in order, depends on already rendered contents
|
||||
FlushCommandBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32 x2, sint32 y2)
|
||||
|
@ -592,11 +625,25 @@ void OpenGLDrawingContext::DrawLine(uint32 colour, sint32 x1, sint32 y1, sint32
|
|||
y2 += _offsetY;
|
||||
|
||||
vec4f paletteColour = _engine->GLPalette[colour & 0xFF];
|
||||
|
||||
DrawLineCommand command = {};
|
||||
|
||||
_drawLineShader->Use();
|
||||
_drawLineShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_drawLineShader->SetColour(paletteColour);
|
||||
_drawLineShader->Draw(x1, y1, x2, y2);
|
||||
command.colour = paletteColour;
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
command.pos[0] = x1;
|
||||
command.pos[1] = y1;
|
||||
command.pos[2] = x2;
|
||||
command.pos[3] = y2;
|
||||
|
||||
_commandBuffers.lines.push_back(command);
|
||||
|
||||
// Must be rendered in order right now, because it does not yet use depth
|
||||
FlushCommandBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 tertiaryColour)
|
||||
|
@ -626,8 +673,6 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t
|
|||
}
|
||||
}
|
||||
|
||||
GLuint texture = _textureCache->GetOrLoadImageTexture(image);
|
||||
|
||||
uint8 zoomLevel = (1 << _dpi->zoom_level);
|
||||
|
||||
sint32 drawOffsetX = g1Element->x_offset;
|
||||
|
@ -664,10 +709,25 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t
|
|||
right += _clipLeft;
|
||||
bottom += _clipTop;
|
||||
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_drawImageShader->SetTexture(texture);
|
||||
_drawImageShader->Draw(left, top, right, bottom);
|
||||
DrawImageCommand command = {};
|
||||
|
||||
command.flags = 0;
|
||||
command.mask = false;
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
auto texture = _textureCache->GetOrLoadImageTexture(image);
|
||||
command.texColour = texture;
|
||||
|
||||
command.bounds[0] = left;
|
||||
command.bounds[1] = top;
|
||||
command.bounds[2] = right;
|
||||
command.bounds[3] = bottom;
|
||||
|
||||
_commandBuffers.images.push_back(command);
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskImage, uint32 colourImage)
|
||||
|
@ -675,8 +735,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
|
|||
rct_g1_element * g1ElementMask = gfx_get_g1_element(maskImage & 0x7FFFF);
|
||||
rct_g1_element * g1ElementColour = gfx_get_g1_element(colourImage & 0x7FFFF);
|
||||
|
||||
GLuint textureMask = _textureCache->GetOrLoadImageTexture(maskImage);
|
||||
GLuint textureColour = _textureCache->GetOrLoadImageTexture(colourImage);
|
||||
auto textureMask = _textureCache->GetOrLoadImageTexture(maskImage);
|
||||
auto textureColour = _textureCache->GetOrLoadImageTexture(colourImage);
|
||||
|
||||
uint8 zoomLevel = (1 << _dpi->zoom_level);
|
||||
|
||||
|
@ -714,11 +774,24 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
|
|||
right += _clipLeft;
|
||||
bottom += _clipTop;
|
||||
|
||||
_drawImageMaskedShader->Use();
|
||||
_drawImageMaskedShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_drawImageMaskedShader->SetTextureMask(textureMask);
|
||||
_drawImageMaskedShader->SetTextureColour(textureColour);
|
||||
_drawImageMaskedShader->Draw(left, top, right, bottom);
|
||||
DrawImageCommand command = {};
|
||||
|
||||
command.mask = true;
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
command.texMask = textureMask;
|
||||
command.texColour = textureColour;
|
||||
|
||||
command.bounds[0] = left;
|
||||
command.bounds[1] = top;
|
||||
command.bounds[2] = right;
|
||||
command.bounds[3] = bottom;
|
||||
|
||||
_commandBuffers.images.push_back(command);
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour)
|
||||
|
@ -728,7 +801,7 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin
|
|||
int g1Id = image & 0x7FFFF;
|
||||
rct_g1_element * g1Element = gfx_get_g1_element(g1Id);
|
||||
|
||||
GLuint texture = _textureCache->GetOrLoadImageTexture(image);
|
||||
auto texture = _textureCache->GetOrLoadImageTexture(image);
|
||||
|
||||
sint32 drawOffsetX = g1Element->x_offset;
|
||||
sint32 drawOffsetY = g1Element->y_offset;
|
||||
|
@ -754,13 +827,25 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin
|
|||
right += _offsetX;
|
||||
bottom += _offsetY;
|
||||
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_drawImageShader->SetTexture(texture);
|
||||
_drawImageShader->SetFlags(1);
|
||||
_drawImageShader->SetColour(paletteColour);
|
||||
_drawImageShader->Draw(left, top, right, bottom);
|
||||
_drawImageShader->SetFlags(0);
|
||||
DrawImageCommand command = {};
|
||||
|
||||
command.flags = 1;
|
||||
command.mask = false;
|
||||
command.colour = paletteColour;
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
command.texColour = texture;
|
||||
|
||||
command.bounds[0] = left;
|
||||
command.bounds[1] = top;
|
||||
command.bounds[2] = right;
|
||||
command.bounds[3] = bottom;
|
||||
|
||||
_commandBuffers.images.push_back(command);
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * palette)
|
||||
|
@ -768,7 +853,7 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p
|
|||
int g1Id = image & 0x7FFFF;
|
||||
rct_g1_element * g1Element = gfx_get_g1_element(g1Id);
|
||||
|
||||
GLuint texture = _textureCache->GetOrLoadGlyphTexture(image, palette);
|
||||
auto texture = _textureCache->GetOrLoadGlyphTexture(image, palette);
|
||||
|
||||
sint32 drawOffsetX = g1Element->x_offset;
|
||||
sint32 drawOffsetY = g1Element->y_offset;
|
||||
|
@ -794,11 +879,92 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p
|
|||
right += _offsetX;
|
||||
bottom += _offsetY;
|
||||
|
||||
DrawImageCommand command = {};
|
||||
|
||||
command.flags = 0;
|
||||
command.mask = false;
|
||||
|
||||
command.clip[0] = _clipLeft;
|
||||
command.clip[1] = _clipTop;
|
||||
command.clip[2] = _clipRight;
|
||||
command.clip[3] = _clipBottom;
|
||||
|
||||
command.texColour = texture;
|
||||
|
||||
command.bounds[0] = left;
|
||||
command.bounds[1] = top;
|
||||
command.bounds[2] = right;
|
||||
command.bounds[3] = bottom;
|
||||
|
||||
_commandBuffers.images.push_back(command);
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushCommandBuffers()
|
||||
{
|
||||
FlushRectangles();
|
||||
FlushLines();
|
||||
|
||||
FlushImages();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushRectangles()
|
||||
{
|
||||
for (const auto& command : _commandBuffers.rectangles)
|
||||
{
|
||||
_fillRectShader->Use();
|
||||
_fillRectShader->SetFlags(command.flags);
|
||||
_fillRectShader->SetSourceFramebuffer(command.sourceFramebuffer);
|
||||
_fillRectShader->SetColour(0, command.colours[0]);
|
||||
_fillRectShader->SetColour(1, command.colours[1]);
|
||||
_fillRectShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]);
|
||||
_fillRectShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]);
|
||||
}
|
||||
|
||||
_commandBuffers.rectangles.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushLines() {
|
||||
for (const auto& command : _commandBuffers.lines)
|
||||
{
|
||||
_drawLineShader->Use();
|
||||
_drawLineShader->SetColour(command.colour);
|
||||
_drawLineShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]);
|
||||
_drawLineShader->Draw(command.pos[0], command.pos[1], command.pos[2], command.pos[3]);
|
||||
}
|
||||
|
||||
_commandBuffers.lines.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushImages()
|
||||
{
|
||||
if (_commandBuffers.images.size() == 0) return;
|
||||
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture());
|
||||
|
||||
std::vector<DrawImageInstance> instances;
|
||||
instances.reserve(_commandBuffers.images.size());
|
||||
|
||||
for (const auto& command : _commandBuffers.images)
|
||||
{
|
||||
DrawImageInstance instance;
|
||||
|
||||
instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]};
|
||||
instance.texColourAtlas = command.texColour.index;
|
||||
instance.texColourBounds = command.texColour.normalizedBounds;
|
||||
instance.texMaskAtlas = command.texMask.index;
|
||||
instance.texMaskBounds = command.texMask.normalizedBounds;
|
||||
instance.flags = command.flags;
|
||||
instance.colour = command.colour;
|
||||
instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]};
|
||||
instance.mask = command.mask;
|
||||
|
||||
instances.push_back(instance);
|
||||
}
|
||||
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetClip(_clipLeft, _clipTop, _clipRight, _clipBottom);
|
||||
_drawImageShader->SetTexture(texture);
|
||||
_drawImageShader->Draw(left, top, right, bottom);
|
||||
_drawImageShader->SetFlags(0);
|
||||
_drawImageShader->DrawInstances(instances);
|
||||
|
||||
_commandBuffers.images.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi)
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#include "../../../core/Memory.hpp"
|
||||
#include "TextureCache.h"
|
||||
|
||||
|
@ -44,14 +45,12 @@ void TextureCache::InvalidateImage(uint32 image)
|
|||
auto kvp = _imageTextureMap.find(image);
|
||||
if (kvp != _imageTextureMap.end())
|
||||
{
|
||||
GLuint texture = kvp->second;
|
||||
glDeleteTextures(1, &texture);
|
||||
|
||||
_atlases[kvp->second.index].Free(kvp->second);
|
||||
_imageTextureMap.erase(kvp);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint TextureCache::GetOrLoadImageTexture(uint32 image)
|
||||
CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image)
|
||||
{
|
||||
auto kvp = _imageTextureMap.find(image & 0x7FFFF);
|
||||
if (kvp != _imageTextureMap.end())
|
||||
|
@ -59,13 +58,13 @@ GLuint TextureCache::GetOrLoadImageTexture(uint32 image)
|
|||
return kvp->second;
|
||||
}
|
||||
|
||||
GLuint texture = LoadImageTexture(image);
|
||||
_imageTextureMap[image & 0x7FFFF] = texture;
|
||||
auto cacheInfo = LoadImageTexture(image);
|
||||
_imageTextureMap[image & 0x7FFFF] = cacheInfo;
|
||||
|
||||
return texture;
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
GLuint TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette)
|
||||
CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette)
|
||||
{
|
||||
GlyphId glyphId;
|
||||
glyphId.Image = image;
|
||||
|
@ -77,46 +76,83 @@ GLuint TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette)
|
|||
return kvp->second;
|
||||
}
|
||||
|
||||
GLuint texture = LoadGlyphTexture(image, palette);
|
||||
_glyphTextureMap[glyphId] = texture;
|
||||
auto cacheInfo = LoadGlyphTexture(image, palette);
|
||||
_glyphTextureMap[glyphId] = cacheInfo;
|
||||
|
||||
return texture;
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
GLuint TextureCache::LoadImageTexture(uint32 image)
|
||||
void TextureCache::CreateAtlasesTexture()
|
||||
{
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
if (!_atlasesTextureInitialised)
|
||||
{
|
||||
// Determine width and height to use for texture atlases
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &_atlasesTextureDimensions);
|
||||
if (_atlasesTextureDimensions > TEXTURE_CACHE_MAX_ATLAS_SIZE) {
|
||||
_atlasesTextureDimensions = TEXTURE_CACHE_MAX_ATLAS_SIZE;
|
||||
}
|
||||
|
||||
rct_drawpixelinfo * dpi = GetImageAsDPI(image, 0);
|
||||
// Determine maximum number of atlases (minimum of size and array limit)
|
||||
glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &_atlasesTextureIndicesLimit);
|
||||
if (_atlasesTextureDimensions < _atlasesTextureIndicesLimit) _atlasesTextureIndicesLimit = _atlasesTextureDimensions;
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, dpi->width, dpi->height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits);
|
||||
// Create an array texture to hold all of the atlases
|
||||
glGenTextures(1, &_atlasesTexture);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
_atlasesTextureInitialised = true;
|
||||
_atlasesTextureIndices = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void TextureCache::EnlargeAtlasesTexture(GLuint newEntries)
|
||||
{
|
||||
CreateAtlasesTexture();
|
||||
|
||||
GLuint newIndices = _atlasesTextureIndices + newEntries;
|
||||
|
||||
// Retrieve current array data
|
||||
auto oldPixels = std::vector<char>(_atlasesTextureDimensions * _atlasesTextureDimensions * _atlasesTextureIndices);
|
||||
glGetTexImage(GL_TEXTURE_2D_ARRAY, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, oldPixels.data());
|
||||
|
||||
// Reallocate array
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, _atlasesTextureDimensions, _atlasesTextureDimensions, newIndices, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
// Restore old data
|
||||
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, _atlasesTextureDimensions, _atlasesTextureDimensions, _atlasesTextureIndices, GL_RED_INTEGER, GL_UNSIGNED_BYTE, oldPixels.data());
|
||||
|
||||
_atlasesTextureIndices = newIndices;
|
||||
}
|
||||
|
||||
CachedTextureInfo TextureCache::LoadImageTexture(uint32 image)
|
||||
{
|
||||
rct_drawpixelinfo * dpi = GetImageAsDPI(image, 0);
|
||||
|
||||
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);
|
||||
|
||||
DeleteDPI(dpi);
|
||||
|
||||
return texture;
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
GLuint TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette)
|
||||
CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette)
|
||||
{
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
|
||||
rct_drawpixelinfo * dpi = GetGlyphAsDPI(image, palette);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8UI, dpi->width, dpi->height, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi->bits);
|
||||
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);
|
||||
|
||||
DeleteDPI(dpi);
|
||||
|
||||
return texture;
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight)
|
||||
|
@ -135,6 +171,42 @@ void * TextureCache::GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32
|
|||
return pixels32;
|
||||
}
|
||||
|
||||
CachedTextureInfo TextureCache::AllocateImage(int imageWidth, int imageHeight)
|
||||
{
|
||||
CreateAtlasesTexture();
|
||||
|
||||
// Find an atlas that fits this image
|
||||
for (Atlas& atlas : _atlases)
|
||||
{
|
||||
if (atlas.GetFreeSlots() > 0 && atlas.IsImageSuitable(imageWidth, imageHeight))
|
||||
{
|
||||
return atlas.Allocate(imageWidth, imageHeight);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no such atlas, then create a new one
|
||||
if ((int) _atlases.size() >= _atlasesTextureIndicesLimit)
|
||||
{
|
||||
throw std::runtime_error("more texture atlases required, but device limit reached!");
|
||||
}
|
||||
|
||||
int atlasIndex = (int) _atlases.size();
|
||||
int atlasSize = (int) powf(2, (float) Atlas::CalculateImageSizeOrder(imageWidth, imageHeight));
|
||||
|
||||
#ifdef DEBUG
|
||||
log_verbose("new texture atlas #%d (size %d) allocated\n", atlasIndex, atlasSize);
|
||||
#endif
|
||||
|
||||
_atlases.push_back(std::move(Atlas(atlasIndex, atlasSize)));
|
||||
_atlases.back().Initialise(_atlasesTextureDimensions, _atlasesTextureDimensions);
|
||||
|
||||
// Enlarge texture array to support new atlas
|
||||
EnlargeAtlasesTexture(1);
|
||||
|
||||
// And allocate from the new atlas
|
||||
return _atlases.back().Allocate(imageWidth, imageHeight);
|
||||
}
|
||||
|
||||
rct_drawpixelinfo * TextureCache::GetImageAsDPI(uint32 image, uint32 tertiaryColour)
|
||||
{
|
||||
rct_g1_element * g1Element = gfx_get_g1_element(image & 0x7FFFF);
|
||||
|
@ -204,30 +276,8 @@ void * TextureCache::ConvertDPIto32bpp(const rct_drawpixelinfo * dpi)
|
|||
|
||||
void TextureCache::FreeTextures()
|
||||
{
|
||||
// Free images
|
||||
size_t numTextures = _imageTextureMap.size();
|
||||
auto textures = std::vector<GLuint>(numTextures);
|
||||
for (auto kvp : _imageTextureMap)
|
||||
{
|
||||
textures.push_back(kvp.second);
|
||||
}
|
||||
if (textures.size() > 0)
|
||||
{
|
||||
glDeleteTextures(textures.size(), textures.data());
|
||||
}
|
||||
|
||||
// Free glyphs
|
||||
numTextures = _glyphTextureMap.size();
|
||||
textures.clear();
|
||||
textures.reserve(numTextures);
|
||||
for (auto kvp : _glyphTextureMap)
|
||||
{
|
||||
textures.push_back(kvp.second);
|
||||
}
|
||||
if (textures.size() > 0)
|
||||
{
|
||||
glDeleteTextures(textures.size(), textures.data());
|
||||
}
|
||||
// Free array texture
|
||||
glDeleteTextures(1, &_atlasesTexture);
|
||||
}
|
||||
|
||||
rct_drawpixelinfo * TextureCache::CreateDPI(sint32 width, sint32 height)
|
||||
|
@ -253,4 +303,9 @@ void TextureCache::DeleteDPI(rct_drawpixelinfo* dpi)
|
|||
delete dpi;
|
||||
}
|
||||
|
||||
GLuint TextureCache::GetAtlasesTexture()
|
||||
{
|
||||
return _atlasesTexture;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -16,10 +16,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <SDL_pixels.h>
|
||||
#include "../../../common.h"
|
||||
#include "OpenGLAPI.h"
|
||||
#include "GLSLTypes.h"
|
||||
|
||||
struct rct_drawpixelinfo;
|
||||
|
||||
|
@ -50,11 +53,150 @@ struct GlyphId
|
|||
};
|
||||
};
|
||||
|
||||
// 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 int TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048;
|
||||
|
||||
// Pixel dimensions of smallest supported slots in texture atlases
|
||||
// Must be a power of 2!
|
||||
constexpr int TEXTURE_CACHE_SMALLEST_SLOT = 32;
|
||||
|
||||
// Location of an image (texture atlas index, slot and normalized coordinates)
|
||||
struct CachedTextureInfo
|
||||
{
|
||||
GLuint index;
|
||||
GLuint slot;
|
||||
vec4i bounds;
|
||||
vec4f normalizedBounds;
|
||||
};
|
||||
|
||||
// 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
|
||||
{
|
||||
private:
|
||||
GLuint _index;
|
||||
int _imageSize;
|
||||
int _atlasWidth, _atlasHeight;
|
||||
std::vector<GLuint> _freeSlots;
|
||||
|
||||
int _cols, _rows;
|
||||
|
||||
public:
|
||||
Atlas(GLuint index, int imageSize)
|
||||
{
|
||||
_index = index;
|
||||
_imageSize = imageSize;
|
||||
}
|
||||
|
||||
void Initialise(int atlasWidth, int atlasHeight)
|
||||
{
|
||||
_atlasWidth = atlasWidth;
|
||||
_atlasHeight = atlasHeight;
|
||||
|
||||
_cols = _atlasWidth / _imageSize;
|
||||
_rows = _atlasHeight / _imageSize;
|
||||
|
||||
_freeSlots.resize(_cols * _rows);
|
||||
for (size_t i = 0; i < _freeSlots.size(); i++)
|
||||
{
|
||||
_freeSlots[i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
CachedTextureInfo Allocate(int actualWidth, int actualHeight)
|
||||
{
|
||||
assert(_freeSlots.size() > 0);
|
||||
|
||||
GLuint slot = _freeSlots.back();
|
||||
_freeSlots.pop_back();
|
||||
|
||||
auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight);
|
||||
|
||||
return
|
||||
{
|
||||
_index,
|
||||
slot,
|
||||
bounds,
|
||||
NormalizeCoordinates(bounds)
|
||||
};
|
||||
}
|
||||
|
||||
void Free(const CachedTextureInfo& 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
|
||||
bool IsImageSuitable(int actualWidth, int actualHeight) const
|
||||
{
|
||||
int imageOrder = CalculateImageSizeOrder(actualWidth, actualHeight);
|
||||
int atlasOrder = (int) log2(_imageSize);
|
||||
|
||||
return imageOrder == atlasOrder;
|
||||
}
|
||||
|
||||
int GetFreeSlots() const
|
||||
{
|
||||
return (int) _freeSlots.size();
|
||||
}
|
||||
|
||||
static int CalculateImageSizeOrder(int actualWidth, int actualHeight)
|
||||
{
|
||||
int actualSize = std::max(actualWidth, actualHeight);
|
||||
|
||||
if (actualSize < TEXTURE_CACHE_SMALLEST_SLOT) {
|
||||
actualSize = TEXTURE_CACHE_SMALLEST_SLOT;
|
||||
}
|
||||
|
||||
return (int) ceil(log2f((float) actualSize));
|
||||
}
|
||||
|
||||
private:
|
||||
vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const
|
||||
{
|
||||
int row = slot / _cols;
|
||||
int col = slot % _cols;
|
||||
|
||||
return vec4i
|
||||
{
|
||||
_imageSize * col,
|
||||
_imageSize * row,
|
||||
_imageSize * col + actualWidth,
|
||||
_imageSize * row + actualHeight,
|
||||
};
|
||||
}
|
||||
|
||||
vec4f NormalizeCoordinates(const vec4i& coords) const
|
||||
{
|
||||
return vec4f
|
||||
{
|
||||
coords.x / (float) _atlasWidth,
|
||||
coords.y / (float) _atlasHeight,
|
||||
coords.z / (float) _atlasWidth,
|
||||
coords.w / (float) _atlasHeight
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
class TextureCache
|
||||
{
|
||||
private:
|
||||
std::unordered_map<uint32, GLuint> _imageTextureMap;
|
||||
std::unordered_map<GlyphId, GLuint, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
|
||||
bool _atlasesTextureInitialised = false;
|
||||
|
||||
GLuint _atlasesTexture;
|
||||
GLint _atlasesTextureDimensions;
|
||||
GLuint _atlasesTextureIndices;
|
||||
GLint _atlasesTextureIndicesLimit;
|
||||
std::vector<Atlas> _atlases;
|
||||
|
||||
std::unordered_map<uint32, CachedTextureInfo> _imageTextureMap;
|
||||
std::unordered_map<GlyphId, CachedTextureInfo, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
|
||||
|
||||
SDL_Color _palette[256];
|
||||
|
||||
public:
|
||||
|
@ -62,12 +204,17 @@ public:
|
|||
~TextureCache();
|
||||
void SetPalette(const SDL_Color * palette);
|
||||
void InvalidateImage(uint32 image);
|
||||
GLuint GetOrLoadImageTexture(uint32 image);
|
||||
GLuint GetOrLoadGlyphTexture(uint32 image, uint8 * palette);
|
||||
CachedTextureInfo GetOrLoadImageTexture(uint32 image);
|
||||
CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette);
|
||||
|
||||
GLuint GetAtlasesTexture();
|
||||
|
||||
private:
|
||||
GLuint LoadImageTexture(uint32 image);
|
||||
GLuint LoadGlyphTexture(uint32 image, uint8 * palette);
|
||||
void CreateAtlasesTexture();
|
||||
void EnlargeAtlasesTexture(GLuint newEntries);
|
||||
CachedTextureInfo LoadImageTexture(uint32 image);
|
||||
CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette);
|
||||
CachedTextureInfo AllocateImage(int imageWidth, int imageHeight);
|
||||
void * GetImageAsARGB(uint32 image, uint32 tertiaryColour, uint32 * outWidth, uint32 * outHeight);
|
||||
rct_drawpixelinfo * GetImageAsDPI(uint32 image, uint32 tertiaryColour);
|
||||
void * GetGlyphAsARGB(uint32 image, uint8 * palette, uint32 * outWidth, uint32 * outHeight);
|
||||
|
|
28
src/rct2.c
28
src/rct2.c
|
@ -301,21 +301,22 @@ void rct2_draw(rct_drawpixelinfo *dpi)
|
|||
gCurrentDrawCount++;
|
||||
}
|
||||
|
||||
static uint32 _lastFPSUpdateTicks;
|
||||
static uint32 _lastFPSTicks;
|
||||
static float _currentFPS;
|
||||
static time_t _lastSecond;
|
||||
static int _currentFPS;
|
||||
static int _frames;
|
||||
|
||||
static float rct2_measure_fps()
|
||||
static void rct2_measure_fps()
|
||||
{
|
||||
uint32 currentTicks = SDL_GetTicks();
|
||||
if (currentTicks - _lastFPSUpdateTicks > 500) {
|
||||
_lastFPSUpdateTicks = currentTicks;
|
||||
_frames++;
|
||||
|
||||
uint32 frameDelta = currentTicks - _lastFPSTicks;
|
||||
_currentFPS = 1000.0f / frameDelta;
|
||||
time_t currentTime = time(NULL);
|
||||
|
||||
if (currentTime != _lastSecond) {
|
||||
_currentFPS = _frames;
|
||||
_frames = 0;
|
||||
}
|
||||
_lastFPSTicks = currentTicks;
|
||||
return _currentFPS;
|
||||
|
||||
_lastSecond = currentTime;
|
||||
}
|
||||
|
||||
static void rct2_draw_fps(rct_drawpixelinfo *dpi)
|
||||
|
@ -332,9 +333,8 @@ static void rct2_draw_fps(rct_drawpixelinfo *dpi)
|
|||
ch = utf8_write_codepoint(ch, FORMAT_MEDIUMFONT);
|
||||
ch = utf8_write_codepoint(ch, FORMAT_OUTLINE);
|
||||
ch = utf8_write_codepoint(ch, FORMAT_WHITE);
|
||||
|
||||
const char *formatString = (_currentFPS >= 100.0f ? "%.0f" : "%.1f");
|
||||
sprintf(ch, formatString, _currentFPS);
|
||||
|
||||
sprintf(ch, "%d", _currentFPS);
|
||||
|
||||
// Draw Text
|
||||
int stringWidth = gfx_get_string_width(buffer);
|
||||
|
|
|
@ -587,6 +587,7 @@ static void window_options_mouseup(rct_window *w, int widgetIndex)
|
|||
switch (widgetIndex) {
|
||||
case WIDX_UNCAP_FPS_CHECKBOX:
|
||||
gConfigGeneral.uncap_fps ^= 1;
|
||||
drawing_engine_set_fps_uncapped(gConfigGeneral.uncap_fps);
|
||||
config_save_default();
|
||||
window_invalidate(w);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue