commit 761fa6ca216d8c4766a43047c2ecc1054540d637 Author: chris bell Date: Sun Aug 30 17:16:43 2026 -0500 Adding current renderer from gamejam project diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f88dc4a --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.envrc +.direnv/ +.vscode/ + +result + +build/ +build-wasm/ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..91813ea --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +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() + +find_package(raylib REQUIRED) +find_package(RmlUi REQUIRED) + +add_executable(gamejam + src/main.cpp + src/Game.cpp + src/Application.cpp + src/Creature.cpp + src/Round.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) + 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} $/assets + COMMENT "Copying assets to build output" + ) +endif() + +install(TARGETS gamejam RUNTIME DESTINATION bin) + +if(NOT EMSCRIPTEN) + install(DIRECTORY ${ASSET_DIR} DESTINATION bin) +endif() diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..ba77209 --- /dev/null +++ b/flake.nix @@ -0,0 +1,190 @@ +{ + description = "Raylib + RmlUI (with android build support) dev shell"; + + 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" + ]; + + 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 "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 = "rrmlui"; + 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 = "rrmlui-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 + ''; + }; + } + ); +} diff --git a/src/backend/RaylibInput.cpp b/src/backend/RaylibInput.cpp new file mode 100644 index 0000000..438e386 --- /dev/null +++ b/src/backend/RaylibInput.cpp @@ -0,0 +1,33 @@ +#include "RaylibInput.h" +#include + +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; +} +} // namespace + +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()); +} \ No newline at end of file diff --git a/src/backend/RaylibInput.h b/src/backend/RaylibInput.h new file mode 100644 index 0000000..b025474 --- /dev/null +++ b/src/backend/RaylibInput.h @@ -0,0 +1,4 @@ +#pragma once +#include + +void ForwardInputToRml(Rml::Context *context); \ No newline at end of file diff --git a/src/backend/RaylibRenderInterface.cpp b/src/backend/RaylibRenderInterface.cpp new file mode 100644 index 0000000..affb2bb --- /dev/null +++ b/src/backend/RaylibRenderInterface.cpp @@ -0,0 +1,116 @@ +#include "RaylibRenderInterface.h" + +#include +#include + +#include +#include + +namespace { + +struct GeometryData { + std::vector vertices; + std::vector indices; +}; + +} // namespace + +Rml::CompiledGeometryHandle +RaylibRenderInterface::CompileGeometry(Rml::Span vertices, + Rml::Span indices) { + auto *geo = new GeometryData(); + geo->vertices.assign(vertices.begin(), vertices.end()); + geo->indices.assign(indices.begin(), indices.end()); + return reinterpret_cast(geo); +} + +void RaylibRenderInterface::RenderGeometry(Rml::CompiledGeometryHandle handle, + Rml::Vector2f translation, + Rml::TextureHandle texture) { + auto *geo = reinterpret_cast(handle); + + if (texture) { + Texture2D *tex = reinterpret_cast(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(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(new Texture2D(tex)); +} + +Rml::TextureHandle +RaylibRenderInterface::GenerateTexture(Rml::Span 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(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(new Texture2D(tex)); +} + +void RaylibRenderInterface::ReleaseTexture(Rml::TextureHandle handle) { + Texture2D *tex = reinterpret_cast(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()); +} \ No newline at end of file diff --git a/src/backend/RaylibRenderInterface.h b/src/backend/RaylibRenderInterface.h new file mode 100644 index 0000000..7253348 --- /dev/null +++ b/src/backend/RaylibRenderInterface.h @@ -0,0 +1,38 @@ +#pragma once +#include + +// 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 vertices, + Rml::Span 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 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; +}; \ No newline at end of file diff --git a/src/backend/RaylibSystemInterface.cpp b/src/backend/RaylibSystemInterface.cpp new file mode 100644 index 0000000..9adb6b3 --- /dev/null +++ b/src/backend/RaylibSystemInterface.cpp @@ -0,0 +1,15 @@ +#include "RaylibSystemInterface.h" +#include + +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; +} \ No newline at end of file diff --git a/src/backend/RaylibSystemInterface.h b/src/backend/RaylibSystemInterface.h new file mode 100644 index 0000000..1d2c247 --- /dev/null +++ b/src/backend/RaylibSystemInterface.h @@ -0,0 +1,8 @@ +#pragma once +#include + +class RaylibSystemInterface : public Rml::SystemInterface { +public: + double GetElapsedTime() override; + bool LogMessage(Rml::Log::Type type, const Rml::String &message) override; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e69de29