mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-10 09:32:29 +01:00
Implement sprite batch drawing using instancing
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
#version 150
|
||||
|
||||
uniform ivec4 uClip;
|
||||
uniform int uFlags;
|
||||
uniform vec4 uColour;
|
||||
uniform usampler2DArray uTexture;
|
||||
uniform vec4 uPalette[256];
|
||||
uniform vec2 uTexCoordScale;
|
||||
uniform int uTexSlot;
|
||||
uniform usampler2DArray uTexture;
|
||||
|
||||
flat in ivec4 fClip;
|
||||
flat in int fFlags;
|
||||
in vec4 fColour;
|
||||
in vec2 fTexCoordScale;
|
||||
flat in int fTexSlot;
|
||||
|
||||
in vec2 fPosition;
|
||||
in vec2 fTextureCoordinate;
|
||||
@@ -15,16 +16,16 @@ 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, vec3(fTextureCoordinate * uTexCoordScale, float(uTexSlot))).r];
|
||||
if ((uFlags & 1) != 0)
|
||||
vec4 texel = uPalette[texture(uTexture, vec3(fTextureCoordinate * fTexCoordScale, float(fTexSlot))).r];
|
||||
if ((fFlags & 1) != 0)
|
||||
{
|
||||
oColour = vec4(uColour.rgb, uColour.a * texel.a);
|
||||
oColour = vec4(fColour.rgb, fColour.a * texel.a);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,32 +1,43 @@
|
||||
#version 150
|
||||
|
||||
uniform ivec2 uScreenSize;
|
||||
uniform ivec4 uBounds;
|
||||
uniform ivec4 uTextureCoordinates;
|
||||
|
||||
in ivec4 ivClip;
|
||||
in vec2 ivTexCoordScale;
|
||||
in int ivTexSlot;
|
||||
in int ivFlags;
|
||||
in vec4 ivColour;
|
||||
in ivec4 ivBounds;
|
||||
|
||||
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;
|
||||
out vec2 fTexCoordScale;
|
||||
flat out int fTexSlot;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 pos;
|
||||
switch (vIndex) {
|
||||
case 0u:
|
||||
pos = uBounds.xy;
|
||||
pos = ivBounds.xy;
|
||||
fTextureCoordinate = uTextureCoordinates.xy;
|
||||
break;
|
||||
case 1u:
|
||||
pos = uBounds.zy;
|
||||
pos = ivBounds.zy;
|
||||
fTextureCoordinate = uTextureCoordinates.zy;
|
||||
break;
|
||||
case 2u:
|
||||
pos = uBounds.xw;
|
||||
pos = ivBounds.xw;
|
||||
fTextureCoordinate = uTextureCoordinates.xw;
|
||||
break;
|
||||
case 3u:
|
||||
pos = uBounds.zw;
|
||||
pos = ivBounds.zw;
|
||||
fTextureCoordinate = uTextureCoordinates.zw;
|
||||
break;
|
||||
}
|
||||
@@ -38,5 +49,11 @@ void main()
|
||||
pos.y = (pos.y * (2.0 / uScreenSize.y)) - 1.0;
|
||||
pos.y *= -1;
|
||||
|
||||
fClip = ivClip;
|
||||
fFlags = ivFlags;
|
||||
fColour = ivColour;
|
||||
fTexCoordScale = ivTexCoordScale;
|
||||
fTexSlot = ivTexSlot;
|
||||
|
||||
gl_Position = vec4(pos, 0.0, 1.0);
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
@@ -34,7 +35,6 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
|
||||
glVertexAttribIPointer(vIndex, 1, GL_INT, 0, nullptr);
|
||||
|
||||
Use();
|
||||
SetFlags(0);
|
||||
SetTextureCoordinates(0, 0, 1, 1);
|
||||
glUniform1i(uTexture, 0);
|
||||
}
|
||||
@@ -42,6 +42,7 @@ DrawImageShader::DrawImageShader() : OpenGLShaderProgram("drawimage")
|
||||
DrawImageShader::~DrawImageShader()
|
||||
{
|
||||
glDeleteBuffers(1, &_vbo);
|
||||
glDeleteBuffers(1, &_vboInstances);
|
||||
glDeleteVertexArrays(1, &_vao);
|
||||
|
||||
glBindVertexArray(_vao);
|
||||
@@ -50,15 +51,9 @@ 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");
|
||||
uTexCoordScale = GetUniformLocation("uTexCoordScale");
|
||||
uTexSlot = GetUniformLocation("uTexSlot");
|
||||
uTextureCoordinates = GetUniformLocation("uTextureCoordinates");
|
||||
|
||||
vIndex = GetAttributeLocation("vIndex");
|
||||
}
|
||||
@@ -68,14 +63,9 @@ void DrawImageShader::SetScreenSize(sint32 width, sint32 height)
|
||||
glUniform2i(uScreenSize, width, height);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetClip(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
void DrawImageShader::SetPalette(const vec4f *glPalette)
|
||||
{
|
||||
glUniform4i(uClip, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetBounds(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
{
|
||||
glUniform4i(uBounds, left, top, right, bottom);
|
||||
glUniform4fv(uPalette, 256, (const GLfloat *) glPalette);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom)
|
||||
@@ -83,36 +73,38 @@ void DrawImageShader::SetTextureCoordinates(sint32 left, sint32 top, sint32 righ
|
||||
glUniform4i(uTextureCoordinates, left, top, right, bottom);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetTextureCoordScale(float width, float height) {
|
||||
glUniform2f(uTexCoordScale, width, height);
|
||||
}
|
||||
|
||||
void DrawImageShader::SetTextureSlot(GLuint slot)
|
||||
void DrawImageShader::DrawInstances(const std::vector<DrawImageInstance>& instances)
|
||||
{
|
||||
glUniform1i(uTexSlot, slot);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
SetBounds(left, top, right, bottom);
|
||||
// Copy instance data to vbo for single-use
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboInstances);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(instances[0]) * instances.size(), instances.data(), GL_STREAM_DRAW);
|
||||
|
||||
// Bind vertex attributes
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
glVertexAttribIPointer(GetAttributeLocation("ivClip"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, clip));
|
||||
glVertexAttribPointer(GetAttributeLocation("ivTexCoordScale"), 2, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texCoordScale));
|
||||
glVertexAttribIPointer(GetAttributeLocation("ivTexSlot"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, texSlot));
|
||||
glVertexAttribIPointer(GetAttributeLocation("ivFlags"), 1, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, flags));
|
||||
glVertexAttribPointer(GetAttributeLocation("ivColour"), 4, GL_FLOAT, GL_FALSE, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, colour));
|
||||
glVertexAttribIPointer(GetAttributeLocation("ivBounds"), 4, GL_INT, sizeof(DrawImageInstance), (void*) offsetof(DrawImageInstance, bounds));
|
||||
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivClip"));
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivTexCoordScale"));
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivTexSlot"));
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivFlags"));
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivColour"));
|
||||
glEnableVertexAttribArray(GetAttributeLocation("ivBounds"));
|
||||
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivClip"), 1);
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivTexCoordScale"), 1);
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivTexSlot"), 1);
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivFlags"), 1);
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivColour"), 1);
|
||||
glVertexAttribDivisor(GetAttributeLocation("ivBounds"), 1);
|
||||
|
||||
// Draw instances
|
||||
glDrawArraysInstanced(GL_TRIANGLES, 0, 6, instances.size());
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
||||
@@ -19,24 +19,30 @@
|
||||
#include "GLSLTypes.h"
|
||||
#include "OpenGLShaderProgram.h"
|
||||
#include <SDL_pixels.h>
|
||||
#include <vector>
|
||||
|
||||
// Per-instance data for images
|
||||
struct DrawImageInstance {
|
||||
vec4i clip;
|
||||
vec2f texCoordScale;
|
||||
int texSlot;
|
||||
int flags;
|
||||
vec4f colour;
|
||||
vec4i bounds;
|
||||
};
|
||||
|
||||
class DrawImageShader : public OpenGLShaderProgram
|
||||
{
|
||||
private:
|
||||
GLuint uScreenSize;
|
||||
GLuint uClip;
|
||||
GLuint uBounds;
|
||||
GLuint uTextureCoordinates;
|
||||
GLuint uTexture;
|
||||
GLuint uColour;
|
||||
GLuint uFlags;
|
||||
GLuint uPalette;
|
||||
GLuint uTexCoordScale;
|
||||
GLuint uTexSlot;
|
||||
GLuint uTextureCoordinates;
|
||||
|
||||
GLuint vIndex;
|
||||
|
||||
GLuint _vbo;
|
||||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
|
||||
SDL_Color _palette[256];
|
||||
@@ -46,15 +52,9 @@ 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 SetTextureCoordScale(float width, float height);
|
||||
void SetTextureSlot(GLuint slot);
|
||||
void SetColour(vec4f colour);
|
||||
void SetFlags(uint32 flags);
|
||||
void SetPalette(const vec4f *glPalette);
|
||||
void Draw(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void SetTextureCoordinates(sint32 left, sint32 top, sint32 right, sint32 bottom);
|
||||
void DrawInstances(const std::vector<DrawImageInstance>& instances);
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
|
||||
@@ -110,6 +110,8 @@ static const char * TryLoadAllProcAddresses()
|
||||
SetupOpenGLFunction(glVertexAttribPointer);
|
||||
SetupOpenGLFunction(glTexStorage3D);
|
||||
SetupOpenGLFunction(glDebugMessageCallback);
|
||||
SetupOpenGLFunction(glDrawArraysInstanced);
|
||||
SetupOpenGLFunction(glVertexAttribDivisor);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,8 @@ GLAPI_DECL PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer GLAP
|
||||
GLAPI_DECL PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer GLAPI_SET;
|
||||
GLAPI_DECL PFNGLTEXSTORAGE3DPROC glTexStorage3D GLAPI_SET;
|
||||
GLAPI_DECL PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback GLAPI_SET;
|
||||
GLAPI_DECL PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced GLAPI_SET;
|
||||
GLAPI_DECL PFNGLVERTEXATTRIBDIVISORPROC glVertexAttribDivisor GLAPI_SET;
|
||||
|
||||
#endif /* OPENGL_NO_LINK */
|
||||
|
||||
|
||||
@@ -803,7 +803,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
|
||||
_commandBuffers.maskedImages.push_back(command);
|
||||
|
||||
// Currently not properly ordered with regular images yet
|
||||
FlushCommandBuffers();
|
||||
// TODO: uncomment once masked images are mixed with normal images using depth sorting
|
||||
//FlushCommandBuffers();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uint8 colour)
|
||||
@@ -943,18 +944,29 @@ void OpenGLDrawingContext::FlushLines() {
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushImages() {
|
||||
if (_commandBuffers.images.size() == 0) return;
|
||||
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetArrayTexture());
|
||||
|
||||
std::vector<DrawImageInstance> instances;
|
||||
instances.reserve(_commandBuffers.images.size());
|
||||
|
||||
for (const auto& command : _commandBuffers.images) {
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->SetClip(command.clip[0], command.clip[1], command.clip[2], command.clip[3]);
|
||||
_drawImageShader->SetTextureCoordScale(command.texColour.dimensions.x, command.texColour.dimensions.y);
|
||||
_drawImageShader->SetTextureSlot(command.texColour.slot);
|
||||
_drawImageShader->SetFlags(command.flags);
|
||||
_drawImageShader->SetColour(command.colour);
|
||||
_drawImageShader->Draw(command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]);
|
||||
DrawImageInstance instance;
|
||||
|
||||
instance.clip = {command.clip[0], command.clip[1], command.clip[2], command.clip[3]};
|
||||
instance.texCoordScale = command.texColour.dimensions;
|
||||
instance.texSlot = command.texColour.slot;
|
||||
instance.flags = command.flags;
|
||||
instance.colour = command.colour;
|
||||
instance.bounds = {command.bounds[0], command.bounds[1], command.bounds[2], command.bounds[3]};
|
||||
|
||||
instances.push_back(instance);
|
||||
}
|
||||
|
||||
_drawImageShader->Use();
|
||||
_drawImageShader->DrawInstances(instances);
|
||||
|
||||
_commandBuffers.images.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ CachedTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image)
|
||||
auto cacheInfo = LoadImageTexture(image);
|
||||
_imageTextureMap[image & 0x7FFFF] = cacheInfo;
|
||||
|
||||
printf("%d slots left\n", (int) _freeSlots.size());
|
||||
//printf("%d slots left\n", (int) _freeSlots.size());
|
||||
|
||||
return cacheInfo;
|
||||
}
|
||||
@@ -86,7 +86,7 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale
|
||||
auto cacheInfo = LoadGlyphTexture(image, palette);
|
||||
_glyphTextureMap[glyphId] = cacheInfo;
|
||||
|
||||
printf("%d slots left\n", (int) _freeSlots.size());
|
||||
//printf("%d slots left\n", (int) _freeSlots.size());
|
||||
|
||||
return cacheInfo;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user