mirror of https://github.com/OpenRCT2/OpenRCT2.git
OpenGL: Add multi-pass transparency
This commit is contained in:
parent
d3d41ea724
commit
aac1c59714
|
@ -17,7 +17,7 @@ void main()
|
|||
uint transparent = texture(uTransparentTex, fTextureCoordinate).r;
|
||||
float transparentDepth = texture(uTransparentDepth, fTextureCoordinate).r;
|
||||
|
||||
if (transparentDepth > opaqueDepth)
|
||||
if (opaqueDepth <= transparentDepth)
|
||||
{
|
||||
transparent = 0u;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,8 @@ void main()
|
|||
{
|
||||
vec2 pos = clamp(vVertMat * vBounds, vClip.xy, vClip.zw);
|
||||
|
||||
// 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;
|
||||
// Transform screen coordinates to viewport coordinates
|
||||
pos = (pos * (2.0 / uScreenSize)) - 1.0;
|
||||
pos.y *= -1;
|
||||
float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT;
|
||||
|
||||
|
|
|
@ -8,6 +8,9 @@ const int FLAG_CROSS_HATCH = (1 << 4);
|
|||
uniform usampler2DArray uTexture;
|
||||
uniform usampler2DRect uPaletteTex;
|
||||
|
||||
uniform sampler2D uPeelingTex;
|
||||
uniform bool uPeeling;
|
||||
|
||||
flat in int fFlags;
|
||||
flat in uint fColour;
|
||||
in vec3 fTexColour;
|
||||
|
@ -15,11 +18,21 @@ in vec3 fTexMask;
|
|||
flat in vec3 fPalettes;
|
||||
|
||||
in vec2 fPosition;
|
||||
in vec3 fPeelPos;
|
||||
|
||||
out uint oColour;
|
||||
|
||||
void main()
|
||||
{
|
||||
if (uPeeling)
|
||||
{
|
||||
float peel = texture(uPeelingTex, fPeelPos.xy).r;
|
||||
if (peel == 0.0 || fPeelPos.z >= peel)
|
||||
{
|
||||
discard;
|
||||
}
|
||||
}
|
||||
|
||||
uint texel;
|
||||
if ((fFlags & FLAG_NO_TEXTURE) == 0)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ in mat4x2 vVertMat;
|
|||
in vec2 vVertVec;
|
||||
|
||||
out vec2 fPosition;
|
||||
out vec3 fPeelPos;
|
||||
flat out int fFlags;
|
||||
flat out uint fColour;
|
||||
out vec3 fTexColour;
|
||||
|
@ -36,15 +37,17 @@ void main()
|
|||
|
||||
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;
|
||||
// Transform screen coordinates to texture coordinates
|
||||
float depth = 1.0 - (vDepth + 1) * DEPTH_INCREMENT;
|
||||
pos = pos / uScreenSize;
|
||||
pos.y = pos.y * -1.0 + 1.0;
|
||||
fPeelPos = vec3(pos, depth * 0.5 + 0.5);
|
||||
|
||||
fFlags = vFlags;
|
||||
fColour = vColour;
|
||||
fPalettes = vec3(vPalettes);
|
||||
|
||||
// Transform texture coordinates to viewport coordinates
|
||||
pos = pos * 2.0 - 1.0;
|
||||
gl_Position = vec4(pos, depth, 1.0);
|
||||
}
|
||||
|
|
|
@ -75,7 +75,9 @@ void ApplyTransparencyShader::GetLocations()
|
|||
vTextureCoordinate = GetAttributeLocation("vTextureCoordinate");
|
||||
}
|
||||
|
||||
void ApplyTransparencyShader::SetTextures(GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex)
|
||||
void ApplyTransparencyShader::SetTextures(GLuint opaqueTex, GLuint opaqueDepth,
|
||||
GLuint transparentTex, GLuint transparentDepth,
|
||||
GLuint paletteTex)
|
||||
{
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D, opaqueTex);
|
||||
OpenGLAPI::SetTexture(1, GL_TEXTURE_2D, opaqueDepth);
|
||||
|
|
|
@ -38,7 +38,9 @@ public:
|
|||
ApplyTransparencyShader();
|
||||
~ApplyTransparencyShader() override;
|
||||
|
||||
void SetTextures(GLuint opaqueTex, GLuint opaqueDepth, GLuint transparentTex, GLuint transparentDepth, GLuint paletteTex);
|
||||
void SetTextures(GLuint opaqueTex, GLuint opaqueDepth,
|
||||
GLuint transparentTex, GLuint transparentDepth,
|
||||
GLuint paletteTex);
|
||||
void Draw();
|
||||
|
||||
private:
|
||||
|
|
|
@ -50,6 +50,14 @@ public:
|
|||
}
|
||||
return _instances[_numInstances++];
|
||||
}
|
||||
T& insert(const T &value)
|
||||
{
|
||||
if (_numInstances + 1 > _instances.size())
|
||||
{
|
||||
_instances.resize((_numInstances + 1) << 1);
|
||||
}
|
||||
return _instances[_numInstances++] = value;
|
||||
}
|
||||
size_t size() const
|
||||
{
|
||||
return _numInstances;
|
||||
|
@ -62,6 +70,14 @@ public:
|
|||
{
|
||||
return _instances.at(idx);
|
||||
}
|
||||
typename std::vector<T>::iterator begin()
|
||||
{
|
||||
return _instances.begin();
|
||||
}
|
||||
typename std::vector<T>::iterator end()
|
||||
{
|
||||
return _instances.begin() + _numInstances;
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawLineCommand
|
||||
|
|
|
@ -94,6 +94,9 @@ DrawRectShader::DrawRectShader() : OpenGLShaderProgram("drawrect")
|
|||
Use();
|
||||
glUniform1i(uTexture, 0);
|
||||
glUniform1i(uPaletteTex, 1);
|
||||
|
||||
glUniform1i(uPeelingTex, 2);
|
||||
glUniform1i(uPeeling, 0);
|
||||
}
|
||||
|
||||
DrawRectShader::~DrawRectShader()
|
||||
|
@ -109,6 +112,9 @@ void DrawRectShader::GetLocations()
|
|||
uTexture = GetUniformLocation("uTexture");
|
||||
uPaletteTex = GetUniformLocation("uPaletteTex");
|
||||
|
||||
uPeelingTex = GetUniformLocation("uPeelingTex");
|
||||
uPeeling = GetUniformLocation("uPeeling");
|
||||
|
||||
vClip = GetAttributeLocation("vClip");
|
||||
vTexColourAtlas = GetAttributeLocation("vTexColourAtlas");
|
||||
vTexColourBounds = GetAttributeLocation("vTexColourBounds");
|
||||
|
@ -129,14 +135,31 @@ void DrawRectShader::SetScreenSize(sint32 width, sint32 height)
|
|||
glUniform2i(uScreenSize, width, height);
|
||||
}
|
||||
|
||||
void DrawRectShader::DrawInstances(const RectCommandBatch& instances)
|
||||
void DrawRectShader::EnablePeeling(GLuint peelingTex)
|
||||
{
|
||||
OpenGLAPI::SetTexture(2, GL_TEXTURE_2D, peelingTex);
|
||||
glUniform1i(uPeeling, 1);
|
||||
}
|
||||
|
||||
void DrawRectShader::DisablePeeling()
|
||||
{
|
||||
glUniform1i(uPeeling, 0);
|
||||
}
|
||||
|
||||
void DrawRectShader::SetInstances(const RectCommandBatch &instances)
|
||||
{
|
||||
glBindVertexArray(_vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboInstances);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(DrawRectCommand) * instances.size(), instances.data(), GL_STREAM_DRAW);
|
||||
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, (GLsizei)instances.size());
|
||||
_instanceCount = (GLsizei)instances.size();
|
||||
}
|
||||
|
||||
void DrawRectShader::DrawInstances()
|
||||
{
|
||||
glBindVertexArray(_vao);
|
||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, _instanceCount);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -29,6 +29,9 @@ private:
|
|||
GLuint uTexture;
|
||||
GLuint uPaletteTex;
|
||||
|
||||
GLuint uPeelingTex;
|
||||
GLuint uPeeling;
|
||||
|
||||
GLuint vVertMat;
|
||||
GLuint vVertVec;
|
||||
|
||||
|
@ -47,12 +50,18 @@ private:
|
|||
GLuint _vboInstances;
|
||||
GLuint _vao;
|
||||
|
||||
GLsizei _instanceCount;
|
||||
|
||||
public:
|
||||
DrawRectShader();
|
||||
~DrawRectShader() override;
|
||||
|
||||
void SetScreenSize(sint32 width, sint32 height);
|
||||
void DrawInstances(const RectCommandBatch& instances);
|
||||
void EnablePeeling(GLuint peelingTex);
|
||||
void DisablePeeling();
|
||||
|
||||
void SetInstances(const RectCommandBatch& instances);
|
||||
void DrawInstances();
|
||||
|
||||
private:
|
||||
void GetLocations();
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define glClearColor __static__glClearColor
|
||||
#define glCullFace __static__glCullFace
|
||||
#define glDeleteTextures __static__glDeleteTextures
|
||||
#define glDepthFunc __static__glDepthFunc
|
||||
#define glDisable __static__glDisable
|
||||
#define glDrawArrays __static__glDrawArrays
|
||||
#define glEnable __static__glEnable
|
||||
|
@ -60,6 +61,7 @@
|
|||
#undef glClearColor
|
||||
#undef glCullFace
|
||||
#undef glDeleteTextures
|
||||
#undef glDepthFunc
|
||||
#undef glDisable
|
||||
#undef glDrawArrays
|
||||
#undef glEnable
|
||||
|
@ -84,6 +86,7 @@ typedef void (APIENTRYP PFNGLCLEARPROC )(GLbitfield mask);
|
|||
typedef void (APIENTRYP PFNGLCLEARCOLORPROC )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
typedef void (APIENTRYP PFNGLCULLFACEPROC )(GLenum mode);
|
||||
typedef void (APIENTRYP PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint *textures);
|
||||
typedef void (APIENTRYP PFNGLDEPTHFUNCPROC )(GLenum func);
|
||||
typedef void (APIENTRYP PFNGLDISABLEPROC )(GLenum cap);
|
||||
typedef void (APIENTRYP PFNGLDRAWARRAYSPROC )(GLenum mode, GLint first, GLsizei count);
|
||||
typedef void (APIENTRYP PFNGLENABLEPROC )(GLenum cap);
|
||||
|
|
|
@ -27,6 +27,7 @@ OPENGL_PROC(PFNGLCLEARPROC, glClear)
|
|||
OPENGL_PROC(PFNGLCLEARCOLORPROC, glClearColor)
|
||||
OPENGL_PROC(PFNGLCULLFACEPROC, glCullFace)
|
||||
OPENGL_PROC(PFNGLDELETETEXTURESPROC, glDeleteTextures)
|
||||
OPENGL_PROC(PFNGLDEPTHFUNCPROC, glDepthFunc)
|
||||
OPENGL_PROC(PFNGLDISABLEPROC, glDisable)
|
||||
OPENGL_PROC(PFNGLDRAWARRAYSPROC, glDrawArrays)
|
||||
OPENGL_PROC(PFNGLENABLEPROC, glEnable)
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
#ifndef DISABLE_OPENGL
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
|
@ -97,7 +99,6 @@ public:
|
|||
|
||||
IDrawingEngine * GetEngine() override;
|
||||
TextureCache * GetTextureCache() const { return _textureCache; }
|
||||
SwapFramebuffer * GetSwapFramebuffer() const { return _swapFramebuffer; }
|
||||
const OpenGLFramebuffer & GetFinalFramebuffer() const { return _swapFramebuffer->GetFinalFramebuffer(); }
|
||||
|
||||
void Initialise();
|
||||
|
@ -116,10 +117,12 @@ public:
|
|||
|
||||
void FlushCommandBuffers();
|
||||
|
||||
void FlushLines(LineCommandBatch &batch);
|
||||
void FlushRectangles(RectCommandBatch &batch);
|
||||
void FlushLines();
|
||||
void FlushRectangles();
|
||||
void HandleTransparency();
|
||||
|
||||
void SetDPI(rct_drawpixelinfo * dpi);
|
||||
sint32 MaxTransparencyDepth();
|
||||
};
|
||||
|
||||
class OpenGLDrawingEngine : public IDrawingEngine
|
||||
|
@ -810,35 +813,75 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p
|
|||
void OpenGLDrawingContext::FlushCommandBuffers()
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
_swapFramebuffer->BindOpaque();
|
||||
FlushLines(_commandBuffers.lines);
|
||||
FlushRectangles(_commandBuffers.rects);
|
||||
_swapFramebuffer->BindTransparent();
|
||||
FlushRectangles(_commandBuffers.transparent);
|
||||
_swapFramebuffer->ApplyTransparency(*_applyTransparencyShader, _textureCache->GetPaletteTexture());
|
||||
_drawRectShader->Use();
|
||||
_drawRectShader->DisablePeeling();
|
||||
|
||||
FlushLines();
|
||||
FlushRectangles();
|
||||
|
||||
HandleTransparency();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushLines(LineCommandBatch &batch)
|
||||
void OpenGLDrawingContext::FlushLines()
|
||||
{
|
||||
if (batch.size() == 0) return;
|
||||
if (_commandBuffers.lines.size() == 0) return;
|
||||
|
||||
_drawLineShader->Use();
|
||||
_drawLineShader->DrawInstances(batch);
|
||||
_drawLineShader->DrawInstances(_commandBuffers.lines);
|
||||
|
||||
batch.clear();
|
||||
_commandBuffers.lines.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::FlushRectangles(RectCommandBatch &batch)
|
||||
void OpenGLDrawingContext::FlushRectangles()
|
||||
{
|
||||
if (batch.size() == 0) return;
|
||||
if (_commandBuffers.rects.size() == 0) return;
|
||||
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture());
|
||||
OpenGLAPI::SetTexture(1, GL_TEXTURE_RECTANGLE, _textureCache->GetPaletteTexture());
|
||||
|
||||
_drawRectShader->Use();
|
||||
_drawRectShader->DrawInstances(batch);
|
||||
_drawRectShader->SetInstances(_commandBuffers.rects);
|
||||
_drawRectShader->DrawInstances();
|
||||
|
||||
batch.clear();
|
||||
_commandBuffers.rects.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::HandleTransparency()
|
||||
{
|
||||
if (_commandBuffers.transparent.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_drawRectShader->Use();
|
||||
_drawRectShader->SetInstances(_commandBuffers.transparent);
|
||||
|
||||
sint32 max_depth = MaxTransparencyDepth();
|
||||
for (sint32 i=0; i < max_depth; ++i)
|
||||
{
|
||||
_swapFramebuffer->BindTransparent();
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthFunc(GL_GREATER);
|
||||
_drawRectShader->Use();
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
_drawRectShader->EnablePeeling(_swapFramebuffer->GetBackDepthTexture());
|
||||
}
|
||||
|
||||
OpenGLAPI::SetTexture(0, GL_TEXTURE_2D_ARRAY, _textureCache->GetAtlasesTexture());
|
||||
OpenGLAPI::SetTexture(1, GL_TEXTURE_RECTANGLE, _textureCache->GetPaletteTexture());
|
||||
|
||||
_drawRectShader->Use();
|
||||
_drawRectShader->DrawInstances();
|
||||
_swapFramebuffer->ApplyTransparency(*_applyTransparencyShader, _textureCache->GetPaletteTexture());
|
||||
}
|
||||
|
||||
_commandBuffers.transparent.clear();
|
||||
}
|
||||
|
||||
void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi)
|
||||
|
@ -862,4 +905,142 @@ void OpenGLDrawingContext::SetDPI(rct_drawpixelinfo * dpi)
|
|||
_dpi = dpi;
|
||||
}
|
||||
|
||||
sint32 OpenGLDrawingContext::MaxTransparencyDepth()
|
||||
{
|
||||
sint32 max_depth = 1;
|
||||
|
||||
struct xdata
|
||||
{
|
||||
sint32 xposition;
|
||||
bool begin;
|
||||
sint32 top, bottom;
|
||||
};
|
||||
std::vector<xdata> x_sweep;
|
||||
x_sweep.reserve(_commandBuffers.transparent.size() * 2);
|
||||
for (DrawRectCommand &command : _commandBuffers.transparent)
|
||||
{
|
||||
sint32 left = std::min(std::max(command.bounds.x, command.clip.x), command.clip.z);
|
||||
sint32 top = std::min(std::max(command.bounds.y, command.clip.y), command.clip.w);
|
||||
sint32 right = std::min(std::max(command.bounds.z, command.clip.x), command.clip.z);
|
||||
sint32 bottom = std::min(std::max(command.bounds.w, command.clip.y), command.clip.w);
|
||||
|
||||
assert(left <= right);
|
||||
assert(top <= bottom);
|
||||
if (left == right) continue;
|
||||
if (top == bottom) continue;
|
||||
|
||||
x_sweep.push_back({left, true, top, bottom});
|
||||
x_sweep.push_back({right, false, top, bottom});
|
||||
}
|
||||
std::sort(x_sweep.begin(), x_sweep.end(), [](const xdata &a, const xdata &b) -> bool {
|
||||
if (a.xposition != b.xposition) return a.xposition < b.xposition;
|
||||
else return !a.begin && b.begin;
|
||||
});
|
||||
|
||||
struct ydata
|
||||
{
|
||||
sint32 count, depth;
|
||||
};
|
||||
std::map<sint32, ydata> y_intersect;
|
||||
for (const xdata &x : x_sweep)
|
||||
{
|
||||
assert(y_intersect.size() == 0 || y_intersect.begin()->second.depth == 0);
|
||||
if (x.begin)
|
||||
{
|
||||
auto top_in = y_intersect.insert({x.top, {1, 0}});
|
||||
auto top_it = top_in.first;
|
||||
if (top_in.second)
|
||||
{
|
||||
auto top_next = std::next(top_it);
|
||||
if (top_next != y_intersect.end())
|
||||
{
|
||||
top_it->second.depth = top_next->second.depth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(top_it->second.count > 0);
|
||||
++top_it->second.count;
|
||||
}
|
||||
|
||||
auto bottom_in = y_intersect.insert({x.bottom, {1, 1}});
|
||||
auto bottom_it = bottom_in.first;
|
||||
if (bottom_in.second)
|
||||
{
|
||||
auto bottom_next = std::next(bottom_it);
|
||||
if (bottom_next != y_intersect.end())
|
||||
{
|
||||
bottom_it->second.depth = bottom_next->second.depth + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(bottom_it->second.count > 0);
|
||||
++bottom_it->second.count;
|
||||
max_depth = std::max(max_depth, ++bottom_it->second.depth);
|
||||
}
|
||||
|
||||
for (auto it = std::next(top_it); it != bottom_it; ++it)
|
||||
{
|
||||
max_depth = std::max(max_depth, ++it->second.depth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto top_it = y_intersect.find(x.top);
|
||||
assert(top_it != y_intersect.end());
|
||||
assert(top_it->second.count > 0);
|
||||
auto bottom_it = y_intersect.find(x.bottom);
|
||||
assert(bottom_it != y_intersect.end());
|
||||
assert(bottom_it->second.count > 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
auto top_next = std::next(top_it);
|
||||
assert(top_next == y_intersect.end() ?
|
||||
top_it->second.depth == 0 :
|
||||
top_it->second.depth == top_next->second.depth - 1);
|
||||
}
|
||||
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
auto bottom_next = std::next(bottom_it);
|
||||
assert(bottom_next == y_intersect.end() ?
|
||||
bottom_it->second.depth == 1 :
|
||||
bottom_it->second.depth == bottom_next->second.depth + 1);
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
||||
for (auto it = std::next(top_it); it != bottom_it; ++it)
|
||||
{
|
||||
assert(it->second.depth > 0);
|
||||
--it->second.depth;
|
||||
}
|
||||
|
||||
if (top_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(top_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
--top_it->second.count;
|
||||
}
|
||||
|
||||
if (bottom_it->second.count == 1)
|
||||
{
|
||||
y_intersect.erase(bottom_it);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(bottom_it->second.depth > 0);
|
||||
--bottom_it->second.count;
|
||||
--bottom_it->second.depth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max_depth;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -44,12 +44,7 @@ OpenGLFramebuffer::OpenGLFramebuffer(sint32 width, sint32 height, bool depth)
|
|||
|
||||
if (depth)
|
||||
{
|
||||
glGenTextures(1, &_depth);
|
||||
glBindTexture(GL_TEXTURE_2D, _depth);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
_depth = CreateDepthTexture(width, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -93,7 +88,9 @@ void OpenGLFramebuffer::GetPixels(rct_drawpixelinfo &dpi) const
|
|||
assert(dpi.width == _width && dpi.height == _height);
|
||||
|
||||
uint8 * pixels = Memory::Allocate<uint8>(_width * _height);
|
||||
glReadPixels(0, 0, _width, _height, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
|
||||
glBindTexture(GL_TEXTURE_2D, _texture);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Flip pixels vertically on copy
|
||||
uint8 * src = pixels + ((_height - 1) * _width);
|
||||
|
@ -107,4 +104,37 @@ void OpenGLFramebuffer::GetPixels(rct_drawpixelinfo &dpi) const
|
|||
Memory::Free(pixels);
|
||||
}
|
||||
|
||||
void OpenGLFramebuffer::SwapColourBuffer(OpenGLFramebuffer &other)
|
||||
{
|
||||
std::swap(_texture, other._texture);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, other._id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, other._texture, 0);
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::SwapDepthTexture(GLuint depth)
|
||||
{
|
||||
std::swap(_depth, depth);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, _id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depth, 0);
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
GLuint OpenGLFramebuffer::CreateDepthTexture(sint32 width, sint32 height)
|
||||
{
|
||||
GLuint depth;
|
||||
glGenTextures(1, &depth);
|
||||
glBindTexture(GL_TEXTURE_2D, depth);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width, height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
return depth;
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -38,6 +38,9 @@ public:
|
|||
OpenGLFramebuffer(sint32 width, sint32 height, bool depth = true);
|
||||
~OpenGLFramebuffer();
|
||||
|
||||
OpenGLFramebuffer(const OpenGLFramebuffer &) = delete;
|
||||
OpenGLFramebuffer &operator=(const OpenGLFramebuffer &) = delete;
|
||||
|
||||
GLuint GetWidth() const { return _width; }
|
||||
GLuint GetHeight() const { return _height; }
|
||||
GLuint GetTexture() const { return _texture; }
|
||||
|
@ -47,4 +50,9 @@ public:
|
|||
void BindDraw() const;
|
||||
void BindRead() const;
|
||||
void GetPixels(rct_drawpixelinfo &dpi) const;
|
||||
|
||||
void SwapColourBuffer(OpenGLFramebuffer &other);
|
||||
GLuint SwapDepthTexture(GLuint depth);
|
||||
|
||||
static GLuint CreateDepthTexture(sint32 width, sint32 height);
|
||||
};
|
||||
|
|
|
@ -20,24 +20,21 @@
|
|||
#include "OpenGLFramebuffer.h"
|
||||
#include "SwapFramebuffer.h"
|
||||
|
||||
constexpr GLfloat depthValue[1] = { 1.0f };
|
||||
constexpr GLfloat depthValueTransparent[1] = { 0.0f };
|
||||
constexpr GLuint indexValue[4] = { 0, 0, 0, 0 };
|
||||
|
||||
SwapFramebuffer::SwapFramebuffer(sint32 width, sint32 height) :
|
||||
_opaqueFramebuffer(width, height), _transparentFramebuffer(width, height),
|
||||
_finalFramebuffer(width, height, false)
|
||||
{ }
|
||||
|
||||
void SwapFramebuffer::BindOpaque()
|
||||
{
|
||||
_opaqueFramebuffer.Bind();
|
||||
}
|
||||
|
||||
void SwapFramebuffer::BindTransparent()
|
||||
_mixFramebuffer(width, height, false), _backDepth(OpenGLFramebuffer::CreateDepthTexture(width, height))
|
||||
{
|
||||
_transparentFramebuffer.Bind();
|
||||
glClearBufferfv(GL_DEPTH, 0, depthValueTransparent);
|
||||
}
|
||||
|
||||
void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader &shader, GLuint paletteTex)
|
||||
{
|
||||
_finalFramebuffer.Bind();
|
||||
_mixFramebuffer.Bind();
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
shader.Use();
|
||||
shader.SetTextures(
|
||||
|
@ -49,21 +46,22 @@ void SwapFramebuffer::ApplyTransparency(ApplyTransparencyShader &shader, GLuint
|
|||
);
|
||||
shader.Draw();
|
||||
|
||||
_backDepth = _transparentFramebuffer.SwapDepthTexture(_backDepth);
|
||||
|
||||
// Clear transparency buffers
|
||||
_transparentFramebuffer.Bind();
|
||||
glClearBufferuiv(GL_COLOR, 0, indexValue);
|
||||
glClearBufferfv(GL_DEPTH, 0, depthValueTransparent);
|
||||
|
||||
_opaqueFramebuffer.SwapColourBuffer(_mixFramebuffer);
|
||||
//Change binding to guaruntee no undefined behavior
|
||||
_opaqueFramebuffer.Bind();
|
||||
}
|
||||
|
||||
void SwapFramebuffer::Clear()
|
||||
{
|
||||
static const GLfloat depthValue[1] = { 1.0f };
|
||||
static const GLuint indexValue[4] = { 0, 0, 0, 0 };
|
||||
|
||||
_opaqueFramebuffer.Bind();
|
||||
glClearBufferfv(GL_DEPTH, 0, depthValue);
|
||||
|
||||
_transparentFramebuffer.Bind();
|
||||
glClearBufferuiv(GL_COLOR, 0, indexValue);
|
||||
glClearBufferfv(GL_DEPTH, 0, depthValue);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_OPENGL */
|
||||
|
|
|
@ -36,18 +36,17 @@ class SwapFramebuffer final
|
|||
private:
|
||||
OpenGLFramebuffer _opaqueFramebuffer;
|
||||
OpenGLFramebuffer _transparentFramebuffer;
|
||||
OpenGLFramebuffer _finalFramebuffer;
|
||||
OpenGLFramebuffer _mixFramebuffer;
|
||||
GLuint _backDepth;
|
||||
|
||||
public:
|
||||
SwapFramebuffer(sint32 width, sint32 height);
|
||||
|
||||
const OpenGLFramebuffer &GetOpaqueFramebuffer() const { return _opaqueFramebuffer; }
|
||||
const OpenGLFramebuffer &GetTransparentFramebuffer() const { return _transparentFramebuffer; }
|
||||
const OpenGLFramebuffer &GetFinalFramebuffer() const { return _finalFramebuffer; }
|
||||
GLuint GetFinalTexture() const { return _finalFramebuffer.GetTexture(); }
|
||||
const OpenGLFramebuffer &GetFinalFramebuffer() const { return _opaqueFramebuffer; }
|
||||
GLuint GetBackDepthTexture() const { return _backDepth; }
|
||||
void BindOpaque() { _opaqueFramebuffer.Bind(); }
|
||||
void BindTransparent() { _transparentFramebuffer.Bind(); }
|
||||
|
||||
void BindOpaque();
|
||||
void BindTransparent();
|
||||
void ApplyTransparency(ApplyTransparencyShader &shader, GLuint paletteTex);
|
||||
void Clear();
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue