Skip to content

Commit

Permalink
Implement clip masks for the GL2 renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
mikke89 committed Sep 22, 2023
1 parent 6025aea commit 73dd1c1
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 47 deletions.
135 changes: 88 additions & 47 deletions Backends/RmlUi_Renderer_GL2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ void RenderInterface_GL2::BeginFrame()
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 1, GLuint(-1));
glStencilMask(GLuint(-1));
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

Rml::Matrix4f projection = Rml::Matrix4f::ProjectOrtho(0, (float)viewport_width, (float)viewport_height, 0, -10000, 10000);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(projection.data());
Expand All @@ -88,13 +93,40 @@ void RenderInterface_GL2::EndFrame() {}
void RenderInterface_GL2::Clear()
{
glClearStencil(0);
glClearColor(0, 0, 0, 1);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}

void RenderInterface_GL2::RenderGeometry(Rml::Vertex* vertices, int /*num_vertices*/, int* indices, int num_indices, const Rml::TextureHandle texture,
void RenderInterface_GL2::RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rml::TextureHandle texture,
const Rml::Vector2f& translation)
{
Rml::CompiledGeometryHandle geometry = CompileGeometry(vertices, num_vertices, indices, num_indices);

if (geometry)
{
RenderCompiledGeometry(geometry, translation, texture);
ReleaseCompiledGeometry(geometry);
}
}

Rml::CompiledGeometryHandle RenderInterface_GL2::CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices)
{
GeometryView* data = new GeometryView{vertices, indices, num_vertices, num_indices};
return reinterpret_cast<Rml::CompiledGeometryHandle>(data);
}

void RenderInterface_GL2::ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry)
{
delete reinterpret_cast<GeometryView*>(geometry);
}

void RenderInterface_GL2::RenderCompiledGeometry(Rml::CompiledGeometryHandle handle, const Rml::Vector2f& translation, Rml::TextureHandle texture)
{
const GeometryView* geometry = reinterpret_cast<GeometryView*>(handle);
const Rml::Vertex* vertices = geometry->vertices;
const int* indices = geometry->indices;
const int num_indices = geometry->num_indices;

glPushMatrix();
glTranslatef(translation.x, translation.y, 0);

Expand Down Expand Up @@ -125,62 +157,71 @@ void RenderInterface_GL2::RenderGeometry(Rml::Vertex* vertices, int /*num_vertic
void RenderInterface_GL2::EnableScissorRegion(bool enable)
{
if (enable)
{
if (!transform_enabled)
{
glEnable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
}
else
{
glDisable(GL_SCISSOR_TEST);
glEnable(GL_STENCIL_TEST);
}
}
glEnable(GL_SCISSOR_TEST);
else
{
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
}
}

void RenderInterface_GL2::SetScissorRegion(int x, int y, int width, int height)
{
if (!transform_enabled)
{
glScissor(x, viewport_height - (y + height), width, height);
}
glScissor(x, viewport_height - (y + height), width, height);
}

void RenderInterface_GL2::EnableClipMask(bool enable)
{
if (enable)
glEnable(GL_STENCIL_TEST);
else
glDisable(GL_STENCIL_TEST);
}

void RenderInterface_GL2::RenderToClipMask(Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation)
{
RMLUI_ASSERT(glIsEnabled(GL_STENCIL_TEST));
using Rml::ClipMaskOperation;

const bool clear_stencil = (operation == ClipMaskOperation::Set || operation == ClipMaskOperation::SetInverse);
if (clear_stencil)
{
// clear the stencil buffer
glStencilMask(GLuint(-1));
// @performance Increment the reference value instead of clearing each time.
glClear(GL_STENCIL_BUFFER_BIT);
}

// fill the stencil buffer
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glDepthMask(GL_FALSE);
glStencilFunc(GL_NEVER, 1, GLuint(-1));
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP);

float fx = (float)x;
float fy = (float)y;
float fwidth = (float)width;
float fheight = (float)height;

// draw transformed quad
GLfloat vertices[] = {fx, fy, 0, fx, fy + fheight, 0, fx + fwidth, fy + fheight, 0, fx + fwidth, fy, 0};
glDisableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
GLushort indices[] = {1, 2, 0, 3};
glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices);
glEnableClientState(GL_COLOR_ARRAY);

// prepare for drawing the real thing
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDepthMask(GL_TRUE);
glStencilMask(0);
glStencilFunc(GL_EQUAL, 1, GLuint(-1));
GLint stencil_test_value = 0;
glGetIntegerv(GL_STENCIL_REF, &stencil_test_value);

glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glStencilFunc(GL_ALWAYS, GLint(1), GLuint(-1));

switch (operation)
{
case ClipMaskOperation::Set:
{
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
stencil_test_value = 1;
}
break;
case ClipMaskOperation::SetInverse:
{
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
stencil_test_value = 0;
}
break;
case ClipMaskOperation::Intersect:
{
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
stencil_test_value += 1;
}
break;
}

RenderCompiledGeometry(geometry, translation, {});

// Restore state
// @performance Cache state so we don't toggle it unnecessarily.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
glStencilFunc(GL_EQUAL, stencil_test_value, GLuint(-1));
}

// Set to byte packing, or the compiler will expand our struct, which means it won't read correctly from file
Expand Down
13 changes: 13 additions & 0 deletions Backends/RmlUi_Renderer_GL2.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,18 @@ class RenderInterface_GL2 : public Rml::RenderInterface {

// -- Inherited from Rml::RenderInterface --

Rml::CompiledGeometryHandle CompileGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices) override;
void ReleaseCompiledGeometry(Rml::CompiledGeometryHandle geometry) override;
void RenderCompiledGeometry(Rml::CompiledGeometryHandle handle, const Rml::Vector2f& translation, Rml::TextureHandle texture);
void RenderGeometry(Rml::Vertex* vertices, int num_vertices, int* indices, int num_indices, Rml::TextureHandle texture,
const Rml::Vector2f& translation) override;

void EnableScissorRegion(bool enable) override;
void SetScissorRegion(int x, int y, int width, int height) override;

void EnableClipMask(bool enable);
void RenderToClipMask(Rml::ClipMaskOperation operation, Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation);

bool LoadTexture(Rml::TextureHandle& texture_handle, Rml::Vector2i& texture_dimensions, const Rml::String& source) override;
bool GenerateTexture(Rml::TextureHandle& texture_handle, const Rml::byte* source, const Rml::Vector2i& source_dimensions) override;
void ReleaseTexture(Rml::TextureHandle texture_handle) override;
Expand All @@ -63,6 +69,13 @@ class RenderInterface_GL2 : public Rml::RenderInterface {
static const Rml::TextureHandle TextureEnableWithoutBinding = Rml::TextureHandle(-1);

private:
struct GeometryView {
Rml::Vertex* vertices = nullptr;
int* indices = nullptr;
int num_vertices = 0;
int num_indices = 0;
};

int viewport_width = 0;
int viewport_height = 0;
bool transform_enabled = false;
Expand Down

0 comments on commit 73dd1c1

Please sign in to comment.