diff --git a/Cargo.toml b/Cargo.toml index 3993b8e..084b3f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "yage" version = "0.0.1" description = "Yet another graphics engine" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] repository = "https://github.com/bwasty/yage" readme = "README.md" license = "MIT/Apache-2.0" @@ -18,23 +18,25 @@ maintenance = { status = "experimental" } crate-type = ["cdylib", "rlib"] [features] -wasm = ["web-sys", "js-sys", "console_error_panic_hook"] -native = [] gltf = ["yage-gltf"] -# NOTE: to disable the default wasm feature, use `default-features = false` -default = ["wasm", "gltf"] +# NOTE: to disable the default gltf feature, use `default-features = false` +default = ["gltf"] [workspace] -members = ["yage-core", "yage-gl", "yage-app", "yage-gltf"] +members = ["yage-core", "yage-gl", "yage-glutin", "yage-web", "yage-gltf"] exclude = ["examples/native-glutin", "examples/rust-webpack", "examples/native-azul"] [dependencies] +cfg-if = "0.1.6" + yage-core = { path = "yage-core", version = "0.0.1" } yage-gl = { path = "yage-gl", version = "0.0.1" } -yage-app = { path = "yage-app", version = "0.0.1" } yage-gltf = { path = "yage-gltf", version = "0.0.1", optional = true } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +yage-glutin = { path = "yage-glutin", version = "0.0.1" } +[target.'cfg(target_arch = "wasm32")'.dependencies] +yage-web = { path = "yage-web", version = "0.0.1" } -cfg-if = "0.1.6" wasm-bindgen = "0.2.37" # The `console_error_panic_hook` crate provides better debugging of panics by diff --git a/README.md b/README.md index c69ed68..aa4e4fa 100644 --- a/README.md +++ b/README.md @@ -17,52 +17,20 @@ Very, very early. Currently it's mostly [wasm-pack-template](https://github.com/ - [npm](https://www.npmjs.com/get-npm) ### Building -- `wasm-pack build` - ---- - -_GENERATED PART OF README_ - ---- - -# πŸ¦€πŸ•ΈοΈ `wasm-pack-template` - -A template for kick starting a Rust and WebAssembly project using -[`wasm-pack`](https://github.com/rustwasm/wasm-pack). - -This template is designed for compiling Rust libraries into WebAssembly and -publishing the resulting package to NPM. - -* Want to use the published NPM package in a Website? [Check out - `create-wasm-app`.](https://github.com/rustwasm/create-wasm-app) -* Want to make a monorepo-style Website without publishing to NPM? Check out - [`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template) - and/or - [`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template). - -## πŸ”‹ Batteries Included - -* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating - between WebAssembly and JavaScript. -* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) - for logging panic messages to the developer console. -* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized - for small code size. - -### πŸ› οΈ Build with `wasm-pack build` - ``` wasm-pack build ``` -### πŸ”¬ Test in Headless Browsers with `wasm-pack test` +### Examples +* Native + - `cd examples/native-glutin` + - `cargo run` +* Web + - `cd examples/rust-webpack` + - `npm install` + - `npm start` +### Testing ``` wasm-pack test --headless --firefox ``` - -### 🎁 Publish to NPM with `wasm-pack publish` - -``` -wasm-pack publish -``` diff --git a/examples/native-azul/Cargo.toml b/examples/native-azul/Cargo.toml index cc0c24c..40c66dd 100644 --- a/examples/native-azul/Cargo.toml +++ b/examples/native-azul/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "native-azul" version = "0.0.1" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] edition = "2018" [dependencies] diff --git a/examples/native-glutin/Cargo.toml b/examples/native-glutin/Cargo.toml index 3a84299..03ded84 100644 --- a/examples/native-glutin/Cargo.toml +++ b/examples/native-glutin/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "native-glutin" version = "0.0.1" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] edition = "2018" [dependencies] glutin = "0.19.0" gl = "0.11.0" -# wasm feature is default - exclude them for quicker compile -yage = { path = "../../", features = ["native", "gltf"], default-features = false } +yage = { path = "../../" } diff --git a/examples/native-glutin/src/main.rs b/examples/native-glutin/src/main.rs index 79f1d59..745a61b 100644 --- a/examples/native-glutin/src/main.rs +++ b/examples/native-glutin/src/main.rs @@ -1,16 +1,9 @@ -mod support; - use glutin::GlContext; -use yage::some_non_wasm_function; -use yage::gltf::load_gltf; +use yage::gl::GL; +use yage::gl::glenum; -// TODO!!: This is just the (slighly adapted) glutin window example and doesn't even use yage fn main() { - - dbg!(some_non_wasm_function()); - load_gltf("Box.glb"); - let mut events_loop = glutin::EventsLoop::new(); let window = glutin::WindowBuilder::new().with_title("A fantastic window!"); let context = glutin::ContextBuilder::new(); @@ -20,7 +13,10 @@ fn main() { println!("Pixel format of the window's GL context: {:?}", gl_window.get_pixel_format()); - support::load(&gl_window.context()); + gl::load_with(|ptr| gl_window.context().get_proc_address(ptr) as *const _); + + let gl = GL::new(); + gl.clear_color(0.0, 1.0, 0.0, 1.0); let mut running = true; while running { @@ -40,7 +36,7 @@ fn main() { } }); - support::draw_frame([1.0, 0.5, 0.7, 1.0]); + gl.clear(glenum::BufferBit::Color); let _ = gl_window.swap_buffers(); } } diff --git a/examples/native-glutin/src/support.rs b/examples/native-glutin/src/support.rs deleted file mode 100644 index e86608c..0000000 --- a/examples/native-glutin/src/support.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::ffi::CStr; -use std::mem; -use std::ptr; -use gl; -use glutin::{self, GlContext}; - -pub fn load(gl_context: &glutin::Context) { - gl::load_with(|ptr| gl_context.get_proc_address(ptr) as *const _); - - let version = unsafe { - let data = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _).to_bytes().to_vec(); - String::from_utf8(data).unwrap() - }; - - println!("OpenGL version {}", version); - - unsafe { - let vs = gl::CreateShader(gl::VERTEX_SHADER); - gl::ShaderSource(vs, 1, [VS_SRC.as_ptr() as *const _].as_ptr(), ptr::null()); - gl::CompileShader(vs); - - let fs = gl::CreateShader(gl::FRAGMENT_SHADER); - gl::ShaderSource(fs, 1, [FS_SRC.as_ptr() as *const _].as_ptr(), ptr::null()); - gl::CompileShader(fs); - - let program = gl::CreateProgram(); - gl::AttachShader(program, vs); - gl::AttachShader(program, fs); - gl::LinkProgram(program); - gl::UseProgram(program); - - let mut vb = mem::uninitialized(); - gl::GenBuffers(1, &mut vb); - gl::BindBuffer(gl::ARRAY_BUFFER, vb); - gl::BufferData(gl::ARRAY_BUFFER, - (VERTEX_DATA.len() * mem::size_of::()) as gl::types::GLsizeiptr, - VERTEX_DATA.as_ptr() as *const _, gl::STATIC_DRAW); - - // if gl::BindVertexArray.is_loaded() { - let mut vao = mem::uninitialized(); - gl::GenVertexArrays(1, &mut vao); - gl::BindVertexArray(vao); - // } - - let pos_attrib = gl::GetAttribLocation(program, b"position\0".as_ptr() as *const _); - let color_attrib = gl::GetAttribLocation(program, b"color\0".as_ptr() as *const _); - gl::VertexAttribPointer(pos_attrib as gl::types::GLuint, 2, gl::FLOAT, 0, - 5 * mem::size_of::() as gl::types::GLsizei, - ptr::null()); - gl::VertexAttribPointer(color_attrib as gl::types::GLuint, 3, gl::FLOAT, 0, - 5 * mem::size_of::() as gl::types::GLsizei, - (2 * mem::size_of::()) as *const () as *const _); - gl::EnableVertexAttribArray(pos_attrib as gl::types::GLuint); - gl::EnableVertexAttribArray(color_attrib as gl::types::GLuint); - } -} - -pub fn draw_frame(color: [f32; 4]) { - unsafe { - gl::ClearColor(color[0], color[1], color[2], color[3]); - gl::Clear(gl::COLOR_BUFFER_BIT); - gl::DrawArrays(gl::TRIANGLES, 0, 3); - } -} - -static VERTEX_DATA: [f32; 15] = [ - -0.5, -0.5, 1.0, 0.0, 0.0, - 0.0, 0.5, 0.0, 1.0, 0.0, - 0.5, -0.5, 0.0, 0.0, 1.0 -]; - -const VS_SRC: &[u8] = b" -#version 100 -precision mediump float; - -attribute vec2 position; -attribute vec3 color; - -varying vec3 v_color; - -void main() { - gl_Position = vec4(position, 0.0, 1.0); - v_color = color; -} -\0"; - -const FS_SRC: &[u8] = b" -#version 100 -precision mediump float; - -varying vec3 v_color; - -void main() { - gl_FragColor = vec4(v_color, 1.0); -} -\0"; diff --git a/examples/rust-webpack/crate/Cargo.toml b/examples/rust-webpack/crate/Cargo.toml index cdb4385..749ba1c 100644 --- a/examples/rust-webpack/crate/Cargo.toml +++ b/examples/rust-webpack/crate/Cargo.toml @@ -1,11 +1,12 @@ [package] -authors = ["The RustWasm Developers"] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] categories = ["wasm"] description = "My super awesome Rust, WebAssembly, and Webpack project!" license = "Apache-2.0/MIT" name = "rust-webpack" readme = "./README.md" repository = "https://github.com/bwasty/yage" +edition = "2018" version = "0.1.0" [lib] diff --git a/examples/rust-webpack/crate/src/lib.rs b/examples/rust-webpack/crate/src/lib.rs index 81b811b..5c487ac 100644 --- a/examples/rust-webpack/crate/src/lib.rs +++ b/examples/rust-webpack/crate/src/lib.rs @@ -4,6 +4,12 @@ extern crate web_sys; extern crate wasm_bindgen; use wasm_bindgen::prelude::*; +use wasm_bindgen::JsCast; + +use web_sys::WebGlRenderingContext; + +use yage::gl::GL; +use yage::gl::glenum; cfg_if! { // When the `console_error_panic_hook` feature is enabled, we can call the @@ -27,6 +33,25 @@ cfg_if! { } } +fn setup_canvas() -> Result<(), JsValue> { + // TODO!!: most of this setup should go into yage-web + let document = web_sys::window().unwrap().document().unwrap(); + let canvas = document.get_element_by_id("canvas").unwrap(); + let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::()?; + + // TODO!: make it WebGL2 + let context: WebGlRenderingContext = canvas + .get_context("webgl")? + .unwrap() + .dyn_into()?; + + let gl = GL::from_webgl_context(context); + gl.clear_color(0.0, 1.0, 0.0, 1.0); + gl.clear(glenum::BufferBit::Color); + + Ok(()) +} + // Called by our JS entry point to run the example. #[wasm_bindgen] pub fn run() -> Result<(), JsValue> { @@ -42,6 +67,7 @@ pub fn run() -> Result<(), JsValue> { let body: &web_sys::Node = body.as_ref(); body.append_child(&p)?; - let _ = yage::start(); + setup_canvas(); + Ok(()) } diff --git a/examples/wasm-app/README.md b/examples/wasm-app/README.md index 42f4365..6c57538 100644 --- a/examples/wasm-app/README.md +++ b/examples/wasm-app/README.md @@ -1,3 +1,6 @@ +# THIS EXAMPLE DOES NOT WORK AT THE MOMENT +Will be unmaintained until more of yage works/is implemented cleanly. + # `wasm-app` Minimal example bootstrapped with [create-wasm-app](https://github.com/rustwasm/create-wasm-app). diff --git a/src/lib.rs b/src/lib.rs index 1898abe..c829ff9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,9 @@ pub extern crate yage_core as core; pub extern crate yage_gl as gl; -pub extern crate yage_app as app; +#[cfg(not(target_arch = "wasm32"))] +pub extern crate yage_glutin; +#[cfg(target_arch = "wasm32")] +pub extern crate yage_web as web; #[cfg(feature = "gltf")] pub extern crate yage_gltf as gltf; @@ -8,16 +11,6 @@ mod utils; use cfg_if::cfg_if; -#[cfg(feature = "wasm")] -use wasm_bindgen::prelude::*; -#[cfg(feature = "wasm")] -use wasm_bindgen::JsCast; - -#[cfg(feature = "wasm")] -use js_sys::WebAssembly; -#[cfg(feature = "wasm")] -use web_sys::{WebGlProgram, WebGlRenderingContext, WebGlShader}; - cfg_if! { // When the `wee_alloc` feature is enabled, use `wee_alloc` as the global // allocator. @@ -27,122 +20,3 @@ cfg_if! { static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; } } - -pub fn some_non_wasm_function() -> u32 { - 42 -} - -#[cfg(feature = "wasm")] -#[wasm_bindgen] -pub fn start() -> Result<(), JsValue> { - let document = web_sys::window().unwrap().document().unwrap(); - let canvas = document.get_element_by_id("canvas").unwrap(); - let canvas: web_sys::HtmlCanvasElement = canvas.dyn_into::()?; - - // TODO!!: make it WebGL2 - let context = canvas - .get_context("webgl")? - .unwrap() - .dyn_into::()?; - - let vert_shader = compile_shader( - &context, - WebGlRenderingContext::VERTEX_SHADER, - r#" - attribute vec4 position; - void main() { - gl_Position = position; - } - "#, - )?; - let frag_shader = compile_shader( - &context, - WebGlRenderingContext::FRAGMENT_SHADER, - r#" - void main() { - gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); - } - "#, - )?; - let program = link_program(&context, [vert_shader, frag_shader].iter())?; - context.use_program(Some(&program)); - - let vertices: [f32; 9] = [-0.7, -0.7, 0.0, 0.7, -0.7, 0.0, 0.0, 0.7, 0.0]; - let memory_buffer = wasm_bindgen::memory() - .dyn_into::()? - .buffer(); - let vertices_location = vertices.as_ptr() as u32 / 4; - let vert_array = js_sys::Float32Array::new(&memory_buffer) - .subarray(vertices_location, vertices_location + vertices.len() as u32); - - let buffer = context.create_buffer().ok_or("failed to create buffer")?; - context.bind_buffer(WebGlRenderingContext::ARRAY_BUFFER, Some(&buffer)); - context.buffer_data_with_array_buffer_view( - WebGlRenderingContext::ARRAY_BUFFER, - &vert_array, - WebGlRenderingContext::STATIC_DRAW, - ); - context.vertex_attrib_pointer_with_i32(0, 3, WebGlRenderingContext::FLOAT, false, 0, 0); - context.enable_vertex_attrib_array(0); - - context.clear_color(0.0, 0.0, 0.0, 1.0); - context.clear(WebGlRenderingContext::COLOR_BUFFER_BIT); - - context.draw_arrays( - WebGlRenderingContext::TRIANGLES, - 0, - (vertices.len() / 3) as i32, - ); - Ok(()) -} - -#[cfg(feature = "wasm")] -pub fn compile_shader( - context: &WebGlRenderingContext, - shader_type: u32, - source: &str, -) -> Result { - let shader = context - .create_shader(shader_type) - .ok_or_else(|| String::from("Unable to create shader object"))?; - context.shader_source(&shader, source); - context.compile_shader(&shader); - - if context - .get_shader_parameter(&shader, WebGlRenderingContext::COMPILE_STATUS) - .as_bool() - .unwrap_or(false) - { - Ok(shader) - } else { - Err(context - .get_shader_info_log(&shader) - .unwrap_or_else(|| "Unknown error creating shader".into())) - } -} - -#[cfg(feature = "wasm")] -pub fn link_program<'a, T: IntoIterator>( - context: &WebGlRenderingContext, - shaders: T, -) -> Result { - let program = context - .create_program() - .ok_or_else(|| String::from("Unable to create shader object"))?; - for shader in shaders { - context.attach_shader(&program, shader) - } - context.link_program(&program); - - if context - .get_program_parameter(&program, WebGlRenderingContext::LINK_STATUS) - .as_bool() - .unwrap_or(false) - { - Ok(program) - } else { - Err(context - .get_program_info_log(&program) - .unwrap_or_else(|| "Unknown error creating program object".into())) - } -} diff --git a/yage-app/Cargo.toml b/yage-app/Cargo.toml deleted file mode 100644 index badf931..0000000 --- a/yage-app/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "yage-app" -version = "0.0.1" -authors = ["Benjamin Wasty "] -edition = "2018" - -[dependencies] - -[target.'cfg(not(target_arch = "wasm32"))'.dependencies] -glutin = "0.19.0" diff --git a/yage-app/README.md b/yage-app/README.md deleted file mode 100644 index 80de75c..0000000 --- a/yage-app/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This crate should abstract over native window and event handling (glutin) and WebGL canvases in the browser. Potential inspiration: https://github.com/unrust/uni-app - -TODO: better name? diff --git a/yage-core/Cargo.toml b/yage-core/Cargo.toml index d1868b1..6132066 100644 --- a/yage-core/Cargo.toml +++ b/yage-core/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "yage-core" version = "0.0.1" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] edition = "2018" [dependencies] diff --git a/yage-gl/Cargo.toml b/yage-gl/Cargo.toml index 6353805..b973795 100644 --- a/yage-gl/Cargo.toml +++ b/yage-gl/Cargo.toml @@ -1,7 +1,30 @@ [package] name = "yage-gl" version = "0.0.1" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] edition = "2018" [dependencies] +glenum = "0.1.1" +[dependencies.web-sys] +version = "0.3.14" +# TODO!: remove unneeded... +features = [ + 'Document', + 'Element', + 'HtmlCanvasElement', + 'WebGlBuffer', + 'WebGlRenderingContext', + 'WebGlProgram', + 'WebGlShader', + 'Window', + 'console' +] + +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +gl = "0.11.0" + +[target.wasm32-unknown-unknown.dependencies] +js-sys = "0.3.14" +wasm-bindgen = "0.2.37" + diff --git a/yage-gl/src/gl_native.rs b/yage-gl/src/gl_native.rs new file mode 100644 index 0000000..8efe616 --- /dev/null +++ b/yage-gl/src/gl_native.rs @@ -0,0 +1,26 @@ +use glenum::*; + +#[derive(Default)] +pub struct GL { +} + +impl GL { + pub fn new() -> GL { + GL { + } + } + + /// specify clear values for the color buffers + pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) { + unsafe { + gl::ClearColor(r, g, b, a); + } + } + + /// clear buffers to preset values + pub fn clear(&self, bit: BufferBit) { + unsafe { + gl::Clear(bit as _); + } + } +} diff --git a/yage-gl/src/gl_web.rs b/yage-gl/src/gl_web.rs new file mode 100644 index 0000000..9f9e674 --- /dev/null +++ b/yage-gl/src/gl_web.rs @@ -0,0 +1,25 @@ +use glenum::*; + +use web_sys::WebGlRenderingContext; + +pub struct GL { + context: WebGlRenderingContext, +} + +impl GL { + pub fn from_webgl_context(context: WebGlRenderingContext) -> GL { + GL { + context + } + } + + /// specify clear values for the color buffers + pub fn clear_color(&self, r: f32, g: f32, b: f32, a: f32) { + self.context.clear_color(r, g, b, a); + } + + /// clear buffers to preset values + pub fn clear(&self, bit: BufferBit) { + self.context.clear(bit as _); + } +} diff --git a/yage-gl/src/lib.rs b/yage-gl/src/lib.rs index e69de29..67bbd13 100644 --- a/yage-gl/src/lib.rs +++ b/yage-gl/src/lib.rs @@ -0,0 +1,10 @@ +#[cfg(not(target_arch = "wasm32"))] +#[path = "gl_native.rs"] +mod gl; + +#[cfg(target_arch = "wasm32")] +#[path = "gl_web.rs"] +pub mod gl; + +pub use crate::gl::*; +pub use glenum; diff --git a/yage-gltf/Cargo.toml b/yage-gltf/Cargo.toml index 8a4e21a..5beed24 100644 --- a/yage-gltf/Cargo.toml +++ b/yage-gltf/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "yage-gltf" version = "0.0.1" -authors = ["Benjamin Wasty "] +authors = ["Benjamin Wasty ", "Stefan Buschmann "] edition = "2018" [dependencies] diff --git a/yage-glutin/Cargo.toml b/yage-glutin/Cargo.toml new file mode 100644 index 0000000..9c5add4 --- /dev/null +++ b/yage-glutin/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "yage-glutin" +version = "0.0.1" +authors = ["Benjamin Wasty ", "Stefan Buschmann "] +edition = "2018" + +[dependencies] +glutin = "0.19.0" diff --git a/yage-glutin/README.md b/yage-glutin/README.md new file mode 100644 index 0000000..90c8ccc --- /dev/null +++ b/yage-glutin/README.md @@ -0,0 +1 @@ +This crate should handle window, context, events loop (most of what is now in `examples/native-glutin/main.rs`) diff --git a/yage-app/src/lib.rs b/yage-glutin/src/lib.rs similarity index 100% rename from yage-app/src/lib.rs rename to yage-glutin/src/lib.rs diff --git a/yage-web/Cargo.toml b/yage-web/Cargo.toml new file mode 100644 index 0000000..92255de --- /dev/null +++ b/yage-web/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "yage-web" +version = "0.0.1" +authors = ["Benjamin Wasty ", "Stefan Buschmann "] +edition = "2018" + +[dependencies] diff --git a/yage-web/README.md b/yage-web/README.md new file mode 100644 index 0000000..e1fd4ff --- /dev/null +++ b/yage-web/README.md @@ -0,0 +1 @@ +This crate should handle the WebGL context and be the web counterpart of yage-glutin. diff --git a/yage-web/src/lib.rs b/yage-web/src/lib.rs new file mode 100644 index 0000000..e69de29