Skip to content

Commit

Permalink
Merge branch 'wasm'
Browse files Browse the repository at this point in the history
  • Loading branch information
tormol committed Aug 1, 2023
2 parents fdfa357 + f999b9d commit 5c62238
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 23 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
target
/target/
/wasm/*.wasm
/wasm/*.ts
/wasm/*.js

[Tt]humbs.db
.DS_Store
24 changes: 24 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ interface = {path="interface"}
engine = {path="engine"}
game = {path="game/", optional=true}

[target.'cfg(target_arch="wasm32")'.dependencies]
log = "0.4"
wasm-logger = "0.2"
console_error_panic_hook = "0.1.6"

[features]
dyn = ["engine/dyn", "interface/dyn", "game"]
piston = ["engine/piston"]
Expand Down
18 changes: 18 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.PHONY: check run dev clippy wasm

check:
cargo check
cargo check --features dyn

run:
cargo run

dev:
cargo run --features dyn

clippy:
cargo clippy --features dyn

wasm:
cargo build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/debug/space_tennis.wasm --out-dir wasm --target web
71 changes: 49 additions & 22 deletions engine/src/speedy2d.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,36 @@
use interface::game::*;

use std::collections::HashMap;
use std::thread;
use std::rc::Rc;
use std::time::{Duration, Instant};
#[cfg(not(target_arch = "wasm32"))]
use std::thread;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Duration;

extern crate speedy2d;
use speedy2d::{Graphics2D, Window};
use speedy2d::Graphics2D;
use speedy2d::color::Color as spColor;
use speedy2d::dimen::Vector2;
use speedy2d::font::{Font, TextLayout, TextOptions, FormattedTextBlock};
use speedy2d::shape::Rectangle;
use speedy2d::time::Stopwatch;
use speedy2d::window::{
MouseButton as spMouseButton,
VirtualKeyCode,
WindowCreationOptions,
WindowHandler,
WindowHelper,
WindowSize,
};
#[cfg(target_arch="wasm32")]
use speedy2d::WebCanvas;
#[cfg(not(target_arch = "wasm32"))]
use speedy2d::Window;
#[cfg(not(target_arch="wasm32"))]
use speedy2d::window::{WindowCreationOptions, WindowSize};

extern crate fxhash;
use fxhash::FxBuildHasher;

#[cfg(not(target_arch="wasm32"))]
const UPDATE_RATE: u32 = 125; // the standard USB polling rate.

fn map_key(key: VirtualKeyCode) -> Option<Key> {
Expand Down Expand Up @@ -87,19 +95,24 @@ impl TextCache {
struct GameWrapper<G: Game> {
game: G,
window_size: [f32; 2], // changes if window is resized
last_physics: Instant,
stopwatch: Stopwatch,
last_physics: f64,
shapes: Graphics,
text: TextCache,
}

impl<G: Game> WindowHandler for GameWrapper<G> {
fn on_start(&mut self,
h: &mut WindowHelper<()>,
_: speedy2d::window::WindowStartupInfo
info: speedy2d::window::WindowStartupInfo
) {
let size = info.viewport_size_pixels().into_f32();
self.window_size = [size.x, size.y];
h.set_cursor_visible(true);
h.set_cursor_grab(false).unwrap();
#[cfg(not(target_arch="wasm32"))]
let sender = h.create_user_event_sender();
#[cfg(not(target_arch="wasm32"))]
thread::spawn(move || {
loop {
sender.send_event(()).unwrap();
Expand All @@ -110,12 +123,15 @@ impl<G: Game> WindowHandler for GameWrapper<G> {

fn on_user_event(&mut self, _: &mut WindowHelper<()>, _: ()) {
let prev = self.last_physics;
self.last_physics = Instant::now();
let elapsed = self.last_physics.saturating_duration_since(prev);
self.game.update(elapsed.as_secs_f32());
self.last_physics = self.stopwatch.secs_elapsed();
let elapsed = self.last_physics - prev;
self.game.update(elapsed as f32);
}

fn on_draw(&mut self, h: &mut WindowHelper<()>, g: &mut Graphics2D) {
#[cfg(target_arch="wasm32")]
self.on_user_event(h, ());

g.clear_screen(spColor::BLACK);
self.game.render(&mut self.shapes);

Expand Down Expand Up @@ -226,22 +242,33 @@ impl<G: Game> WindowHandler for GameWrapper<G> {

#[inline(never)]
pub fn start<G:Game+'static>(game: G, name: &'static str, initial_size: [f32; 2]) {
let window_size = Vector2 { x: initial_size[0], y: initial_size[1] };
let window_size = WindowSize::ScaledPixels(window_size);
let options = WindowCreationOptions::new_windowed(window_size, None)
.with_always_on_top(false)
.with_decorations(true)
.with_resizable(true)
.with_transparent(false)
.with_vsync(true);
let window = Window::new_with_options(name, options).unwrap();

let wrapper = GameWrapper {
game,
window_size: initial_size,
last_physics: Instant::now(),
stopwatch: Stopwatch::new().expect("create stopwatch"),
last_physics: 0.0,
shapes: Graphics::default(),
text: TextCache::new(),
};
window.run_loop(wrapper);

#[cfg(target_arch="wasm32")]
{
let _ = name;
WebCanvas::new_for_id("space_tennis_game", wrapper)
.expect("bind to canvas");
// .unregister_when_dropped() would make the game end immediately.
}
#[cfg(not(target_arch="wasm32"))]
{
let window_size = Vector2 { x: initial_size[0], y: initial_size[1] };
let window_size = WindowSize::ScaledPixels(window_size);
let options = WindowCreationOptions::new_windowed(window_size, None)
.with_always_on_top(false)
.with_decorations(true)
.with_resizable(true)
.with_transparent(false)
.with_vsync(true);
let window = Window::new_with_options(name, options).unwrap();
window.run_loop(wrapper);
}
}
11 changes: 11 additions & 0 deletions interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,24 @@ macro_rules! expose_game{($mod:tt::$game:tt) => {
#[macro_export]
macro_rules! impl_main {($dir:tt) => {
extern crate engine;
#[cfg(target_arch="wasm32")]
extern crate wasm_logger;
#[cfg(target_arch="wasm32")]
extern crate log;

#[cfg(feature="dyn")]
extern crate $dir;
#[cfg(not(feature="dyn"))]
mod $dir;

fn main() {
#[cfg(target_arch="wasm32")]
{
wasm_logger::init(wasm_logger::Config::default());
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
log::info!("{} WebGL", game::NAME);
}

let game = game::create_game();
#[cfg(feature="dyn")]
engine::reload::start_reloading(&game);
Expand Down
26 changes: 26 additions & 0 deletions wasm/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>
<style>
body {
margin: 0px;
padding: 0px;
}

canvas {
position: absolute;
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<canvas id="space_tennis_game"></canvas>
<script type="module" src="./space_tennis.js"></script>
<script type="module">
import main from "./space_tennis.js";
main();
</script>
</body>
</html>

0 comments on commit 5c62238

Please sign in to comment.