Clip masks complete

This commit is contained in:
2026-08-31 16:45:25 -05:00
parent b75eebfd49
commit 260a037314
8 changed files with 135 additions and 11 deletions

View File

@@ -10,6 +10,7 @@ endif()
find_package(raylib REQUIRED) find_package(raylib REQUIRED)
find_package(RmlUi REQUIRED) find_package(RmlUi REQUIRED)
find_package(OpenGL REQUIRED)
add_library(rmlui_backend STATIC add_library(rmlui_backend STATIC
src/backend/RaylibSystemInterface.cpp src/backend/RaylibSystemInterface.cpp
@@ -23,6 +24,7 @@ add_executable(${PROJECT_NAME}
target_link_libraries(${PROJECT_NAME} PRIVATE target_link_libraries(${PROJECT_NAME} PRIVATE
raylib raylib
OpenGL::GL
rmlui_backend rmlui_backend
RmlUi::Core RmlUi::Core
RmlUi::Debugger RmlUi::Debugger

View File

@@ -5,7 +5,8 @@
</head> </head>
<body> <body>
<h1>Hello from RmlUi</h1> <h1>Hello from RmlUi</h1>
<div style="position:absolute; top: 0; left: 0; width: 200px; height: 100px; background-color: rgba(255, 0, 0, 128); transform: rotate(15deg) translate(50px,0) scale(0.8)"> <div style="position: relative; width: 300px; height: 200px; overflow: hidden; border-radius: 40px; background-color: #0000ff">
<div style="position: absolute; top: -20px; left: -20px; width: 150px; height: 150px; background-color: #ff0000; transform: rotate(15deg);"></div>
</div> </div>
</body> </body>
</rml> </rml>

6
flake.lock generated
View File

@@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1788039129, "lastModified": 1788179007,
"narHash": "sha256-pa4Q0qErvCvzCaaUph7Sm37RhR4xvPrYI8Lgz6k85+A=", "narHash": "sha256-hn1oU2rue2SYK8dAr8+WNZWtbsz1S2W5mnHlSEuh3bo=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "d2f67949798825fe853f7c5d0492b8bf016d3f88", "rev": "34ab99075ac4f7e40cf037eef32cb1c360bb85e9",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -14,8 +14,8 @@
rmluiSrc = pkgs.fetchFromGitHub { rmluiSrc = pkgs.fetchFromGitHub {
owner = "mikke89"; owner = "mikke89";
repo = "RmlUi"; repo = "RmlUi";
rev = "9c74c4fadc2ad7f1496239e560bab19ca2fe5072"; tag = "6.3";
hash = "sha256-YZz41ViE3+a0VPypnbJ1Orlf5Hyxd65se5yzyHIY7ZI="; hash = "sha256-ZoK6H3ldrgHjCoMgDg+6XAD+ZaCwLuUgPq0fK+GdlCs=";
}; };
rmluiCmakeFlags = [ rmluiCmakeFlags = [
@@ -27,13 +27,23 @@
rmlui = pkgs.stdenv.mkDerivation { rmlui = pkgs.stdenv.mkDerivation {
pname = "rmlui"; pname = "rmlui";
version = "master"; version = "6.3";
src = rmluiSrc; src = rmluiSrc;
nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ]; nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ];
buildInputs = [ pkgs.freetype ]; buildInputs = [ pkgs.freetype ];
cmakeFlags = rmluiCmakeFlags ++ [ "-DBUILD_SHARED_LIBS=ON" ]; cmakeFlags = rmluiCmakeFlags ++ [ "-DBUILD_SHARED_LIBS=ON" ];
}; };
raylibPatched = pkgs.raylib.overrideAttrs (old: {
postPatch = (old.postPatch or "") + ''
substituteInPlace src/platforms/rcore_desktop_glfw.c \
--replace-fail \
'glfwSetJoystickCallback(NULL);' \
'glfwWindowHint(GLFW_STENCIL_BITS, 8);
glfwSetJoystickCallback(NULL);'
'';
});
nativeBuildTools = with pkgs; [ nativeBuildTools = with pkgs; [
cmake cmake
pkg-config pkg-config
@@ -41,7 +51,7 @@
]; ];
nativeRuntimeDeps = with pkgs; [ nativeRuntimeDeps = with pkgs; [
raylib raylibPatched
libGL libGL
libX11 libX11
libXcursor libXcursor
@@ -79,6 +89,8 @@
--prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath nativeRuntimeDeps}" --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath nativeRuntimeDeps}"
''; '';
}; };
packages.raylibPatched = raylibPatched;
} }
); );
} }

View File

