Impl. example with Raylib

This commit is contained in:
Stephen Seo 2024-09-18 21:45:13 +09:00
parent f807978401
commit 96e76cc4d4
9 changed files with 510 additions and 10 deletions

View file

@ -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} $<

279
rust_src/Cargo.lock generated
View file

@ -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"

View file

@ -13,3 +13,6 @@ panic = "abort"
panic = "abort"
[dependencies]
[build-dependencies]
bindgen = "0.70.1"

17
rust_src/build.rs Normal file
View file

@ -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!");
}

View file

@ -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"));

View file

@ -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,
}
}
}
}

1
rust_src/wrapper.h Normal file
View file

@ -0,0 +1 @@
#include "../third_party/raylib/src/raylib.h"

1
third_party/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
raylib/

36
third_party/raylib_patch_00.patch vendored Normal file
View file

@ -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