Added raylib+rmlui template
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
build/
|
||||||
|
build-wasm/
|
||||||
|
.envrc
|
||||||
|
.direnv/
|
||||||
|
.vscode/
|
||||||
|
result
|
||||||
|
.cache/
|
||||||
|
compile_commands.json
|
||||||
69
CMakeLists.txt
Normal file
69
CMakeLists.txt
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(gamejam LANGUAGES C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Dependencies
|
||||||
|
#
|
||||||
|
# Native build: raylib + RmlUi come from nixpkgs / the `rmlui` derivation,
|
||||||
|
# found on the default system paths set up by the dev shell.
|
||||||
|
#
|
||||||
|
# Wasm build: raylib + RmlUi come from the `raylibWasm` / `rmluiWasm`
|
||||||
|
# derivations, located via -DCMAKE_PREFIX_PATH set by devShells.wasm.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
find_package(raylib REQUIRED)
|
||||||
|
find_package(RmlUi REQUIRED)
|
||||||
|
|
||||||
|
add_executable(gamejam
|
||||||
|
src/main.cpp
|
||||||
|
src/Application.cpp
|
||||||
|
src/backend/RaylibSystemInterface.cpp
|
||||||
|
src/backend/RaylibRenderInterface.cpp
|
||||||
|
src/backend/RaylibInput.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(gamejam PRIVATE
|
||||||
|
raylib
|
||||||
|
RmlUi::Core
|
||||||
|
RmlUi::Debugger
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(gamejam PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
||||||
|
|
||||||
|
set(ASSET_DIR ${CMAKE_SOURCE_DIR}/assets)
|
||||||
|
|
||||||
|
if(EMSCRIPTEN)
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
# Wasm-specific settings
|
||||||
|
# -----------------------------------------------------------------------
|
||||||
|
set(CMAKE_EXECUTABLE_SUFFIX ".html")
|
||||||
|
|
||||||
|
target_link_options(gamejam PRIVATE
|
||||||
|
"-sUSE_GLFW=3"
|
||||||
|
"-sASYNCIFY"
|
||||||
|
"-sALLOW_MEMORY_GROWTH=1"
|
||||||
|
"-sFORCE_FILESYSTEM=1"
|
||||||
|
"--preload-file=${ASSET_DIR}@assets"
|
||||||
|
# "--shell-file=${CMAKE_SOURCE_DIR}/shell.html"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
else()
|
||||||
|
add_custom_command(TARGET gamejam POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
|
${ASSET_DIR} $<TARGET_FILE_DIR:gamejam>/assets
|
||||||
|
COMMENT "Copying assets to build output"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
install(TARGETS gamejam RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
|
install(DIRECTORY ${ASSET_DIR} DESTINATION bin)
|
||||||
|
endif()
|
||||||
39
assets/main.rcss
Normal file
39
assets/main.rcss
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
body {
|
||||||
|
font-family: rmlui-debugger-font;
|
||||||
|
font-size: 16px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#panel {
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
left: 40px;
|
||||||
|
width: 300px;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: rgba(20, 20, 20, 220);
|
||||||
|
border: 2px #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
color: #ffd35c;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#start-btn {
|
||||||
|
display: block;
|
||||||
|
width: 100px;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #3a6ea5;
|
||||||
|
color: white;
|
||||||
|
border: 1px #5a8ec5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#start-btn:hover {
|
||||||
|
background-color: #4a7eb5;
|
||||||
|
}
|
||||||
13
assets/main.rml
Normal file
13
assets/main.rml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<rml>
|
||||||
|
<head>
|
||||||
|
<title>gamejam</title>
|
||||||
|
<link type="text/rcss" href="main.rcss"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="panel">
|
||||||
|
<h1>gamejam</h1>
|
||||||
|
<p>RmlUi + raylib scaffold is alive.</p>
|
||||||
|
<button id="start-btn">Start</button>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</rml>
|
||||||
61
flake.lock
generated
Normal file
61
flake.lock
generated
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1787360063,
|
||||||
|
"narHash": "sha256-dt4WdcvsA8/RCe+VZZwqU0X+XMM3wBbGCWA0/sFWzGo=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "2c423e03bbafcff28bfadc6781a4a8257f205cb5",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"utils": "utils"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
195
flake.nix
Normal file
195
flake.nix
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
{
|
||||||
|
description = "Raylib + RmlUI gamejam dev environment (desktop + wasm)";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
utils.url = "github:numtide/flake-utils";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, utils }:
|
||||||
|
utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
pkgs = import nixpkgs { inherit system; };
|
||||||
|
|
||||||
|
rmluiSrc = pkgs.fetchFromGitHub {
|
||||||
|
owner = "mikke89";
|
||||||
|
repo = "RmlUi";
|
||||||
|
rev = "9c74c4fadc2ad7f1496239e560bab19ca2fe5072";
|
||||||
|
hash = "sha256-YZz41ViE3+a0VPypnbJ1Orlf5Hyxd65se5yzyHIY7ZI=";
|
||||||
|
};
|
||||||
|
|
||||||
|
rmluiCmakeFlags = [
|
||||||
|
"-DRMLUI_LUA_BINDINGS=OFF"
|
||||||
|
"-DRMLUI_SVG_PLUGIN=OFF"
|
||||||
|
"-DBUILD_SAMPLES=OFF"
|
||||||
|
"-DBUILD_TESTING=OFF"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Emscripten's toolchain file restricts find_library/find_path/find_package
|
||||||
|
# to CMAKE_FIND_ROOT_PATH (its own sysroot) by default. Our externally-built
|
||||||
|
# wasm deps (freetypeWasm, raylibWasm, rmluiWasm) live in the Nix store,
|
||||||
|
# outside that sysroot, so CMAKE_PREFIX_PATH alone is silently ignored
|
||||||
|
# unless we relax these three modes to BOTH.
|
||||||
|
wasmFindOverrides = [
|
||||||
|
"-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH"
|
||||||
|
"-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH"
|
||||||
|
"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH"
|
||||||
|
];
|
||||||
|
|
||||||
|
# ---- native RmlUi (shared lib) --------------------------------------
|
||||||
|
rmlui = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "rmlui";
|
||||||
|
version = "master";
|
||||||
|
src = rmluiSrc;
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.pkg-config ];
|
||||||
|
buildInputs = [ pkgs.freetype ];
|
||||||
|
cmakeFlags = rmluiCmakeFlags ++ [ "-DBUILD_SHARED_LIBS=ON" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# ---- WASM Freetype (static, minimal deps) ---------------------------
|
||||||
|
freetypeWasm = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "freetype-wasm";
|
||||||
|
version = pkgs.freetype.version;
|
||||||
|
src = pkgs.freetype.src;
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.emscripten ];
|
||||||
|
dontFixup = true;
|
||||||
|
configurePhase = ''
|
||||||
|
emcmake cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_SHARED_LIBS=OFF \
|
||||||
|
-DFT_DISABLE_ZLIB=TRUE \
|
||||||
|
-DFT_DISABLE_BZIP2=TRUE \
|
||||||
|
-DFT_DISABLE_PNG=TRUE \
|
||||||
|
-DFT_DISABLE_HARFBUZZ=TRUE \
|
||||||
|
-DFT_DISABLE_BROTLI=TRUE \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$out
|
||||||
|
'';
|
||||||
|
buildPhase = "emmake make -C build -j$NIX_BUILD_CORES";
|
||||||
|
installPhase = "emmake make -C build install";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ---- WASM RmlUi (static) ---------------------------------------------
|
||||||
|
rmluiWasm = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "rmlui-wasm";
|
||||||
|
version = "master";
|
||||||
|
src = rmluiSrc;
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.emscripten ];
|
||||||
|
dontFixup = true;
|
||||||
|
configurePhase = ''
|
||||||
|
emcmake cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DBUILD_SHARED_LIBS=OFF \
|
||||||
|
${pkgs.lib.concatStringsSep " " rmluiCmakeFlags} \
|
||||||
|
${pkgs.lib.concatStringsSep " " wasmFindOverrides} \
|
||||||
|
-DCMAKE_PREFIX_PATH="${freetypeWasm}" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$out
|
||||||
|
'';
|
||||||
|
buildPhase = "emmake make -C build -j$NIX_BUILD_CORES";
|
||||||
|
installPhase = "emmake make -C build install";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ---- WASM raylib (PLATFORM=Web) ---------------------------------------
|
||||||
|
raylibWasm = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "raylib-wasm";
|
||||||
|
version = pkgs.raylib.version;
|
||||||
|
src = pkgs.raylib.src;
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.emscripten ];
|
||||||
|
dontFixup = true;
|
||||||
|
configurePhase = ''
|
||||||
|
emcmake cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DPLATFORM=Web \
|
||||||
|
-DBUILD_EXAMPLES=OFF \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$out
|
||||||
|
'';
|
||||||
|
buildPhase = "emmake make -C build -j$NIX_BUILD_CORES";
|
||||||
|
installPhase = "emmake make -C build install";
|
||||||
|
};
|
||||||
|
|
||||||
|
# ---- native toolchain / runtime ---------------------------------------
|
||||||
|
nativeBuildTools = with pkgs; [
|
||||||
|
cmake
|
||||||
|
pkg-config
|
||||||
|
clang-tools
|
||||||
|
];
|
||||||
|
|
||||||
|
nativeRuntimeDeps = with pkgs; [
|
||||||
|
raylib
|
||||||
|
libGL
|
||||||
|
libX11
|
||||||
|
libXcursor
|
||||||
|
libXrandr
|
||||||
|
libXinerama
|
||||||
|
libXi
|
||||||
|
wayland
|
||||||
|
libxkbcommon
|
||||||
|
rmlui
|
||||||
|
freetype
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = nativeBuildTools;
|
||||||
|
buildInputs = nativeRuntimeDeps;
|
||||||
|
shellHook = ''
|
||||||
|
export C_INCLUDE_PATH="${rmlui}/include:${pkgs.raylib}/include"
|
||||||
|
export CPLUS_INCLUDE_PATH="$C_INCLUDE_PATH"
|
||||||
|
export LIBRARY_PATH="${pkgs.lib.makeLibraryPath nativeRuntimeDeps}"
|
||||||
|
export LD_LIBRARY_PATH="$LIBRARY_PATH:$LD_LIBRARY_PATH"
|
||||||
|
echo "native dev shell ready (raylib + rmlui)"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
devShells.wasm = pkgs.mkShell {
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.emscripten pkgs.python3 ];
|
||||||
|
shellHook = ''
|
||||||
|
export RAYLIB_WASM="${raylibWasm}"
|
||||||
|
export RMLUI_WASM="${rmluiWasm}"
|
||||||
|
export FREETYPE_WASM="${freetypeWasm}"
|
||||||
|
echo "wasm dev shell ready — configure with:"
|
||||||
|
echo " emcmake cmake -B build-wasm -DPLATFORM=Web \\"
|
||||||
|
echo " -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=BOTH \\"
|
||||||
|
echo " -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=BOTH \\"
|
||||||
|
echo " -DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH \\"
|
||||||
|
echo " -DCMAKE_PREFIX_PATH=\"\$RAYLIB_WASM;\$RMLUI_WASM;\$FREETYPE_WASM\""
|
||||||
|
echo " emmake make -C build-wasm"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.default = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "gamejam";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./.;
|
||||||
|
nativeBuildInputs = nativeBuildTools ++ [ pkgs.makeWrapper ];
|
||||||
|
buildInputs = nativeRuntimeDeps;
|
||||||
|
cmakeFlags = [ "-DCMAKE_BUILD_TYPE=Release" ];
|
||||||
|
postInstall = ''
|
||||||
|
wrapProgram $out/bin/gamejam \
|
||||||
|
--prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath nativeRuntimeDeps}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
packages.wasm = pkgs.stdenv.mkDerivation {
|
||||||
|
pname = "gamejam-wasm";
|
||||||
|
version = "0.1.0";
|
||||||
|
src = ./.;
|
||||||
|
nativeBuildInputs = [ pkgs.cmake pkgs.emscripten ];
|
||||||
|
dontFixup = true;
|
||||||
|
configurePhase = ''
|
||||||
|
emcmake cmake -S . -B build \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DPLATFORM=Web \
|
||||||
|
${pkgs.lib.concatStringsSep " " wasmFindOverrides} \
|
||||||
|
-DCMAKE_PREFIX_PATH="${raylibWasm};${rmluiWasm};${freetypeWasm}" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=$out
|
||||||
|
'';
|
||||||
|
buildPhase = "emmake make -C build -j$NIX_BUILD_CORES";
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out
|
||||||
|
cp -r build/*.html build/*.js build/*.wasm $out/ 2>/dev/null || true
|
||||||
|
emmake make -C build install || true
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
51
src/Application.cpp
Normal file
51
src/Application.cpp
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#include "Application.h"
|
||||||
|
#include "backend/RaylibInput.h"
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <RmlUi/Core.h>
|
||||||
|
#include <RmlUi/Debugger.h>
|
||||||
|
|
||||||
|
bool Application::Init(int width, int height, const char* title, const char* documentPath) {
|
||||||
|
InitWindow(width, height, title);
|
||||||
|
SetTargetFPS(60);
|
||||||
|
|
||||||
|
Rml::SetSystemInterface(&system_interface);
|
||||||
|
Rml::SetRenderInterface(&render_interface);
|
||||||
|
Rml::Initialise();
|
||||||
|
|
||||||
|
context = Rml::CreateContext("main", Rml::Vector2i(width, height));
|
||||||
|
Rml::Debugger::Initialise(context);
|
||||||
|
|
||||||
|
// TODO: load a real font
|
||||||
|
|
||||||
|
if (Rml::ElementDocument* document = context->LoadDocument(documentPath)) {
|
||||||
|
document->Show();
|
||||||
|
} else {
|
||||||
|
TraceLog(LOG_WARNING, "Failed to load %s", documentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Frame() {
|
||||||
|
if (WindowShouldClose()) {
|
||||||
|
running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ForwardInputToRml(context);
|
||||||
|
context->Update();
|
||||||
|
|
||||||
|
BeginDrawing();
|
||||||
|
ClearBackground(DARKGRAY);
|
||||||
|
|
||||||
|
// --- game world rendering goes here, before the UI ---
|
||||||
|
|
||||||
|
context->Render();
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::Shutdown() {
|
||||||
|
Rml::Shutdown();
|
||||||
|
CloseWindow();
|
||||||
|
}
|
||||||
19
src/Application.h
Normal file
19
src/Application.h
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
#include "backend/RaylibSystemInterface.h"
|
||||||
|
#include "backend/RaylibRenderInterface.h"
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
public:
|
||||||
|
bool Init(int width, int height, const char* title, const char* documentPath);
|
||||||
|
void Frame();
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
bool IsRunning() const { return running; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
RaylibSystemInterface system_interface;
|
||||||
|
RaylibRenderInterface render_interface;
|
||||||
|
Rml::Context* context = nullptr;
|
||||||
|
bool running = true;
|
||||||
|
};
|
||||||
25
src/backend/RaylibInput.cpp
Normal file
25
src/backend/RaylibInput.cpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#include "RaylibInput.h"
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
int GetRmlKeyModifiers() {
|
||||||
|
int mods = 0;
|
||||||
|
if (IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT)) mods |= Rml::Input::KM_SHIFT;
|
||||||
|
if (IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL)) mods |= Rml::Input::KM_CTRL;
|
||||||
|
if (IsKeyDown(KEY_LEFT_ALT) || IsKeyDown(KEY_RIGHT_ALT)) mods |= Rml::Input::KM_ALT;
|
||||||
|
return mods;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForwardInputToRml(Rml::Context* context) {
|
||||||
|
Vector2 mouse = GetMousePosition();
|
||||||
|
context->ProcessMouseMove((int)mouse.x, (int)mouse.y, GetRmlKeyModifiers());
|
||||||
|
|
||||||
|
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) context->ProcessMouseButtonDown(0, GetRmlKeyModifiers());
|
||||||
|
if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) context->ProcessMouseButtonUp(0, GetRmlKeyModifiers());
|
||||||
|
if (IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) context->ProcessMouseButtonDown(1, GetRmlKeyModifiers());
|
||||||
|
if (IsMouseButtonReleased(MOUSE_BUTTON_RIGHT)) context->ProcessMouseButtonUp(1, GetRmlKeyModifiers());
|
||||||
|
|
||||||
|
float wheel = GetMouseWheelMove();
|
||||||
|
if (wheel != 0.0f) context->ProcessMouseWheel(-wheel, GetRmlKeyModifiers());
|
||||||
|
}
|
||||||
4
src/backend/RaylibInput.h
Normal file
4
src/backend/RaylibInput.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <RmlUi/Core/Context.h>
|
||||||
|
|
||||||
|
void ForwardInputToRml(Rml::Context* context);
|
||||||
109
src/backend/RaylibRenderInterface.cpp
Normal file
109
src/backend/RaylibRenderInterface.cpp
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
#include "RaylibRenderInterface.h"
|
||||||
|
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <rlgl.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct GeometryData {
|
||||||
|
std::vector<Rml::Vertex> vertices;
|
||||||
|
std::vector<int> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::CompiledGeometryHandle RaylibRenderInterface::CompileGeometry(
|
||||||
|
Rml::Span<const Rml::Vertex> vertices, Rml::Span<const int> indices) {
|
||||||
|
auto* geo = new GeometryData();
|
||||||
|
geo->vertices.assign(vertices.begin(), vertices.end());
|
||||||
|
geo->indices.assign(indices.begin(), indices.end());
|
||||||
|
return reinterpret_cast<Rml::CompiledGeometryHandle>(geo);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::RenderGeometry(Rml::CompiledGeometryHandle handle,
|
||||||
|
Rml::Vector2f translation,
|
||||||
|
Rml::TextureHandle texture) {
|
||||||
|
auto* geo = reinterpret_cast<GeometryData*>(handle);
|
||||||
|
|
||||||
|
if (texture) {
|
||||||
|
Texture2D* tex = reinterpret_cast<Texture2D*>(texture);
|
||||||
|
rlSetTexture(tex->id);
|
||||||
|
} else {
|
||||||
|
rlSetTexture(rlGetTextureIdDefault());
|
||||||
|
}
|
||||||
|
|
||||||
|
rlPushMatrix();
|
||||||
|
rlTranslatef(translation.x, translation.y, 0.0f);
|
||||||
|
|
||||||
|
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]];
|
||||||
|
rlColor4ub(v.colour.red, v.colour.green, v.colour.blue, v.colour.alpha);
|
||||||
|
rlTexCoord2f(v.tex_coord.x, v.tex_coord.y);
|
||||||
|
rlVertex2f(v.position.x, v.position.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rlEnd();
|
||||||
|
|
||||||
|
rlPopMatrix();
|
||||||
|
rlSetTexture(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::ReleaseGeometry(Rml::CompiledGeometryHandle handle) {
|
||||||
|
delete reinterpret_cast<GeometryData*>(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle RaylibRenderInterface::LoadTexture(Rml::Vector2i& texture_dimensions,
|
||||||
|
const Rml::String& source) {
|
||||||
|
Texture2D tex = ::LoadTexture(source.c_str());
|
||||||
|
if (tex.id == 0) {
|
||||||
|
TraceLog(LOG_WARNING, "[RmlUi] failed to load texture: %s", source.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
texture_dimensions = Rml::Vector2i(tex.width, tex.height);
|
||||||
|
return reinterpret_cast<Rml::TextureHandle>(new Texture2D(tex));
|
||||||
|
}
|
||||||
|
|
||||||
|
Rml::TextureHandle RaylibRenderInterface::GenerateTexture(Rml::Span<const Rml::byte> source_data,
|
||||||
|
Rml::Vector2i source_dimensions) {
|
||||||
|
Image img{};
|
||||||
|
img.width = source_dimensions.x;
|
||||||
|
img.height = source_dimensions.y;
|
||||||
|
img.mipmaps = 1;
|
||||||
|
img.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8;
|
||||||
|
|
||||||
|
size_t byte_count = static_cast<size_t>(img.width) * img.height * 4;
|
||||||
|
img.data = RL_MALLOC(byte_count);
|
||||||
|
std::memcpy(img.data, source_data.data(), byte_count);
|
||||||
|
|
||||||
|
Texture2D tex = LoadTextureFromImage(img);
|
||||||
|
UnloadImage(img); // frees img.data
|
||||||
|
|
||||||
|
return reinterpret_cast<Rml::TextureHandle>(new Texture2D(tex));
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::ReleaseTexture(Rml::TextureHandle handle) {
|
||||||
|
Texture2D* tex = reinterpret_cast<Texture2D*>(handle);
|
||||||
|
UnloadTexture(*tex);
|
||||||
|
delete tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::EnableScissorRegion(bool enable) {
|
||||||
|
scissor_enabled = enable;
|
||||||
|
if (enable) ApplyScissor();
|
||||||
|
else EndScissorMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::SetScissorRegion(Rml::Rectanglei region) {
|
||||||
|
scissor_region = region;
|
||||||
|
if (scissor_enabled) ApplyScissor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RaylibRenderInterface::ApplyScissor() {
|
||||||
|
BeginScissorMode(scissor_region.Left(), scissor_region.Top(),
|
||||||
|
scissor_region.Width(), scissor_region.Height());
|
||||||
|
}
|
||||||
37
src/backend/RaylibRenderInterface.h
Normal file
37
src/backend/RaylibRenderInterface.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <RmlUi/Core/RenderInterface.h>
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: RmlUi's RenderInterface signature has shifted across versions
|
||||||
|
// (raw pointer+count vs. Rml::Span<>). If this fails to compile against
|
||||||
|
// a different RmlUi commit, check RmlUi/Core/RenderInterface.h and adjust
|
||||||
|
// CompileGeometry/GenerateTexture's parameter types, internal logic
|
||||||
|
// stays the same.
|
||||||
|
|
||||||
|
class RaylibRenderInterface : public Rml::RenderInterface {
|
||||||
|
public:
|
||||||
|
Rml::CompiledGeometryHandle CompileGeometry(Rml::Span<const Rml::Vertex> vertices,
|
||||||
|
Rml::Span<const int> indices) override;
|
||||||
|
|
||||||
|
void RenderGeometry(Rml::CompiledGeometryHandle handle, Rml::Vector2f translation,
|
||||||
|
Rml::TextureHandle texture) override;
|
||||||
|
|
||||||
|
void ReleaseGeometry(Rml::CompiledGeometryHandle handle) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle LoadTexture(Rml::Vector2i& texture_dimensions,
|
||||||
|
const Rml::String& source) override;
|
||||||
|
|
||||||
|
Rml::TextureHandle GenerateTexture(Rml::Span<const Rml::byte> source_data,
|
||||||
|
Rml::Vector2i source_dimensions) override;
|
||||||
|
|
||||||
|
void ReleaseTexture(Rml::TextureHandle handle) override;
|
||||||
|
|
||||||
|
void EnableScissorRegion(bool enable) override;
|
||||||
|
void SetScissorRegion(Rml::Rectanglei region) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ApplyScissor();
|
||||||
|
|
||||||
|
bool scissor_enabled = false;
|
||||||
|
Rml::Rectanglei scissor_region;
|
||||||
|
};
|
||||||
14
src/backend/RaylibSystemInterface.cpp
Normal file
14
src/backend/RaylibSystemInterface.cpp
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#include "RaylibSystemInterface.h"
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
double RaylibSystemInterface::GetElapsedTime() {
|
||||||
|
return GetTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RaylibSystemInterface::LogMessage(Rml::Log::Type type, const Rml::String& message) {
|
||||||
|
TraceLogLevel level = LOG_INFO;
|
||||||
|
if (type == Rml::Log::LT_WARNING) level = LOG_WARNING;
|
||||||
|
if (type == Rml::Log::LT_ERROR || type == Rml::Log::LT_ASSERT) level = LOG_ERROR;
|
||||||
|
TraceLog(level, "[RmlUi] %s", message.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
8
src/backend/RaylibSystemInterface.h
Normal file
8
src/backend/RaylibSystemInterface.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <RmlUi/Core/SystemInterface.h>
|
||||||
|
|
||||||
|
class RaylibSystemInterface : public Rml::SystemInterface {
|
||||||
|
public:
|
||||||
|
double GetElapsedTime() override;
|
||||||
|
bool LogMessage(Rml::Log::Type type, const Rml::String& message) override;
|
||||||
|
};
|
||||||
33
src/main.cpp
Normal file
33
src/main.cpp
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#include <emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Application* g_app = nullptr;
|
||||||
|
|
||||||
|
void MainLoopStep() {
|
||||||
|
g_app->Frame();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
static Application app;
|
||||||
|
g_app = &app;
|
||||||
|
|
||||||
|
app.Init(1280, 720, "gamejam", "assets/main.rml");
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop(MainLoopStep, 0, 1);
|
||||||
|
#else
|
||||||
|
while (app.IsRunning()) {
|
||||||
|
app.Frame();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
app.Shutdown();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user