@@ -7,7 +7,7 @@ I originally began creating this for a Game Jam project where I got the basic re
## Roadmap ## Roadmap
*Rendering features (from the RmlUi render interfface documentation https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/interfaces/render.html#feature-table):* *Rendering features (from the RmlUi render interfface documentation https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/interfaces/render.html#feature-table):*
- [x] Basic rendering - [x] Basic rendering
- [ ] Clip Mask - [x] Clip Mask
- [x] Transforms - [x] Transforms
- [ ] Layers - [ ] Layers
- [ ] Render textures - [ ] Render textures

View File

@@ -3,6 +3,8 @@
#include <raylib.h> #include <raylib.h>
#include <rlgl.h> #include <rlgl.h>
#include <GL/gl.h>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
@@ -127,3 +129,77 @@ void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) {
has_transform = false; has_transform = false;
} }
} }
void RaylibRenderInterface::DrawGeometryTriangles(Rml::CompiledGeometryHandle handle,
Rml::Vector2f translation) {
auto *geo = reinterpret_cast<GeometryData *>(handle);
rlPushMatrix();
rlTranslatef(translation.x, translation.y, 0.0f);
if (has_transform) {
rlMultMatrixf(current_transform.data());
}
rlBegin(RL_TRIANGLES);
for (size_t i = 0; i + 2 < geo->indices.size(); i += 3) {
for (int j = 0; j < 3; ++j) {
const Rml::Vertex &v = geo->vertices[geo->indices[i + j]];
rlVertex2f(v.position.x, v.position.y);
}
}
rlEnd();
rlPopMatrix();
}
void RaylibRenderInterface::EnableClipMask(bool enable) {
rlDrawRenderBatchActive();
clip_mask_enabled = enable;
if (enable) {
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
} else {
glDisable(GL_STENCIL_TEST);
}
}
void RaylibRenderInterface::RenderToClipMask(Rml::ClipMaskOperation operation,
Rml::CompiledGeometryHandle geometry,
Rml::Vector2f translation) {
rlDrawRenderBatchActive();
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
switch (operation) {
case Rml::ClipMaskOperation::Set:
glClearStencil(0);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 1, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
clip_mask_level = 1;
break;
case Rml::ClipMaskOperation::SetInverse:
glClearStencil(1);
glClear(GL_STENCIL_BUFFER_BIT);
glStencilFunc(GL_ALWAYS, 0, 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
clip_mask_level = 1;
break;
case Rml::ClipMaskOperation::Intersect:
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
clip_mask_level += 1;
break;
}
DrawGeometryTriangles(geometry, translation);
rlDrawRenderBatchActive();
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(GL_EQUAL, static_cast<GLint>(clip_mask_level), 0xFF);
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
}

View File

@@ -32,6 +32,11 @@ public:
void SetTransform(const Rml::Matrix4f *transform) override; void SetTransform(const Rml::Matrix4f *transform) override;
void EnableClipMask(bool enable) override;
void RenderToClipMask(Rml::ClipMaskOperation operation,
Rml::CompiledGeometryHandle geometry,
Rml::Vector2f translation) override;
private: private:
void ApplyScissor(); void ApplyScissor();
@@ -40,4 +45,8 @@ private:
bool has_transform = false; bool has_transform = false;
Rml::Matrix4f current_transform; Rml::Matrix4f current_transform;
bool clip_mask_enabled = false;
unsigned int clip_mask_level = 0;
void DrawGeometryTriangles(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation);
}; };

View File

@@ -10,6 +10,8 @@
#include "backend/RaylibSystemInterface.h" #include "backend/RaylibSystemInterface.h"
#include "backend/RaylibInput.h" #include "backend/RaylibInput.h"
#include <GL/gl.h>
static RaylibSystemInterface system_interface; static RaylibSystemInterface system_interface;
static RaylibRenderInterface render_interface; static RaylibRenderInterface render_interface;
static Rml::Context *ctx; static Rml::Context *ctx;
@@ -24,12 +26,24 @@ int main() {
Rml::SetSystemInterface(&system_interface); Rml::SetSystemInterface(&system_interface);
Rml::SetRenderInterface(&render_interface); Rml::SetRenderInterface(&render_interface);
Rml::Initialise(); Rml::Initialise();
TraceLog(LOG_INFO, "RmlUi version: %s", Rml::GetVersion().c_str());
ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800)); ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800));
Rml::Debugger::Initialise(ctx); Rml::Debugger::Initialise(ctx);
auto doc = ctx->LoadDocument("assets/main.rml"); auto doc = ctx->LoadDocument("assets/main.rml");
doc->Show(); doc->Show();
Camera3D cam3;
cam3.position = Vector3 {0.0f, 10.0f, 10.0f};
cam3.target = Vector3 {0.0f, 0.0f, 0.0f};
cam3.up = Vector3 {0, 1.0f, 0.0f};
cam3.fovy = 45.0f;
cam3.projection = CAMERA_PERSPECTIVE;
Vector3 cubePos = Vector3 {0.0f, 0.0f, 0.0f};
// DisableCursor();
while (!WindowShouldClose()) { while (!WindowShouldClose()) {
@@ -37,14 +51,24 @@ int main() {
ctx->SetDimensions(Rml::Vector2i(GetScreenWidth(), GetScreenHeight())); ctx->SetDimensions(Rml::Vector2i(GetScreenWidth(), GetScreenHeight()));
} }
// UpdateCamera(&cam3, CAMERA_FREE);
ForwardInputToRml(ctx); ForwardInputToRml(ctx);
ctx->Update(); ctx->Update();
if (IsKeyPressed(KEY_Z)) cam3.target = Vector3 {0.0f, 0.0f, 0.0f};
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(BLACK);
DrawFPS(10, 10); DrawFPS(10, 10);
DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10, RAYWHITE); // DrawText("Hello!", GetScreenWidth()/2, GetScreenHeight()/2, 10, RAYWHITE);
BeginMode3D(cam3);
DrawCube(cubePos, 2.0f, 2.0f, 2.0f, RED);
DrawCubeWires(cubePos, 2.0f, 2.0f, 2.0f, BLUE);
DrawGrid(10, 1.0f);
EndMode3D();
ctx->Render(); ctx->Render();
EndDrawing(); EndDrawing();
} }