diff --git a/oden-js/src/conversion/from.rs b/oden-js/src/conversion/from.rs index d53f270c..d7a6acb4 100644 --- a/oden-js/src/conversion/from.rs +++ b/oden-js/src/conversion/from.rs @@ -104,14 +104,3 @@ impl TryFromValue for Value { Ok(value.dup(ctx)) } } - -impl TryFromValue for Option { - #[inline] - fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result { - if value.is_undefined() { - Ok(None) - } else { - Ok(Some(T::try_from_value(value, ctx)?)) - } - } -} diff --git a/oden-js/src/conversion/function.rs b/oden-js/src/conversion/function.rs index cd3e9878..8f5148d2 100644 --- a/oden-js/src/conversion/function.rs +++ b/oden-js/src/conversion/function.rs @@ -48,11 +48,11 @@ where } } -impl RustFunction> for FN +impl RustFunction> for F where R: IntoRustFunctionResult, A: TryFromValue, - FN: Fn(&ContextRef, A) -> R + Sized, + F: Fn(&ContextRef, A) -> R + Sized, { fn argument_count() -> usize { 1 @@ -72,12 +72,12 @@ where } } -impl RustFunction> for FN +impl RustFunction> for F where R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, - FN: Fn(&ContextRef, A, B) -> R + Sized, + F: Fn(&ContextRef, A, B) -> R + Sized, { fn argument_count() -> usize { 2 @@ -98,13 +98,13 @@ where } } -impl RustFunction> for FN +impl RustFunction> for F where R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, C: TryFromValue, - FN: Fn(&ContextRef, A, B, C) -> R + Sized, + F: Fn(&ContextRef, A, B, C) -> R + Sized, { fn argument_count() -> usize { 3 @@ -126,14 +126,14 @@ where } } -impl RustFunction> for FN +impl RustFunction> for F where R: IntoRustFunctionResult, A: TryFromValue, B: TryFromValue, C: TryFromValue, D: TryFromValue, - FN: Fn(&ContextRef, A, B, C, D) -> R + Sized, + F: Fn(&ContextRef, A, B, C, D) -> R + Sized, { fn argument_count() -> usize { 4 @@ -156,7 +156,7 @@ where } } -impl RustFunction> for FN +impl RustFunction> for F where R: IntoRustFunctionResult, A: TryFromValue, @@ -164,7 +164,7 @@ where C: TryFromValue, D: TryFromValue, E: TryFromValue, - FN: Fn(&ContextRef, A, B, C, D, E) -> R + Sized, + F: Fn(&ContextRef, A, B, C, D, E) -> R + Sized, { fn argument_count() -> usize { 5 @@ -187,113 +187,3 @@ where res.into_res(context) } } - -impl RustFunction> for FN -where - R: IntoRustFunctionResult, - A: TryFromValue, - B: TryFromValue, - C: TryFromValue, - D: TryFromValue, - E: TryFromValue, - F: TryFromValue, - FN: Fn(&ContextRef, A, B, C, D, E, F) -> R + Sized, -{ - fn argument_count() -> usize { - 6 - } - - fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { - if args.len() != Self::argument_count() { - return Err(Error::ArgumentCountMismatch { - expected: Self::argument_count(), - received: args.len(), - }); - } - - let va = A::try_from_value(args[0], &context)?; - let vb = B::try_from_value(args[1], &context)?; - let vc = C::try_from_value(args[2], &context)?; - let vd = D::try_from_value(args[3], &context)?; - let ve = E::try_from_value(args[4], &context)?; - let vf = F::try_from_value(args[4], &context)?; - let res = self(context, va, vb, vc, vd, ve, vf); - res.into_res(context) - } -} - -impl RustFunction> - for FN -where - R: IntoRustFunctionResult, - A: TryFromValue, - B: TryFromValue, - C: TryFromValue, - D: TryFromValue, - E: TryFromValue, - F: TryFromValue, - G: TryFromValue, - FN: Fn(&ContextRef, A, B, C, D, E, F, G) -> R + Sized, -{ - fn argument_count() -> usize { - 7 - } - - fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { - if args.len() != Self::argument_count() { - return Err(Error::ArgumentCountMismatch { - expected: Self::argument_count(), - received: args.len(), - }); - } - - let va = A::try_from_value(args[0], &context)?; - let vb = B::try_from_value(args[1], &context)?; - let vc = C::try_from_value(args[2], &context)?; - let vd = D::try_from_value(args[3], &context)?; - let ve = E::try_from_value(args[4], &context)?; - let vf = F::try_from_value(args[4], &context)?; - let vg = G::try_from_value(args[4], &context)?; - let res = self(context, va, vb, vc, vd, ve, vf, vg); - res.into_res(context) - } -} - -impl - RustFunction> for FN -where - R: IntoRustFunctionResult, - A: TryFromValue, - B: TryFromValue, - C: TryFromValue, - D: TryFromValue, - E: TryFromValue, - F: TryFromValue, - G: TryFromValue, - H: TryFromValue, - FN: Fn(&ContextRef, A, B, C, D, E, F, G, H) -> R + Sized, -{ - fn argument_count() -> usize { - 8 - } - - fn call(&self, context: &ContextRef, args: &[&ValueRef]) -> ValueResult { - if args.len() != Self::argument_count() { - return Err(Error::ArgumentCountMismatch { - expected: Self::argument_count(), - received: args.len(), - }); - } - - let va = A::try_from_value(args[0], &context)?; - let vb = B::try_from_value(args[1], &context)?; - let vc = C::try_from_value(args[2], &context)?; - let vd = D::try_from_value(args[3], &context)?; - let ve = E::try_from_value(args[4], &context)?; - let vf = F::try_from_value(args[4], &context)?; - let vg = G::try_from_value(args[4], &context)?; - let vh = H::try_from_value(args[4], &context)?; - let res = self(context, va, vb, vc, vd, ve, vf, vg, vh); - res.into_res(context) - } -} diff --git a/oden-js/src/conversion/into.rs b/oden-js/src/conversion/into.rs index 3dd5915f..dbb5cf81 100644 --- a/oden-js/src/conversion/into.rs +++ b/oden-js/src/conversion/into.rs @@ -128,13 +128,3 @@ impl TryIntoValue for T { self.into_value(ctx) } } - -impl TryIntoValue for Option { - #[inline] - fn try_into_value(self, ctx: &ContextRef) -> ValueResult { - match self { - None => Ok(ctx.undefined()), - Some(v) => v.try_into_value(ctx), - } - } -} diff --git a/src/lib.rs b/src/lib.rs index 42d6346e..a21e5470 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ use bytemuck; +use wgpu::util::DeviceExt; use winit::{ event::*, event_loop::{ControlFlow, EventLoop}, @@ -7,13 +8,13 @@ use winit::{ }; mod script; -use script::graphics::GraphicsCommand; +use script::graphics::{ClearCommand, GraphicsCommand, PrintCommand}; mod texture; #[repr(C)] #[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] struct Vertex { - position: [f32; 3], // TODO: Why do I pass in a Z here? + position: [f32; 3], tex_coords: [f32; 2], } @@ -73,7 +74,8 @@ struct State { render_pipeline: wgpu::RenderPipeline, vertex_buffer: wgpu::Buffer, - max_vertices: usize, + index_buffer: wgpu::Buffer, + num_indices: u32, // Indices in index_buffer diffuse_bind_group: wgpu::BindGroup, @@ -246,15 +248,17 @@ impl State { multiview: None, }); - let max_vertices: usize = 4096; - let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor { + let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { label: Some("Vertex Buffer"), - size: (max_vertices * std::mem::size_of::()) - .try_into() - .unwrap(), - mapped_at_creation: false, - usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + contents: bytemuck::cast_slice(VERTICES), + usage: wgpu::BufferUsages::VERTEX, }); + let index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Index Buffer"), + contents: bytemuck::cast_slice(INDICES), + usage: wgpu::BufferUsages::INDEX, + }); + let num_indices = INDICES.len() as u32; Self { window, @@ -265,7 +269,8 @@ impl State { size, render_pipeline, vertex_buffer, - max_vertices, + index_buffer, + num_indices, diffuse_bind_group, mouse_x: 0.0, @@ -297,6 +302,11 @@ impl State { let view = output .texture .create_view(&wgpu::TextureViewDescriptor::default()); + let mut encoder = self + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor { + label: Some("Render Encoder"), + }); // Group the commands into passes. struct Pass { @@ -306,8 +316,8 @@ impl State { let mut passes = Vec::new(); for command in commands { match command { - GraphicsCommand::Clear(cc) => passes.push(Pass { - color: Some(cc.color), + GraphicsCommand::Clear(ClearCommand { color }) => passes.push(Pass { + color: Some(color), commands: Vec::new(), }), GraphicsCommand::EndFrame => (), @@ -321,91 +331,39 @@ impl State { } } - let mut vertices = Vec::new(); for pass in passes { - // TODO: It would be great if we could use multiple passes in a - // single encoder but right now because of the dyanmic - // nature of vertices we can't, I think? Because - // queue.write_buffer doesn't actually happen until we call - // submit... - let mut encoder = self - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor { - label: Some("Render Encoder"), - }); - - { - let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Render Pass"), - color_attachments: &[Some(wgpu::RenderPassColorAttachment { - view: &view, - resolve_target: None, - ops: wgpu::Operations { - load: if let Some([r, g, b, a]) = pass.color { - wgpu::LoadOp::Clear(wgpu::Color { - r, //0.1, - g, //0.2, - b, - a, - }) - } else { - wgpu::LoadOp::Load - }, - store: true, + let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Render Pass"), + color_attachments: &[Some(wgpu::RenderPassColorAttachment { + view: &view, + resolve_target: None, + ops: wgpu::Operations { + load: if let Some([r, g, b, a]) = pass.color { + wgpu::LoadOp::Clear(wgpu::Color { + r, //0.1, + g, //0.2, + b, + a, + }) + } else { + wgpu::LoadOp::Load }, - })], - depth_stencil_attachment: None, - }); + store: true, + }, + })], + depth_stencil_attachment: None, + }); - vertices.clear(); - for command in pass.commands { - match command { - GraphicsCommand::Print(pc) => { - println!("{}", pc.text); - } - GraphicsCommand::Sprite(sc) => { - vertices.push(Vertex { - position: [sc.x, sc.y, 0.0], - tex_coords: [sc.u, sc.v], - }); - vertices.push(Vertex { - position: [sc.x + sc.w, sc.y, 0.0], - tex_coords: [sc.u + sc.sw, sc.v], - }); - vertices.push(Vertex { - position: [sc.x, sc.y + sc.h, 0.0], - tex_coords: [sc.u, sc.v], - }); - vertices.push(Vertex { - position: [sc.x, sc.y + sc.h, 0.0], - tex_coords: [sc.u, sc.v], - }); - vertices.push(Vertex { - position: [sc.x + sc.w, sc.y, 0.0], - tex_coords: [sc.u, sc.v], - }); - vertices.push(Vertex { - position: [sc.x + sc.w, sc.y + sc.h, 0.0], - tex_coords: [sc.u, sc.v], - }); - } - - GraphicsCommand::Clear(_) => (), // Already handled - GraphicsCommand::EndFrame => (), // Should never appear + for command in pass.commands { + match command { + GraphicsCommand::Print(PrintCommand { text }) => { + println!("{}", text); } + + GraphicsCommand::Clear(_) => (), // Already handled + GraphicsCommand::EndFrame => (), // Should never appear } - - assert!(vertices.len() < self.max_vertices); // ! - self.queue - .write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&vertices)); - render_pass.set_pipeline(&self.render_pipeline); - render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]); - render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); - render_pass.draw(0..(vertices.len() as u32), 0..1); } - - // Submit will accept anything that implements IntoIter - self.queue.submit(std::iter::once(encoder.finish())); } // { @@ -439,6 +397,8 @@ impl State { // render_pass.draw_indexed(0..self.num_indices, 0, 0..1); // } + // Submit will accept anything that implements IntoIter + self.queue.submit(std::iter::once(encoder.finish())); output.present(); Ok(()) diff --git a/src/main.js b/src/main.js index 8b21b959..7bc0a8ba 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,4 @@ -import { cls, print, spr } from "graphics"; +import { cls, print } from "graphics"; export function init() { print("Hello world!"); @@ -8,5 +8,4 @@ export function update() {} export function draw() { cls(0.1, 0.2, 0.3); - spr(0, 0, 0.5, 0.5, 0, 0, 0.5, 0.5); } diff --git a/src/script/graphics.rs b/src/script/graphics.rs index 4ad1560a..ee3e9f69 100644 --- a/src/script/graphics.rs +++ b/src/script/graphics.rs @@ -1,4 +1,4 @@ -use oden_js::{module, ContextRef, Value, ValueRef, ValueResult}; +use oden_js::{module, ContextRef, Error, Value, ValueRef, ValueResult}; use std::sync::mpsc::Sender; use std::sync::Arc; @@ -10,21 +10,9 @@ pub struct ClearCommand { pub color: [f64; 4], } -pub struct SpriteCommand { - pub x: f32, - pub y: f32, - pub w: f32, - pub h: f32, - pub u: f32, - pub v: f32, - pub sw: f32, - pub sh: f32, -} - pub enum GraphicsCommand { Clear(ClearCommand), Print(PrintCommand), - Sprite(SpriteCommand), EndFrame, } @@ -51,37 +39,22 @@ impl GraphicsImpl { Ok(Value::undefined(ctx)) } - fn cls_fn(&self, ctx: &ContextRef, r: f64, g: f64, b: f64) -> ValueResult { + fn cls_fn(&self, ctx: &ContextRef, args: &[&ValueRef]) -> ValueResult { + if args.len() != 3 { + return Err(Error::ArgumentCountMismatch { + expected: 3, + received: args.len(), + }); + } + let r = args[0].to_float64(&ctx)?; + let g = args[1].to_float64(&ctx)?; + let b = args[1].to_float64(&ctx)?; + let _ = self.sender.send(GraphicsCommand::Clear(ClearCommand { color: [r, g, b, 1.0], })); Ok(Value::undefined(ctx)) } - - fn spr_fn( - &self, - ctx: &ContextRef, - x: f32, - y: f32, - w: f32, - h: f32, - u: f32, - v: f32, - sw: Option, - sh: Option, - ) -> ValueResult { - let _ = self.sender.send(GraphicsCommand::Sprite(SpriteCommand { - x, - y, - w, - h, - u, - v, - sw: sw.unwrap_or(w), - sh: sh.unwrap_or(h), - })); - Ok(Value::undefined(ctx)) - } } pub struct GraphicsAPI { @@ -91,43 +64,18 @@ pub struct GraphicsAPI { impl GraphicsAPI { pub fn define(ctx: &ContextRef, sender: Sender) -> oden_js::Result { let gfx = Arc::new(GraphicsImpl::new(sender)); - let mut builder = module::NativeModuleBuilder::new(ctx); - { - let gfx = gfx.clone(); - builder.export( + let gfx_a = gfx.clone(); + let gfx_b = gfx.clone(); + module::NativeModuleBuilder::new(ctx) + .export( "print", - ctx.new_dynamic_fn(move |ctx, _, args| gfx.print_fn(ctx, args))?, - )?; - } - { - let gfx = gfx.clone(); - builder.export( + ctx.new_dynamic_fn(move |ctx, _, args| gfx_a.print_fn(ctx, args))?, + )? + .export( "cls", - ctx.new_fn(move |ctx: &ContextRef, r: f64, g: f64, b: f64| { - gfx.cls_fn(ctx, r, g, b) - })?, - )?; - } - { - let gfx = gfx.clone(); - builder.export( - "spr", - ctx.new_fn( - move |ctx: &ContextRef, - x: f32, - y: f32, - w: f32, - h: f32, - u: f32, - v: f32, - sw: Option, - sh: Option| { - gfx.spr_fn(ctx, x, y, w, h, u, v, sw, sh) - }, - )?, - )?; - } - builder.build("graphics")?; + ctx.new_dynamic_fn(move |ctx, _, args| gfx_b.cls_fn(ctx, args))?, + )? + .build("graphics")?; Ok(GraphicsAPI { gfx }) }