diff --git a/.gitmodules b/.gitmodules index ffacd92..cd4f90d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,4 +10,6 @@ [submodule "external/imgui"] path = external/imgui url = https://github.com/ocornut/imgui.git - branch = 1.92.4-docking +[submodule "external/rlImGui"] + path = external/rlImGui + url = https://github.com/raylib-extras/rlImGui.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c4ba6d..b6709a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,28 @@ add_subdirectory(external/angelscript/sdk/angelscript/projects/cmake) # ------------------------- # Ensure the submodule exists at external/imgui (added with git submodule) add_subdirectory(cmake/imgui) + +# ------------------------- +# rlImGui (optional - Raylib ImGui integration) +# ------------------------- +# If you add rlImGui as a submodule under external/rlImGui, CMake will pick it up +option(USE_RLIMGUI "Enable rlImGui integration if found in external/rlImGui" ON) +set(RLIMGUI_ROOT "${CMAKE_SOURCE_DIR}/external/rlImGui") +if(USE_RLIMGUI) + if(EXISTS "${RLIMGUI_ROOT}/CMakeLists.txt") + message(STATUS "rlImGui CMakeLists found at ${RLIMGUI_ROOT} - adding to build") + add_subdirectory(${RLIMGUI_ROOT} EXCLUDE_FROM_ALL) + set(HAVE_RLIMGUI TRUE) + elseif(EXISTS "${RLIMGUI_ROOT}") + message(STATUS "rlImGui sources found at ${RLIMGUI_ROOT} - using project wrapper cmake/rlImGui") + add_subdirectory(cmake/rlImGui) + set(HAVE_RLIMGUI TRUE) + else() + set(HAVE_RLIMGUI FALSE) + endif() +else() + set(HAVE_RLIMGUI FALSE) +endif() # ------------------------- # Tests # ------------------------- @@ -68,7 +90,7 @@ target_include_directories(simian PUBLIC external/imgui ) -target_link_libraries(simian +target_link_libraries(simian PRIVATE raylib angelscript scriptstdstring @@ -76,11 +98,19 @@ target_link_libraries(simian imgui ) +if(HAVE_RLIMGUI) + target_include_directories(simian PUBLIC ${RLIMGUI_ROOT}/include) + target_link_libraries(simian PRIVATE rlImGui) + message(STATUS "Linking rlImGui into simian") +else() + message(STATUS "rlImGui not found - building without rlImGui integration") +endif() + # ------------------------- # 5️⃣ Platform-specific linking # ------------------------- if(WIN32) - target_link_libraries(simian winmm gdi32) + target_link_libraries(simian PRIVATE winmm gdi32) elseif(UNIX) # Linux / macOS: Raylib handles system libs automatically endif() diff --git a/Justfile b/Justfile new file mode 100644 index 0000000..d29398b --- /dev/null +++ b/Justfile @@ -0,0 +1,66 @@ +# Justfile for Simian project +# Usage: just + +# Default configuration +set shell := ["powershell", "-Command"] + +# Variables +BUILD_DIR := "build" +CMAKE_CONFIG := "Release" +CMAKE_GENERATOR := "Visual Studio 17 2022" +CMAKE_ARCH := "x64" + +# Initialize and update submodules +submodules: + @echo "Updating submodules..." + git submodule update --init --recursive + +# Configure the project (out-of-source) +configure: + @echo "Configuring CMake (generator: {{CMAKE_GENERATOR}}, arch: {{CMAKE_ARCH}})" + cmake -G "{{CMAKE_GENERATOR}}" -A {{CMAKE_ARCH}} -S . -B {{BUILD_DIR}} + +# Configure for Debug +configure-debug: + @echo "Configuring Debug" + cmake -G "{{CMAKE_GENERATOR}}" -A {{CMAKE_ARCH}} -S . -B {{BUILD_DIR}} -DCMAKE_BUILD_TYPE=Debug + +# Build (Release by default) +build: + @echo "Building (config: {{CMAKE_CONFIG}})" + cmake --build {{BUILD_DIR}} --config {{CMAKE_CONFIG}} + +# Build Debug +build-debug: + @echo "Building Debug" + cmake --build {{BUILD_DIR}} --config Debug + +# Run the built executable +run: + @echo "Running simian..." + {{BUILD_DIR}}\{{CMAKE_CONFIG}}\simian.exe + +# Clean build folder +clean: + @echo "Removing {{BUILD_DIR}} folder" + Remove-Item -Recurse -Force {{BUILD_DIR}} -ErrorAction SilentlyContinue + +# Reconfigure, build and run (convenience) +rebuild-run: submodules configure build run + +# Lint / formatting (placeholder) +format: + @echo "No formatter configured. Add commands here." + +# Tests (placeholder - uses CTest if configured) +test: + @echo "Running tests (if configured)" + cmake --build {{BUILD_DIR}} --config {{CMAKE_CONFIG}} --target RUN_TESTS + +# Provide a help recipe +help: + @echo "Available recipes: submodules, configure, configure-debug, build, build-debug, run, clean, rebuild-run, format, test" + +# Notes for non-Windows shells +# If you're running on Git Bash or WSL, set shell and generator accordingly, e.g.: +# just -s --shell "bash -lc" configure diff --git a/README.md b/README.md index e7d6fca..a36580a 100644 --- a/README.md +++ b/README.md @@ -1,200 +1,130 @@ -# Simian +## Simian -**Simian** is a Raylib + AngelScript test project on Windows and Linux. -It demonstrates how to integrate **Raylib** for graphics and **AngelScript** for scripting, including the `scriptstdstring` add-on. +Simian is a small Raylib + AngelScript test project, refactored to be easy to extend and to show a safe hot-reload workflow for AngelScript. -## Refactored Architecture +This README was updated to reflect the current layout, build paths, and the small CMake wrapper approach used to optionally build ImGui / rlImGui when those folders are present. -The project has been refactored from a single `main.cpp` file into a more maintainable modular structure: +## What changed -### Core Components -- **Application** (`Application.h/cpp`) - Main application lifecycle and game loop -- **ScriptEngine** (`ScriptEngine.h/cpp`) - AngelScript engine management and script compilation -- **ScriptBindings** (`ScriptBindings.h/cpp`) - C++ to AngelScript function bindings -- **HotReload** (`HotReload.h/cpp`) - File monitoring for automatic script reloading -- **main.cpp** - Minimal entry point +- The original single-file demo was split into modules: Application, ScriptEngine, ScriptBindings and HotReload. +- Hot-reloads are performed safely: scripts compile into a temporary module first and only replace the running module on successful compilation. Compilation errors will no longer crash the running app. +- CMake wrappers live in `cmake/` to build third-party projects that don't ship a CMakeLists.txt (example: ImGui, rlImGui). This keeps submodules untouched. +- A `Justfile` was added with convenient recipes for configure, build, run and cleaning. -### Directory Structure -``` -Simian/ -├─ include/ # Header files -│ ├─ Application.h -│ ├─ ScriptEngine.h -│ ├─ ScriptBindings.h -│ └─ HotReload.h -├─ src/ # Source files -│ ├─ Application.cpp -│ ├─ ScriptEngine.cpp -│ ├─ ScriptBindings.cpp -│ └─ HotReload.cpp -├─ external/ # Dependencies -├─ scripts/ # AngelScript files -├─ main.cpp # Entry point -└─ CMakeLists.txt # Build configuration -``` +## Quick start (Windows) ---- +Open a developer prompt for Visual Studio or use PowerShell / cmd configured for MSVC. -## Requirements +Clone with submodules: -### Windows -- Windows 10/11 (tested) -- [Visual Studio 2022](https://visualstudio.microsoft.com/) with **Desktop development with C++** workload -- [CMake 3.25+](https://cmake.org/download/) -- Git -- Optional: VSCode for editing - -### Linux -- Ubuntu 20.04+ or equivalent Linux distribution -- GCC 9+ or Clang 10+ -- [CMake 3.25+](https://cmake.org/download/) -- Git -- Development libraries: `sudo apt install build-essential cmake git` - ---- - -## Getting Started - -### 1. Clone the repository with submodules - -```bash -git clone --recurse-submodules +```powershell +git clone --recurse-submodules cd Simian ``` -If you forgot `--recurse-submodules`, run: +Using the included `Justfile` (optional): -```bash -git submodule update --init --recursive +```powershell +# from project root +just configure # runs cmake -S . -B build -G "Visual Studio 17 2022" -A x64 +just build # builds Debug by default (uses cmake --build) +just run # runs the built executable (Debug) ``` -This will pull **Raylib** and **AngelScript** into `external/`. +Or use raw CMake commands: ---- - -### 2. Build with CMake - -#### Windows (Visual Studio) - -```bash -# Create build folder -mkdir build -cd build - -# Generate Visual Studio solution (64-bit) +```powershell +mkdir build; cd build cmake -G "Visual Studio 17 2022" -A x64 .. - -# Build Release version cmake --build . --config Release -``` - -After building, the executable will be at: - -``` +# run: build\Release\simian.exe ``` -#### Linux (Unix Makefiles) +If you are using cmd.exe, the same commands apply (adjust quotes for generator if needed). + +## Linux / Unix ```bash -# Create build folder -mkdir build -cd build - -# Generate Unix Makefiles +git clone --recurse-submodules +cd Simian +mkdir build && cd build cmake -G "Unix Makefiles" .. - -# Build cmake --build . +./simian ``` -After building, the executable will be at: - -``` -build/simian -``` - ---- - -### 3. Run the project - -#### Windows -```bash -build\Release\simian.exe -``` - -#### Linux -```bash -./build/simian -``` - -You should see a **Raylib window** open and the console will output: - -``` -[Script] Hello from AngelScript! -``` - ---- - -## Project Structure +## Project layout (important files) ``` Simian/ -├─ external/ -│ ├─ raylib/ # Git submodule -│ └─ angelscript/ # Git submodule (includes scriptstdstring add-on) -├─ scripts/ # Optional: .as scripts to be loaded at runtime -├─ main.cpp # Entry point (Raylib + AngelScript) -├─ CMakeLists.txt # Build configuration -└─ README.md +├─ CMakeLists.txt # top level CMake +├─ Justfile # convenience tasks (configure/build/run/clean) +├─ include/ # public headers (Application, ScriptEngine, ScriptBindings, HotReload) +├─ src/ # implementation +├─ scripts/ # AngelScript source files loaded at runtime +├─ external/ # git submodules (raylib, angelscript, optional imgui/rlImGui) +└─ cmake/ # local CMake wrappers (imgui, rlImGui) ``` ---- +## Hot-reload notes + +- The app watches `scripts/` for changes. When a script is updated it is compiled into a temporary AngelScript module. +- If compilation succeeds, the temp module replaces the live `main` module and new functions are used. If compilation fails, the running module is left intact and a single-line error is shown on-screen. +- This avoids crashes that happen when a script with compilation errors would otherwise replace/break function pointers while the engine is executing. + +## ImGui / rlImGui (optional) + +The repository prefers to keep upstream code as submodules. Some upstream projects (like certain ImGui tags or rlImGui) don't provide a CMakeLists.txt. To support those without editing submodules, the project includes small wrappers in `cmake/`: + +- `cmake/imgui/` builds ImGui core (and optionally backends) when `external/imgui` is present. +- `cmake/rlImGui/` builds the rlImGui integration and links it to the `imgui` target if available. + +If you prefer to use the upstream CMake (when present), the top-level `CMakeLists.txt` will prefer `external/rlImGui`'s CMake if it detects one; otherwise it falls back to the wrapper. + +To add ImGui/rlImGui as submodules: + +```powershell +# from repo root +git submodule add https://github.com/ocornut/imgui.git external/imgui +git submodule add https://github.com/NeoSpark314/rlImGui.git external/rlImGui +git submodule update --init --recursive +``` + +Then re-run CMake from a clean build directory. + +Troubleshooting: if Git warns about "embedded git repository" when adding files, convert the folder to a submodule (remove cached tracked files, then add as submodule) — this README intentionally avoids modifying submodule contents. + +## Tests / Verification + +Quick smoke test after building: + +```powershell +# run the Debug build +build\Debug\simian.exe +``` + +You should see the Raylib window. The running console prints from script when the default script executes (e.g. "[Script] Hello from AngelScript!"). + +If a script has a compilation error, the app will continue running and a brief error message is presented on the top-left of the window. + +## Updating submodules + +Keep submodules pinned for reproducible builds. To update them safely: + +```powershell +cd external/raylib && git fetch && git checkout +cd ../angelscript && git fetch && git checkout +cd ../.. && git add external/raylib external/angelscript && git commit -m "Update submodules" +``` ## Notes -* **AngelScript `string` support** is enabled via `scriptstdstring` add-on. -* **Hot-reloading scripts** can be implemented by loading `.as` files from the `scripts/` folder. -* Update submodules with: - -```bash -cd external/raylib -git pull origin master -cd ../angelscript -git pull origin master -cd ../.. -git add external/raylib external/angelscript -git commit -m "Update submodules" -``` - ---- - -## CMake Targets - -* `simian` — main executable -* `raylib` — static library submodule -* `angelscript` — static library submodule -* `scriptstdstring` — static library add-on for AngelScript - ---- - -## Tips - -#### Windows -* Always use **VS2022 Developer Command Prompt** or VSCode terminal configured for MSVC. - -#### Linux -* Make sure you have the required development packages installed. -* On some distributions you may need additional X11 development libraries. - -#### General -* Pin submodules to specific commits for reproducible builds. -* To clean build: delete the `build/` folder and regenerate with CMake. - ---- +- The project was developed and tested on Windows with Visual Studio; Linux builds are supported but may need X11 / audio dev packages installed depending on your environment. +- The codebase avoids changing tracked submodule contents; use the `cmake/` wrappers when a submodule doesn't include a CMake build. ## License -* Raylib: [Zlib License](https://github.com/raysan5/raylib#license) -* AngelScript: [MIT License](https://github.com/angelcode/angelscript/blob/master/license.txt) -* Simian: Not open source (Yet) +* Raylib: Zlib License (see https://github.com/raysan5/raylib#license) +* AngelScript: MIT License (see https://github.com/angelcode/angelscript/blob/master/license.txt) +* Simian: Not open source (yet) diff --git a/cmake/imgui/CMakeLists.txt b/cmake/imgui/CMakeLists.txt index e4413bc..85ea7c0 100644 --- a/cmake/imgui/CMakeLists.txt +++ b/cmake/imgui/CMakeLists.txt @@ -1,27 +1,63 @@ cmake_minimum_required(VERSION 3.10) project(imgui_wrapper NONE) -# Root of the imgui submodule +# Root of the imgui submodule (expected to live at external/imgui) set(IMGUI_ROOT "${CMAKE_SOURCE_DIR}/external/imgui") if(NOT EXISTS "${IMGUI_ROOT}/imgui.h") message(FATAL_ERROR "ImGui not found in ${IMGUI_ROOT}. Run: git submodule update --init --recursive") endif() -# Gather core sources and optional backend sources if present -file(GLOB IMGUI_CORE_SRCS "${IMGUI_ROOT}/*.cpp") -file(GLOB IMGUI_BACKEND_SRCS "${IMGUI_ROOT}/backends/*.cpp") +# Options: build demo and/or backends. By default we only build the core library which +# avoids pulling in platform deps (SDL/Android/etc) from the backends and examples. +option(IMGUI_BUILD_DEMO "Include imgui_demo.cpp in the build" OFF) +option(IMGUI_BUILD_BACKENDS "Include selected backend implementations from backends/" OFF) -# Exclude example / main files if any sneak in -list(FILTER IMGUI_CORE_SRCS EXCLUDE REGEX ".*example.*|.*main.*") +# Core sources (explicit list - avoids accidentally including examples) +set(IMGUI_CORE_SRC + "${IMGUI_ROOT}/imgui.cpp" + "${IMGUI_ROOT}/imgui_draw.cpp" + "${IMGUI_ROOT}/imgui_tables.cpp" + "${IMGUI_ROOT}/imgui_widgets.cpp" +) -set(IMGUI_SOURCES ${IMGUI_CORE_SRCS} ${IMGUI_BACKEND_SRCS}) +if(IMGUI_BUILD_DEMO) + list(APPEND IMGUI_CORE_SRC "${IMGUI_ROOT}/imgui_demo.cpp") +endif() -add_library(imgui STATIC ${IMGUI_SOURCES}) +add_library(imgui STATIC ${IMGUI_CORE_SRC}) target_include_directories(imgui PUBLIC ${IMGUI_ROOT} ) -# Optional: keep PIC for static linking on some platforms +# Optionally include a small, safe set of backends (desktop common ones) when requested. +if(IMGUI_BUILD_BACKENDS) + # Gather backend sources and whitelist a few common desktop backends + file(GLOB IMGUI_BACKEND_SRCS "${IMGUI_ROOT}/backends/*.cpp") + + set(IMGUI_BACKEND_WHITELIST + "imgui_impl_glfw.cpp" + "imgui_impl_opengl3.cpp" + "imgui_impl_win32.cpp" + "imgui_impl_sdl2.cpp" + ) + + set(IMGUI_SELECTED_BACKENDS) + foreach(_f IN LISTS IMGUI_BACKEND_SRCS) + get_filename_component(_name ${_f} NAME) + foreach(_allowed IN LISTS IMGUI_BACKEND_WHITELIST) + if(_name STREQUAL _allowed) + list(APPEND IMGUI_SELECTED_BACKENDS ${_f}) + endif() + endforeach() + endforeach() + + if(IMGUI_SELECTED_BACKENDS) + target_sources(imgui PRIVATE ${IMGUI_SELECTED_BACKENDS}) + target_include_directories(imgui PUBLIC "${IMGUI_ROOT}/backends") + endif() +endif() + +# Build position independent code to make static lib usable in shared contexts set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON) \ No newline at end of file diff --git a/cmake/rlImGui/CMakeLists.txt b/cmake/rlImGui/CMakeLists.txt new file mode 100644 index 0000000..efcea01 --- /dev/null +++ b/cmake/rlImGui/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 3.10) +project(rlImGui_wrapper NONE) + +# Path to the rlImGui sources (submodule should be under external/rlImGui) +set(RLIMGUI_ROOT "${CMAKE_SOURCE_DIR}/external/rlImGui") + +if(NOT EXISTS "${RLIMGUI_ROOT}/README.md") + message(FATAL_ERROR "rlImGui not found in ${RLIMGUI_ROOT}. Add it as a submodule: git submodule add external/rlImGui") +endif() + +# Collect sources - rlImGui has sources under src/ and maybe example/backends + +# Look for sources either under src/ or at the project root +file(GLOB RLIMGUI_ROOT_SRCS "${RLIMGUI_ROOT}/*.c" "${RLIMGUI_ROOT}/*.cpp") +file(GLOB RLIMGUI_SRC_DIR_SRCS "${RLIMGUI_ROOT}/src/*.c" "${RLIMGUI_ROOT}/src/*.cpp") + +set(RLIMGUI_SOURCES ${RLIMGUI_ROOT_SRCS} ${RLIMGUI_SRC_DIR_SRCS}) + +# Exclude examples/tests if present +list(FILTER RLIMGUI_SOURCES EXCLUDE REGEX ".*example.*|.*test.*") + +if(RLIMGUI_SOURCES) + add_library(rlImGui STATIC ${RLIMGUI_SOURCES}) + + # Add includes: rlImGui root and src if present + target_include_directories(rlImGui PUBLIC + ${RLIMGUI_ROOT} + ${RLIMGUI_ROOT}/src + ) + + # Ensure ImGui's headers are available (imgui submodule expected at external/imgui) + set(IMGUI_ROOT "${CMAKE_SOURCE_DIR}/external/imgui") + if(EXISTS "${IMGUI_ROOT}/imgui.h") + target_include_directories(rlImGui PUBLIC ${IMGUI_ROOT}) + endif() + + # If the imgui target exists (from cmake/imgui wrapper), link it so we reuse the same lib + if(TARGET imgui) + target_link_libraries(rlImGui PRIVATE imgui) + endif() +else() + message(FATAL_ERROR "No rlImGui sources found under ${RLIMGUI_ROOT}. Expected rlImGui.cpp or src/*.cpp") +endif() + +# Provide a property so consumers can check availability +set_target_properties(rlImGui PROPERTIES EXPORT_NAME rlImGui) + +# Try to link to raylib if available in the parent project +if(TARGET raylib) + target_link_libraries(rlImGui PRIVATE raylib) +endif() diff --git a/external/rlImGui b/external/rlImGui new file mode 160000 index 0000000..4d8a618 --- /dev/null +++ b/external/rlImGui @@ -0,0 +1 @@ +Subproject commit 4d8a61842903978bc42adf3347cd34f4e6524efc