Compare commits

...

2 commits

Author SHA1 Message Date
d231859fe2 Update README.md 2024-09-18 21:46:12 +09:00
96e76cc4d4 Impl. example with Raylib 2024-09-18 21:45:13 +09:00
10 changed files with 513 additions and 13 deletions

View file

@ -13,6 +13,7 @@ CFLAGS := \
-Irust_src/include \ -Irust_src/include \
-sEXPORTED_FUNCTIONS=_main \ -sEXPORTED_FUNCTIONS=_main \
-sSTACK_SIZE=2097152 \ -sSTACK_SIZE=2097152 \
-s USE_GLFW=3 \
${C_OTHER_FLAGS} ${C_OTHER_FLAGS}
# Check https://emscripten.org/docs/tools_reference/emcc.html for more compiler # Check https://emscripten.org/docs/tools_reference/emcc.html for more compiler
# flags to pass to emcc. # flags to pass to emcc.
@ -20,15 +21,24 @@ CFLAGS := \
HEADERS := \ HEADERS := \
rust_src/include/rust_src.h 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} 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 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 dist @mkdir -p dist
${CC} -o dist/my_project.html ${CFLAGS} $^ ${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 .PHONY: clean
@ -36,6 +46,7 @@ clean:
cd rust_src && cargo clean cd rust_src && cargo clean
rm -f src/*.c.o rm -f src/*.c.o
rm -rf dist rm -rf dist
test -d third_party/raylib/src && make -C third_party/raylib/src clean
%.c.o: %.c ${HEADERS} %.c.o: %.c ${HEADERS}
${CC} -o $@ -c ${CFLAGS} $< ${CC} -o $@ -c ${CFLAGS} $<

View file

@ -19,11 +19,11 @@ Just run `make` in the root of this project.
## Other Notes ## Other Notes
This `raylib` branch pulls the repository (if it doesn't exist) and builds it.
It should do this automatically when you invoke `make`.
The current set up of the update/draw loop uses The current set up of the update/draw loop uses
`emscripten_set_main_loop_arg(...)` with parameters that should call the `emscripten_set_main_loop_arg(...)` with parameters that should call the
browser's `requestAnimationFrame` that should call `update` and `draw` once per browser's `requestAnimationFrame` that should call `update` and `draw` once per
each frame at the fps that the browser decides, which should match the fps of each frame at the fps that the browser decides, which should match the fps of
your display. your display.
If you want to use graphics, I suggest using/building `raylib`, but that will
require building it separately with `emsdk` and linking to it in the Makefile.

279
rust_src/Cargo.lock generated
View file

@ -2,6 +2,285 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 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]] [[package]]
name = "ems_rust_template" name = "ems_rust_template"
version = "0.1.0" 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" panic = "abort"
[dependencies] [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; 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] #[no_mangle]
pub extern "C" fn get_main_ctx() -> *mut ffi::c_void { pub extern "C" fn get_main_ctx() -> *mut ffi::c_void {
Context::ems_new() Context::ems_new()
@ -22,7 +32,11 @@ pub extern "C" fn ctx_draw(ctx: *mut ffi::c_void) {
} }
#[no_mangle] #[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 { unsafe {
let ctx: *mut Context = ctx as *mut Context; let ctx: *mut Context = ctx as *mut Context;
(*ctx).resize_event_callback(width, height); (*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 { 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 { impl Context {
pub fn new() -> Self { 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 { pub fn ems_new() -> *mut ffi::c_void {
@ -45,13 +81,124 @@ impl Context {
pub fn update(&mut self) { pub fn update(&mut self) {
println!("update called."); 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) { 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) { pub fn resize_event_callback(&mut self, _width: ffi::c_int, _height: ffi::c_int) {
println!("Resize event: {}, {}", width, height); 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