-
-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: MarkAnthonyM <[email protected]>
- Loading branch information
1 parent
acd4249
commit b185ec3
Showing
11 changed files
with
466 additions
and
51 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[package] | ||
name = "minimal-web" | ||
version = "0.1.0" | ||
authors = ["Jay Oster <[email protected]>"] | ||
edition = "2018" | ||
resolver = "2" | ||
publish = false | ||
|
||
[features] | ||
optimize = ["log/release_max_level_warn"] | ||
web = ["wgpu/webgl", "winit/web-sys"] | ||
default = ["optimize"] | ||
|
||
[dependencies] | ||
log = "0.4" | ||
pixels = { path = "../.." } | ||
wgpu = "0.11" | ||
winit = "0.25" | ||
winit_input_helper = "0.10" | ||
|
||
[target.'cfg(target_arch = "wasm32")'.dependencies] | ||
console_error_panic_hook = "0.1" | ||
console_log = "0.2" | ||
wasm-bindgen = "0.2.78" | ||
wasm-bindgen-futures = "0.4" | ||
web-sys = "0.3" | ||
|
||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] | ||
env_logger = "0.9" | ||
pollster = "0.2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
# Hello Pixels + Web | ||
|
||
![Hello Pixels + Web](../../img/minimal-web.png) | ||
|
||
Minimal example for WebGL2. | ||
|
||
## Install build dependencies | ||
|
||
Install the WASM32 target and a few CLI tools: | ||
|
||
```bash | ||
rustup target add wasm32-unknown-unknown | ||
cargo install --locked wasm-bindgen-cli just miniserve | ||
``` | ||
|
||
## Running on the Web | ||
|
||
Build the project and start a local server to host it: | ||
|
||
```bash | ||
just serve minimal-web | ||
``` | ||
|
||
Open http://localhost:8080/ in your browser to run the example. | ||
|
||
To build the project without serving it: | ||
|
||
```bash | ||
just build minimal-web | ||
``` | ||
|
||
The build files are stored in `./target/minimal-web/`. | ||
|
||
## Running on native targets | ||
|
||
```bash | ||
cargo run --release --package minimal-web | ||
``` | ||
|
||
## About | ||
|
||
This example is based on `minimal-winit`, demonstrating how to build your app for WebGL2 targets. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<!DOCTYPE html> | ||
|
||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<style type="text/css"> | ||
body { | ||
background-color: #000; | ||
margin: 0; | ||
overflow: hidden; | ||
} | ||
</style> | ||
<title>Hello Pixels + Web</title> | ||
</head> | ||
<body> | ||
<script type="module"> | ||
import init from "./minimal-web.js"; | ||
window.addEventListener("load", () => { | ||
init(); | ||
}); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
#![deny(clippy::all)] | ||
#![forbid(unsafe_code)] | ||
|
||
use log::error; | ||
use pixels::{Pixels, SurfaceTexture}; | ||
use std::rc::Rc; | ||
use winit::dpi::LogicalSize; | ||
use winit::event::{Event, VirtualKeyCode}; | ||
use winit::event_loop::{ControlFlow, EventLoop}; | ||
use winit::window::WindowBuilder; | ||
use winit_input_helper::WinitInputHelper; | ||
|
||
const WIDTH: u32 = 320; | ||
const HEIGHT: u32 = 240; | ||
const BOX_SIZE: i16 = 64; | ||
|
||
/// Representation of the application state. In this example, a box will bounce around the screen. | ||
struct World { | ||
box_x: i16, | ||
box_y: i16, | ||
velocity_x: i16, | ||
velocity_y: i16, | ||
} | ||
|
||
fn main() { | ||
#[cfg(target_arch = "wasm32")] | ||
{ | ||
std::panic::set_hook(Box::new(console_error_panic_hook::hook)); | ||
console_log::init_with_level(log::Level::Trace).expect("error initializing logger"); | ||
|
||
wasm_bindgen_futures::spawn_local(run()); | ||
} | ||
|
||
#[cfg(not(target_arch = "wasm32"))] | ||
{ | ||
env_logger::init(); | ||
|
||
pollster::block_on(run()); | ||
} | ||
} | ||
|
||
async fn run() { | ||
let event_loop = EventLoop::new(); | ||
let window = { | ||
let size = LogicalSize::new(WIDTH as f64, HEIGHT as f64); | ||
WindowBuilder::new() | ||
.with_title("Hello Pixels + Web") | ||
.with_inner_size(size) | ||
.with_min_inner_size(size) | ||
.build(&event_loop) | ||
.expect("WindowBuilder error") | ||
}; | ||
|
||
let window = Rc::new(window); | ||
|
||
#[cfg(target_arch = "wasm32")] | ||
{ | ||
use wasm_bindgen::JsCast; | ||
use winit::platform::web::WindowExtWebSys; | ||
|
||
// Retrieve current width and height dimensions of browser client window | ||
let get_window_size = || { | ||
let client_window = web_sys::window().unwrap(); | ||
LogicalSize::new( | ||
client_window.inner_width().unwrap().as_f64().unwrap(), | ||
client_window.inner_height().unwrap().as_f64().unwrap(), | ||
) | ||
}; | ||
|
||
let window = Rc::clone(&window); | ||
|
||
// Initialize winit window with current dimensions of browser client | ||
window.set_inner_size(get_window_size()); | ||
|
||
let client_window = web_sys::window().unwrap(); | ||
|
||
// Attach winit canvas to body element | ||
web_sys::window() | ||
.and_then(|win| win.document()) | ||
.and_then(|doc| doc.body()) | ||
.and_then(|body| { | ||
body.append_child(&web_sys::Element::from(window.canvas())) | ||
.ok() | ||
}) | ||
.expect("couldn't append canvas to document body"); | ||
|
||
// Listen for resize event on browser client. Adjust winit window dimensions | ||
// on event trigger | ||
let closure = wasm_bindgen::closure::Closure::wrap(Box::new(move |_e: web_sys::Event| { | ||
let size = get_window_size(); | ||
window.set_inner_size(size) | ||
}) as Box<dyn FnMut(_)>); | ||
client_window | ||
.add_event_listener_with_callback("resize", closure.as_ref().unchecked_ref()) | ||
.unwrap(); | ||
closure.forget(); | ||
} | ||
|
||
let mut input = WinitInputHelper::new(); | ||
let mut pixels = { | ||
let window_size = window.inner_size(); | ||
let surface_texture = | ||
SurfaceTexture::new(window_size.width, window_size.height, window.as_ref()); | ||
Pixels::new_async(WIDTH, HEIGHT, surface_texture) | ||
.await | ||
.expect("Pixels error") | ||
}; | ||
let mut world = World::new(); | ||
|
||
event_loop.run(move |event, _, control_flow| { | ||
// Draw the current frame | ||
if let Event::RedrawRequested(_) = event { | ||
world.draw(pixels.get_frame()); | ||
if pixels | ||
.render() | ||
.map_err(|e| error!("pixels.render() failed: {}", e)) | ||
.is_err() | ||
{ | ||
*control_flow = ControlFlow::Exit; | ||
return; | ||
} | ||
} | ||
|
||
// Handle input events | ||
if input.update(&event) { | ||
// Close events | ||
if input.key_pressed(VirtualKeyCode::Escape) || input.quit() { | ||
*control_flow = ControlFlow::Exit; | ||
return; | ||
} | ||
|
||
// Resize the window | ||
if let Some(size) = input.window_resized() { | ||
pixels.resize_surface(size.width, size.height); | ||
} | ||
|
||
// Update internal state and request a redraw | ||
world.update(); | ||
window.request_redraw(); | ||
} | ||
}); | ||
} | ||
|
||
impl World { | ||
/// Create a new `World` instance that can draw a moving box. | ||
fn new() -> Self { | ||
Self { | ||
box_x: 24, | ||
box_y: 16, | ||
velocity_x: 1, | ||
velocity_y: 1, | ||
} | ||
} | ||
|
||
/// Update the `World` internal state; bounce the box around the screen. | ||
fn update(&mut self) { | ||
if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 { | ||
self.velocity_x *= -1; | ||
} | ||
if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 { | ||
self.velocity_y *= -1; | ||
} | ||
|
||
self.box_x += self.velocity_x; | ||
self.box_y += self.velocity_y; | ||
} | ||
|
||
/// Draw the `World` state to the frame buffer. | ||
/// | ||
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb` | ||
fn draw(&self, frame: &mut [u8]) { | ||
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() { | ||
let x = (i % WIDTH as usize) as i16; | ||
let y = (i / WIDTH as usize) as i16; | ||
|
||
let inside_the_box = x >= self.box_x | ||
&& x < self.box_x + BOX_SIZE | ||
&& y >= self.box_y | ||
&& y < self.box_y + BOX_SIZE; | ||
|
||
let rgba = if inside_the_box { | ||
[0x5e, 0x48, 0xe8, 0xff] | ||
} else { | ||
[0x48, 0xb2, 0xe8, 0xff] | ||
}; | ||
|
||
pixel.copy_from_slice(&rgba); | ||
} | ||
} | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.