diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ed9eee..4a86cd2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,6 +10,7 @@ endif() find_package(raylib REQUIRED) find_package(RmlUi REQUIRED) +find_package(OpenGL REQUIRED) add_library(rmlui_backend STATIC src/backend/RaylibSystemInterface.cpp @@ -23,6 +24,7 @@ add_executable(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} PRIVATE raylib + OpenGL::GL rmlui_backend RmlUi::Core RmlUi::Debugger diff --git a/assets/main.rml b/assets/main.rml index fa19728..88b98a9 100644 --- a/assets/main.rml +++ b/assets/main.rml @@ -5,7 +5,8 @@

Hello from RmlUi

-
+
+
diff --git a/flake.lock b/flake.lock index 700d2c3..5d2aa29 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1788039129, - "narHash": "sha256-pa4Q0qErvCvzCaaUph7Sm37RhR4xvPrYI8Lgz6k85+A=", + "lastModified": 1788179007, + "narHash": "sha256-hn1oU2rue2SYK8dAr8+WNZWtbsz1S2W5mnHlSEuh3bo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "d2f67949798825fe853f7c5d0492b8bf016d3f88", + "rev": "34ab99075ac4f7e40cf037eef32cb1c360bb85e9", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 002a243..2576a7e 100644 --- a/flake.nix +++ b/flake.nix @@ -14,8 +14,8 @@ rmluiSrc = pkgs.fetchFromGitHub { owner = "mikke89"; repo = "RmlUi"; - rev = "9c74c4fadc2ad7f1496239e560bab19ca2fe5072"; - hash = "sha256-YZz41ViE3+a0VPypnbJ1Orlf5Hyxd65se5yzyHIY7ZI="; + tag = "6.3"; + hash = "sha256-ZoK6H3ldrgHjCoMgDg+6XAD+ZaCwLuUgPq0fK+GdlCs="; }; rmluiCmakeFlags = [ @@ -27,13 +27,23 @@ rmlui = pkgs.stdenv.mkDerivation { pname = "rmlui"; - version = "master"; + version = "6.3"; src = rmluiSrc; nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ]; buildInputs = [ pkgs.freetype ]; 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; [ cmake pkg-config @@ -41,7 +51,7 @@ ]; nativeRuntimeDeps = with pkgs; [ - raylib + raylibPatched libGL libX11 libXcursor @@ -79,6 +89,8 @@ --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath nativeRuntimeDeps}" ''; }; + + packages.raylibPatched = raylibPatched; } ); } diff --git a/readme.md b/readme.md index 2af3ca0..7abf2c2 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ I originally began creating this for a Game Jam project where I got the basic re ## Roadmap *Rendering features (from the RmlUi render interfface documentation https://mikke89.github.io/RmlUiDoc/pages/cpp_manual/interfaces/render.html#feature-table):* - [x] Basic rendering -- [ ] Clip Mask +- [x] Clip Mask - [x] Transforms - [ ] Layers - [ ] Render textures diff --git a/src/backend/RaylibRenderInterface.cpp b/src/backend/RaylibRenderInterface.cpp index 90b5c7c..ea908b0 100644 --- a/src/backend/RaylibRenderInterface.cpp +++ b/src/backend/RaylibRenderInterface.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -127,3 +129,77 @@ void RaylibRenderInterface::SetTransform(const Rml::Matrix4f *transform) { has_transform = false; } } + +void RaylibRenderInterface::DrawGeometryTriangles(Rml::CompiledGeometryHandle handle, + Rml::Vector2f translation) { + auto *geo = reinterpret_cast(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(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(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(clip_mask_level), 0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); +} diff --git a/src/backend/RaylibRenderInterface.h b/src/backend/RaylibRenderInterface.h index 45de261..bfefe7b 100644 --- a/src/backend/RaylibRenderInterface.h +++ b/src/backend/RaylibRenderInterface.h @@ -32,6 +32,11 @@ public: 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: void ApplyScissor(); @@ -40,4 +45,8 @@ private: bool has_transform = false; Rml::Matrix4f current_transform; + + bool clip_mask_enabled = false; + unsigned int clip_mask_level = 0; + void DrawGeometryTriangles(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation); }; diff --git a/src/main.cpp b/src/main.cpp index cd28cee..0f261a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,8 @@ #include "backend/RaylibSystemInterface.h" #include "backend/RaylibInput.h" +#include + static RaylibSystemInterface system_interface; static RaylibRenderInterface render_interface; static Rml::Context *ctx; @@ -24,12 +26,24 @@ int main() { Rml::SetSystemInterface(&system_interface); Rml::SetRenderInterface(&render_interface); Rml::Initialise(); + TraceLog(LOG_INFO, "RmlUi version: %s", Rml::GetVersion().c_str()); ctx = Rml::CreateContext("main", Rml::Vector2i(600, 800)); Rml::Debugger::Initialise(ctx); auto doc = ctx->LoadDocument("assets/main.rml"); 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()) { @@ -37,14 +51,24 @@ int main() { ctx->SetDimensions(Rml::Vector2i(GetScreenWidth(), GetScreenHeight())); } + // UpdateCamera(&cam3, CAMERA_FREE); + ForwardInputToRml(ctx); ctx->Update(); - + + if (IsKeyPressed(KEY_Z)) cam3.target = Vector3 {0.0f, 0.0f, 0.0f}; BeginDrawing(); ClearBackground(BLACK); 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(); EndDrawing(); }