diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbc131c..cbf0e04 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,8 +1,21 @@ -name: CI +name: CI Extension on: + workflow_dispatch: push: + paths: + - 'ext/rubyraylib/**' + - 'third_party/**' + - '.github/workflows/ci.yml' + - '!ext/rubyraylib/main.cpp' + - '!src/main.hpp' pull_request: + paths: + - 'ext/rubyraylib/**' + - 'third_party/**' + - '.github/workflows/ci.yml' + - '!ext/rubyraylib/main.cpp' + - '!ext/rubyraylib/main.hpp' jobs: build: @@ -27,8 +40,7 @@ jobs: with: submodules: 'recursive' - - name: Set up Ruby - uses: ruby/setup-ruby@v1 + - uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} bundler-cache: true diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml new file mode 100644 index 0000000..0826524 --- /dev/null +++ b/.github/workflows/linux.yml @@ -0,0 +1,64 @@ +name: Linux Binary + +on: + workflow_dispatch: + push: + paths: + - 'ext/rubyraylib/**' + - 'CMakeLists.txt' + - 'third_party/**' + - '.github/workflows/linux.yml' + - '!ext/rubyraylib/rubyraylib.cpp' + - '!ext/rubyraylib/rubyraylib.hpp' + pull_request: + paths: + - 'ext/rubyraylib/**' + - 'CMakeLists.txt' + - 'third_party/**' + - '.github/workflows/linux.yml' + - '!ext/rubyraylib/rubyraylib.cpp' + - '!ext/rubyraylib/rubyraylib.hpp' + +jobs: + build-linux: + name: linux-x86_64 + runs-on: ubuntu-latest + env: + OS: linux + ARCH: x86_64 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3 + + - name: Update package database + run: sudo apt update -qq + + - name: Install required packages + run: | + sudo apt-get install gcc-multilib cmake ninja-build + sudo apt-get install -y --no-install-recommends libglfw3 libglfw3-dev libx11-dev libxcursor-dev libxrandr-dev libxinerama-dev libxi-dev libxext-dev libxfixes-dev libwayland-dev libxkbcommon-dev + + - name: Configure CMake + run: cmake -B build -G Ninja -DCMAKE_BUILD_TYPE:STRING=Release + + - name: Build + run: cmake --build build --config Release --target all + + - name: Strip Shared Libraries + run: strip --strip-unneeded ${{ github.workspace }}/build/libruby.so + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: raylib-cruby-${{ env.ARCH }} + path: | + ${{ github.workspace }}/build/raylib-cruby-${{ env.ARCH }} + ${{ github.workspace }}/build/*.so + retention-days: 90 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 0000000..ab73007 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,54 @@ +name: Windows Binary + +on: + workflow_dispatch: + push: + paths: + - 'ext/rubyraylib/**' + - 'CMakeLists.txt' + - 'third_party/**' + - '.github/workflows/windows.yml' + - '!ext/rubyraylib/rubyraylib.cpp' + - '!ext/rubyraylib/rubyraylib.hpp' + pull_request: + paths: + - 'ext/rubyraylib/**' + - 'CMakeLists.txt' + - 'third_party/**' + - '.github/workflows/windows.yml' + - '!ext/rubyraylib/rubyraylib.cpp' + - '!ext/rubyraylib/rubyraylib.hpp' + +jobs: + build-windows: + name: windows-x86_64 + runs-on: windows-latest + env: + OS: windows + ARCH: x86_64 + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + submodules: 'recursive' + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.3 + + - name: Configure CMake + run: cmake -B build -DCMAKE_BUILD_TYPE:STRING=Release + + - name: Build CMake + run: cmake --build build --config Release --target all + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: raylib-cruby-${{ env.ARCH }} + path: | + ${{ github.workspace }}/build/raylib-cruby-${{ env.ARCH }} + ${{ github.workspace }}/build/*.dll + retention-days: 90 + diff --git a/.gitignore b/.gitignore index 149fca1..477ed92 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ mkmf.log /.config/ +/build/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 16e663e..9723350 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,7 +5,8 @@ [submodule "third_party/raygui"] path = third_party/raygui url = https://github.com/Nathan-MV/raygui.git - branch = raylibruby + branch = raylibruby [submodule "third_party/reasings"] path = third_party/reasings - url = https://github.com/raylib-extras/reasings + url = https://github.com/Nathan-MV/reasings.git + branch = raylibruby diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..265e75c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,76 @@ +cmake_minimum_required(VERSION 3.20) + +# Project Settings +project(Game VERSION 0.1.0) + +# Set C++ standard and required flag +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Set Rpath +set(CMAKE_SKIP_BUILD_RPATH FALSE) +set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +set(CMAKE_INSTALL_RPATH "\${ORIGIN}") + +# Set directories +set(SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ext/rubyraylib") +set(THIRD_PARTY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party) + +# set(OPENGL_VERSION "4.3") +# set(PLATFORM RGFW CACHE STRING "" FORCE) +# set(PLATFORM SDL CACHE STRING "" FORCE) + +# Set up third-party libraries +set(LIBRARIES + raylib + raygui + reasings +) + +foreach(LIB ${LIBRARIES}) + set(LIB_DIR ${THIRD_PARTY_DIR}/${LIB}) + set(LIB_BUILD_DIR ${CMAKE_BINARY_DIR}/third_party/${LIB}) + + add_subdirectory(${LIB_DIR}) + + if(${LIB} STREQUAL "raylib") + include_directories(${LIB_BUILD_DIR}/raylib/include) + target_compile_definitions(${LIB} PRIVATE PLATFORM_DESKTOP_RGFW) + else() + include_directories(${LIB_BUILD_DIR}/include) + endif() + + if(${LIB} STREQUAL "raygui") + target_compile_definitions(${LIB} PRIVATE RAYGUI_IMPLEMENTATION) + endif() +endforeach() + +# Executable definition +file(GLOB SRC_FILES ${SRC_DIR}/*.cpp) +add_executable(game ${SRC_FILES}) +set_target_properties(game PROPERTIES OUTPUT_NAME "raylib-cruby-${CMAKE_SYSTEM_PROCESSOR}") + +add_dependencies(game ${LIBRARIES}) + +# Find Ruby +find_package(Ruby 3.3 REQUIRED) + +# Set up include directories +target_include_directories(game + PUBLIC + $ + $ + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${RUBY_INCLUDE_PATH} +) + +# Set up link libraries +target_link_libraries(game PRIVATE ${LIBRARIES} ${RUBY_LIBRARY}) + +# Copy Ruby library to output directory +add_custom_command(TARGET game POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${RUBY_LIBRARY} + $ +) diff --git a/README.md b/README.md index 72220c3..6864249 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,6 @@ git clone https://github.com/Nathan-MV/raylib-cruby-extension cd raylib-cruby-extension git submodule update --init --recursive ``` -Note: If you encounter an "undefined symbol: RayLoadImage" error after compiling, it means Raylib was not checked out to the origin/rubyraylib branch correctly (Still wondering how to fix it). - Install Dependencies ``` @@ -25,24 +24,31 @@ bundle install --with compile - Raylib Dependencies (Ubuntu) ``` -sudo apt install libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev libwayland-dev libxkbcommon-dev +sudo apt install cmake ninja-build ruby-devel libasound2-dev libx11-dev libxrandr-dev libxi-dev libgl1-mesa-dev libglu1-mesa-dev libxcursor-dev libxinerama-dev libwayland-dev libxkbcommon-dev ``` - Raylib Dependencies (Fedora) ``` -sudo dnf install alsa-lib-devel mesa-libGL-devel libX11-devel libXrandr-devel libXi-devel libXcursor-devel libXinerama-devel libatomic wayland-devel libxkbcommon-devel wayland-protocols-devel +sudo dnf install cmake ninja-build ruby-devel alsa-lib-devel mesa-libGL-devel libX11-devel libXrandr-devel libXi-devel libXcursor-devel libXinerama-devel libatomic wayland-devel libxkbcommon-devel wayland-protocols-devel ``` - Raylib Dependencies (Arch Linux) ``` -sudo pacman -S alsa-lib mesa libx11 libxrandr libxi libxcursor libxinerama +sudo pacman -S cmake ninja ruby alsa-lib mesa libx11 libxrandr libxi libxcursor libxinerama ``` -- Compile +- Compile (Ruby Extension) ``` rake ``` +- Compile (Binary) +Note: Require CMake, Ninja and Ruby 3.3 (Currently the Windows binary does not work, help is appreciated) +``` +cmake -B build -G Ninja -DCMAKE_BUILD_TYPE:STRING=Release +cmake --build build --config Release --target all +``` + ## Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/Nathan-MV/raylib-cruby-extension. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/Nathan-MV/raylib-cruby-extension/blob/master/CODE_OF_CONDUCT.md). diff --git a/ext/rubyraylib/extconf.rb b/ext/rubyraylib/extconf.rb index 77f6aa5..f99f3eb 100644 --- a/ext/rubyraylib/extconf.rb +++ b/ext/rubyraylib/extconf.rb @@ -11,13 +11,19 @@ $INCFLAGS << " -I#{raylib_dir} -I#{raygui_dir} -I#{reasings_dir}" $LDFLAGS << " -L#{raylib_dir} -L#{raygui_dir} -L#{reasings_dir}" -# Link against the static libraries +# Specify the static libraries to link against +raylib_lib = File.expand_path("#{raylib_dir}/libraylib.a") +raygui_lib = File.expand_path("#{raygui_dir}/libraygui.a") +reasings_lib = File.expand_path("#{reasings_dir}/libreasings.a") + +$LDFLAGS << " #{raylib_lib} #{raygui_lib} #{reasings_lib}" + if /linux/i =~ RUBY_PLATFORM - $LDFLAGS << " -lraylib -lraygui -lreasings -lGL -lm -lpthread -ldl -lrt -lX11 -lXrandr" + $LDFLAGS << " -lGL -lm -lpthread -ldl -lrt -lX11 -lXrandr" elsif /darwin/i =~ RUBY_PLATFORM - $LDFLAGS << " -lraylib -lraygui -lreasings -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL" + $LDFLAGS << " -framework CoreVideo -framework IOKit -framework Cocoa -framework GLUT -framework OpenGL" else - $LDFLAGS << " -lraylib -lraygui -lreasings -lgdi32 -lwinmm" + $LDFLAGS << " -lgdi32 -lwinmm" end # Debugging information diff --git a/ext/rubyraylib/ruby_values.hpp b/ext/rubyraylib/ruby_values.hpp index 3be9652..c2be89c 100644 --- a/ext/rubyraylib/ruby_values.hpp +++ b/ext/rubyraylib/ruby_values.hpp @@ -2,6 +2,8 @@ #define RUBY_VALUES_H #include +#include +#include #include #include #include "vec2.hpp" diff --git a/ext/rubyraylib/rubyraylib.cpp b/ext/rubyraylib/rubyraylib.cpp index 302e5dc..7a58bdf 100644 --- a/ext/rubyraylib/rubyraylib.cpp +++ b/ext/rubyraylib/rubyraylib.cpp @@ -30,3 +30,63 @@ RUBY_FUNC_EXPORTED void Init_rubyraylib(void) { // Custom initializeTextureAtlas(); } + +static void initializeRubyInterpreter() { + int argc = 0; + char **argv = nullptr; + + ruby_sysinit(&argc, &argv); + RUBY_INIT_STACK; + ruby_init(); + rb_enc_set_default_internal(rb_enc_from_encoding(rb_utf8_encoding())); + rb_enc_set_default_external(rb_enc_from_encoding(rb_utf8_encoding())); +} + +static void initializeRubyArguments() { + std::vector args{"RUBY", "-e ", "--yjit", "--parser=prism"}; + void *rubyNode = ruby_options(args.size(), const_cast(args.data())); + int executionState = 0; + bool success = ruby_executable_node(rubyNode, &executionState); + if (success) { + ruby_exec_node(rubyNode); + } else { + std::cerr << "RUBY: Failed to execute ruby arguments" << std::endl; + ruby_cleanup(executionState); + } +} + +static VALUE script_run(VALUE) { + rb_ary_push(rb_gv_get("$LOAD_PATH"), rb_str_new_literal("./script")); + rb_load(rb_str_new_literal("./main.rb"), 0); + return Qnil; +} + +static VALUE script_rescue(VALUE, VALUE exc) { + VALUE backtrace = rb_ary_to_ary(rb_funcall(exc, rb_intern("backtrace"), 0)); + VALUE message = rb_str_to_str(rb_funcall(exc, rb_intern("message"), 0)); + std::cerr << StringValueCStr(message) << std::endl; + for (long i = 0; i < RARRAY_LEN(backtrace); ++i) { + VALUE lp = rb_str_to_str(rb_ary_entry(backtrace, i)); + std::cerr << StringValueCStr(lp) << std::endl; + } + return Qnil; +} + +int main() { + // Initialize components + initializeRubyInterpreter(); + initializeRubyArguments(); + Init_rubyraylib(); + + try { + rb_rescue2(script_run, Qnil, script_rescue, Qnil, rb_eException, + static_cast(0)); + } catch (std::exception &e) { + std::string msg = "Error:\n"; + std::cerr << msg + e.what() << std::endl; + } + ruby_finalize(); + + // Return success or failure based on script evaluation + return Qnil; +} diff --git a/ext/rubyraylib/rubyraylib.hpp b/ext/rubyraylib/rubyraylib.hpp index 550a523..8b3c213 100644 --- a/ext/rubyraylib/rubyraylib.hpp +++ b/ext/rubyraylib/rubyraylib.hpp @@ -1,6 +1,12 @@ #ifndef RUBYRAYLIB_H #define RUBYRAYLIB_H 1 +#include +#include +#include +#include +#include + #include "ruby_values.hpp" #include "raylib_values.hpp" diff --git a/lib/rubyraylib/main.rb b/lib/main.rb similarity index 74% rename from lib/rubyraylib/main.rb rename to lib/main.rb index d124335..00e3c0a 100644 --- a/lib/rubyraylib/main.rb +++ b/lib/main.rb @@ -1,5 +1,12 @@ +# For the binary + # frozen_string_literal: true +require_relative "rubyraylib/version" +require_relative "rubyraylib/settings" + +require_relative "rubyraylib/raymark" + class Game def initialize(klass) Window.init(SCREEN_WIDTH, SCREEN_HEIGHT, klass.to_s) @@ -20,3 +27,5 @@ def run Window.close end end + +Game.new(Raymark).run diff --git a/lib/rubyraylib.rb b/lib/rubyraylib.rb index 5f90cfa..d9ed85e 100644 --- a/lib/rubyraylib.rb +++ b/lib/rubyraylib.rb @@ -6,6 +6,25 @@ require_relative "rubyraylib/raymark" -require_relative "rubyraylib/main" +class Game + def initialize(klass) + Window.init(SCREEN_WIDTH, SCREEN_HEIGHT, klass.to_s) + Window.target_fps = Window.refresh_rate(Window.current_monitor) + @klass = klass.new + end + + def run + until Window.should_close? + @klass.update(Window.frame_time) + Draw.begin do + Draw.clear(Color::WHITE) + @klass.draw + Window.show_fps(0, 0) + end + end + @klass.unload + Window.close + end +end Game.new(Raymark).run diff --git a/lib/rubyraylib/raymark.rb b/lib/rubyraylib/raymark.rb index 004e5c1..addb72c 100644 --- a/lib/rubyraylib/raymark.rb +++ b/lib/rubyraylib/raymark.rb @@ -2,7 +2,7 @@ class Raymark # The upper limit decreased after i updated Raylib from 5.0 to 5.5... - MAX_ELEMENTS = 30_000 # RubyVM::YJIT.enabled? ? 90_000 : 50_000 + MAX_ELEMENTS = 80_000 # RubyVM::YJIT.enabled? ? 110_000 : 80_000 MAX_BATCH_ELEMENTS = 8192 MOVE_ELEMENTS = false diff --git a/third_party/raygui b/third_party/raygui index ec34196..f8eb4e4 160000 --- a/third_party/raygui +++ b/third_party/raygui @@ -1 +1 @@ -Subproject commit ec3419695422b3fe363d9a79b8969753db6240a2 +Subproject commit f8eb4e4a5a6b484791809cc9ba4405ba64a6819e diff --git a/third_party/reasings b/third_party/reasings index 76fb4a6..336a92f 160000 --- a/third_party/reasings +++ b/third_party/reasings @@ -1 +1 @@ -Subproject commit 76fb4a6e4d6037803a329c0177e42449e495d9ec +Subproject commit 336a92f07de6c9ff867d618b8574ce9a1efa4e43