diff --git a/Makefile b/Makefile index 9d7d421..90a4e64 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ CFLAGS := \ -Irust_src/include \ -sEXPORTED_FUNCTIONS=_main \ -sSTACK_SIZE=2097152 \ + -s USE_GLFW=3 \ ${C_OTHER_FLAGS} # Check https://emscripten.org/docs/tools_reference/emcc.html for more compiler # flags to pass to emcc. @@ -20,15 +21,24 @@ CFLAGS := \ HEADERS := \ rust_src/include/rust_src.h -all: dist +RUST_SOURCES := \ + rust_src/src/lib.rs \ + rust_src/src/ffi_raylib.rs -rust_src/target/wasm32-unknown-emscripten/${RUST_BUILD_TYPE}/libems_rust_template.a: +all: dist/my_project.html + +rust_src/target/wasm32-unknown-emscripten/${RUST_BUILD_TYPE}/libems_rust_template.a: third_party/raylib/src/libraylib.a ${RUST_SOURCES} cd rust_src && cargo build --target=wasm32-unknown-emscripten ${RUST_EXTRA_FLAGS} -dist: rust_src/target/wasm32-unknown-emscripten/${RUST_BUILD_TYPE}/libems_rust_template.a src/main.c.o - @mkdir dist +dist/my_project.html: rust_src/target/wasm32-unknown-emscripten/${RUST_BUILD_TYPE}/libems_rust_template.a src/main.c.o third_party/raylib/src/libraylib.a + @mkdir -p dist ${CC} -o dist/my_project.html ${CFLAGS} $^ - ln -s my_project.html dist/index.html + ln -sf my_project.html dist/index.html + +third_party/raylib/src/libraylib.a: + test -d third_party/raylib/src || git clone --depth=1 --no-single-branch https://github.com/raysan5/raylib.git third_party/raylib + cd third_party/raylib/ && git restore . && git checkout 5.0 && patch -p1 < ../raylib_patch_00.patch + source ${HOME}/git/emsdk/emsdk_env.sh && make -C third_party/raylib/src .PHONY: clean @@ -36,6 +46,7 @@ clean: cd rust_src && cargo clean rm -f src/*.c.o rm -rf dist + test -d third_party/raylib/src && make -C third_party/raylib/src clean %.c.o: %.c ${HEADERS} ${CC} -o $@ -c ${CFLAGS} $< diff --git a/rust_src/Cargo.lock b/rust_src/Cargo.lock index 23b7a83..6a9423a 100644 --- a/rust_src/Cargo.lock +++ b/rust_src/Cargo.lock @@ -2,6 +2,285 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "ems_rust_template" version = "0.1.0" +dependencies = [ + "bindgen", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.158" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "prettyplease" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/rust_src/Cargo.toml b/rust_src/Cargo.toml index ea520ba..f58aa12 100644 --- a/rust_src/Cargo.toml +++ b/rust_src/Cargo.toml @@ -13,3 +13,6 @@ panic = "abort" panic = "abort" [dependencies] + +[build-dependencies] +bindgen = "0.70.1" diff --git a/rust_src/build.rs b/rust_src/build.rs new file mode 100644 index 0000000..baf96a7 --- /dev/null +++ b/rust_src/build.rs @@ -0,0 +1,17 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + let bindings = bindgen::Builder::default() + .header("wrapper.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .clang_arg("-fvisibility=default") + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/rust_src/src/ffi_raylib.rs b/rust_src/src/ffi_raylib.rs new file mode 100644 index 0000000..a38a13a --- /dev/null +++ b/rust_src/src/ffi_raylib.rs @@ -0,0 +1,5 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/rust_src/src/lib.rs b/rust_src/src/lib.rs index 59944f1..2f1f47f 100644 --- a/rust_src/src/lib.rs +++ b/rust_src/src/lib.rs @@ -1,5 +1,15 @@ +pub mod ffi_raylib; + use std::ffi; +pub const SCREEN_WIDTH: ffi::c_int = 800; +pub const SCREEN_HEIGHT: ffi::c_int = 600; +pub const APPLICATION_TITLE: &'static str = "My Project"; + +pub const EXAMPLE_BALL_VX: f32 = 70.0f32; +pub const EXAMPLE_BALL_GRAVITY: f32 = 200.0f32; +pub const EXAMPLE_BALL_COLOR_RATE: f32 = 0.4f32; + #[no_mangle] pub extern "C" fn get_main_ctx() -> *mut ffi::c_void { Context::ems_new() @@ -22,7 +32,11 @@ pub extern "C" fn ctx_draw(ctx: *mut ffi::c_void) { } #[no_mangle] -pub extern "C" fn ctx_resize_event_callback(ctx: *mut ffi::c_void, width: ffi::c_int, height: ffi::c_int) { +pub extern "C" fn ctx_resize_event_callback( + ctx: *mut ffi::c_void, + width: ffi::c_int, + height: ffi::c_int, +) { unsafe { let ctx: *mut Context = ctx as *mut Context; (*ctx).resize_event_callback(width, height); @@ -30,12 +44,34 @@ pub extern "C" fn ctx_resize_event_callback(ctx: *mut ffi::c_void, width: ffi::c } struct Context { + ball_radius: f32, + ball_x: f32, + ball_y: f32, + ball_vx: f32, + ball_vy: f32, + ball_ay: f32, + ball_color: f32, } impl Context { pub fn new() -> Self { - Self { + let mut ctx = Self { + ball_radius: 30.0f32, + ball_x: SCREEN_WIDTH as f32 / 2.0f32, + ball_y: SCREEN_HEIGHT as f32 / 2.0f32, + ball_vx: EXAMPLE_BALL_VX, + ball_vy: 0.0f32, + ball_ay: EXAMPLE_BALL_GRAVITY, + ball_color: 0.0f32, + }; + + // Raylib initialization calls. + let title_cstring: ffi::CString = ffi::CString::new(APPLICATION_TITLE).unwrap(); + unsafe { + ffi_raylib::InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, title_cstring.as_ptr()); } + + ctx } pub fn ems_new() -> *mut ffi::c_void { @@ -45,13 +81,124 @@ impl Context { pub fn update(&mut self) { println!("update called."); + + let f_delta: f32 = unsafe { ffi_raylib::GetFrameTime() }; + + self.ball_vy += f_delta * self.ball_ay; + + self.ball_x += f_delta * self.ball_vx; + if self.ball_x - self.ball_radius <= 0.0f32 + || self.ball_x + self.ball_radius >= SCREEN_WIDTH as f32 + { + self.ball_vx *= -1.0f32; + self.ball_x += f_delta * self.ball_vx * 2.0f32; + } + + self.ball_y += f_delta * self.ball_vy; + if self.ball_y + self.ball_radius >= SCREEN_HEIGHT as f32 { + self.ball_vy *= -1.0f32; + self.ball_y += f_delta * self.ball_vy * 2.0f32; + } else if self.ball_y - self.ball_radius <= 0.0f32 { + self.ball_y -= f_delta * self.ball_vy * 2.0f32; + self.ball_vy = 0.0f32; + } + + self.ball_color += f_delta * EXAMPLE_BALL_COLOR_RATE; + if self.ball_color >= 1.0f32 { + self.ball_color -= 1.0f32; + } } pub fn draw(&mut self) { - println!("draw called."); + println!( + "draw called. ball xy: {:.1}, {:.1}", + self.ball_x, self.ball_y + ); + // Raylib draw calls. + unsafe { + ffi_raylib::BeginDrawing(); + ffi_raylib::ClearBackground(ffi_raylib::Color { + r: 0, + g: 0, + b: 0, + a: 255, + }); + ffi_raylib::DrawText( + "Test Text.\0" as *const str as *const i8, + 10, + 10, + 24, + ffi_raylib::Color { + r: 255, + g: 255, + b: 255, + a: 255, + }, + ); + ffi_raylib::DrawCircle( + self.ball_x.round() as i32, + self.ball_y.round() as i32, + self.ball_radius, + self.get_color_from_value(), + ); + ffi_raylib::EndDrawing(); + } } - pub fn resize_event_callback(&mut self, width: ffi::c_int, height: ffi::c_int) { - println!("Resize event: {}, {}", width, height); + pub fn resize_event_callback(&mut self, _width: ffi::c_int, _height: ffi::c_int) { + println!("Resize event ignored."); + } + + fn get_color_from_value(&self) -> ffi_raylib::Color { + if self.ball_color < 0.1667f32 { + // Red to yellow. + ffi_raylib::Color { + r: 255, + g: (255f32 * (self.ball_color / 0.1667f32)) as u8, + b: 0, + a: 255, + } + } else if self.ball_color < 0.3333f32 { + // Yellow to green. + ffi_raylib::Color { + r: (255f32 * (1.0f32 - (self.ball_color - 0.1667f32) / (0.3333f32 - 0.1667f32))) + as u8, + g: 255, + b: 0, + a: 255, + } + } else if self.ball_color < 0.5f32 { + // Green to cyan. + ffi_raylib::Color { + r: 0, + g: 255, + b: (255f32 * (self.ball_color - 0.3333f32) / (0.5f32 - 0.3333f32)) as u8, + a: 255, + } + } else if self.ball_color < 0.6667f32 { + // Cyan to blue. + ffi_raylib::Color { + r: 0, + g: (255f32 * (1.0f32 - (self.ball_color - 0.5f32) / (0.6667f32 - 0.5f32))) as u8, + b: 255, + a: 255, + } + } else if self.ball_color < 0.8333f32 { + // Blue to magenta. + ffi_raylib::Color { + r: (255f32 * (self.ball_color - 0.6667f32) / (0.8333f32 - 0.6667f32)) as u8, + g: 0, + b: 255, + a: 255, + } + } else { + // Magenta to red. + ffi_raylib::Color { + r: 255, + g: 0, + b: (255f32 * (1.0f32 - (self.ball_color - 0.8333f32) / (1.0f32 - 0.8333f32))) as u8, + a: 255, + } + } } } diff --git a/rust_src/wrapper.h b/rust_src/wrapper.h new file mode 100644 index 0000000..598565a --- /dev/null +++ b/rust_src/wrapper.h @@ -0,0 +1 @@ +#include "../third_party/raylib/src/raylib.h" diff --git a/third_party/.gitignore b/third_party/.gitignore new file mode 100644 index 0000000..c7c61eb --- /dev/null +++ b/third_party/.gitignore @@ -0,0 +1 @@ +raylib/ diff --git a/third_party/raylib_patch_00.patch b/third_party/raylib_patch_00.patch new file mode 100644 index 0000000..145fa0d --- /dev/null +++ b/third_party/raylib_patch_00.patch @@ -0,0 +1,36 @@ +local changes for emsdk + +--- a/src/Makefile ++++ b/src/Makefile +@@ -51,7 +51,7 @@ + # Define required environment variables + #------------------------------------------------------------------------------------------------ + # Define target platform: PLATFORM_DESKTOP, PLATFORM_DRM, PLATFORM_ANDROID, PLATFORM_WEB +-PLATFORM ?= PLATFORM_DESKTOP ++PLATFORM ?= PLATFORM_WEB + + # Define required raylib variables + RAYLIB_VERSION = 5.0.0 +--- a/src/config.h ++++ b/src/config.h +@@ -59,7 +59,7 @@ + // Use a partial-busy wait loop, in this case frame sleeps for most of the time, but then runs a busy loop at the end for accuracy + #define SUPPORT_PARTIALBUSY_WAIT_LOOP 1 + // Allow automatic screen capture of current screen pressing F12, defined in KeyCallback() +-#define SUPPORT_SCREEN_CAPTURE 1 ++//#define SUPPORT_SCREEN_CAPTURE 1 + // Allow automatic gif recording of current screen pressing CTRL+F12, defined in KeyCallback() + #define SUPPORT_GIF_RECORDING 1 + // Support CompressData() and DecompressData() functions +--- a/src/rcore.c ++++ b/src/rcore.c +@@ -349,9 +349,7 @@ RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported s + + CoreData CORE = { 0 }; // Global CORE state context + +-#if defined(SUPPORT_SCREEN_CAPTURE) + static int screenshotCounter = 0; // Screenshots counter +-#endif + + #if defined(SUPPORT_GIF_RECORDING) + int gifFrameCounter = 0; // GIF frames counter