diff --git a/oden-js/Cargo.lock b/oden-js/Cargo.lock index ad7d556c..00f5674c 100644 --- a/oden-js/Cargo.lock +++ b/oden-js/Cargo.lock @@ -8,12 +8,6 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - [[package]] name = "bindgen" version = "0.63.0" @@ -147,7 +141,6 @@ name = "oden-js" version = "0.1.0" dependencies = [ "anyhow", - "assert_matches", "bitflags", "oden-js-sys", "thiserror", diff --git a/oden-js/Cargo.toml b/oden-js/Cargo.toml index c9dcd5c5..cf4bb98a 100644 --- a/oden-js/Cargo.toml +++ b/oden-js/Cargo.toml @@ -9,7 +9,4 @@ edition = "2021" anyhow = "1" bitflags = "1" thiserror = "1" -oden-js-sys = {path = "../oden-js-sys"} - -[dev-dependencies] -assert_matches = "1.5.0" +oden-js-sys = {path = "../oden-js-sys"} \ No newline at end of file diff --git a/oden-js/src/context.rs b/oden-js/src/context.rs index 22f75654..300a5915 100644 --- a/oden-js/src/context.rs +++ b/oden-js/src/context.rs @@ -151,7 +151,7 @@ impl ContextRef { pub fn import_module(&self, name: &str, base: &str) -> Result { let name = CString::new(name)?; let base = CString::new(base)?; - let module = unsafe { sys::JS_RunModule(self.ctx, base.as_ptr(), name.as_ptr()) }; + let module = unsafe { sys::JS_RunModule(self.ctx, name.as_ptr(), base.as_ptr()) }; if module.is_null() { return Err(self.exception_error()); } diff --git a/oden-js/src/conversion/function.rs b/oden-js/src/conversion/function.rs index 98123db5..cd3e9878 100644 --- a/oden-js/src/conversion/function.rs +++ b/oden-js/src/conversion/function.rs @@ -216,7 +216,7 @@ where 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[5], &context)?; + let vf = F::try_from_value(args[4], &context)?; let res = self(context, va, vb, vc, vd, ve, vf); res.into_res(context) } @@ -252,8 +252,8 @@ where 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[5], &context)?; - let vg = G::try_from_value(args[6], &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) } @@ -290,290 +290,10 @@ where 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[5], &context)?; - let vg = G::try_from_value(args[6], &context)?; - let vh = H::try_from_value(args[7], &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) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::{Context, Error, EvalFlags, Result, Runtime}; - use assert_matches::assert_matches; - - #[test] - fn no_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn(|_: &ContextRef| -> Result { Ok(0.0) }) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function()", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("0"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn one_argument() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn(|_: &ContextRef, a: f32| -> Result { Ok(a) }) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("1"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function()", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn two_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn(|_: &ContextRef, a: f32, b: f32| -> Result { Ok(a + b) }) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("3"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn three_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn(|_: &ContextRef, a: f32, b: f32, c: f32| -> Result { Ok(a + b + c) }) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("6"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn four_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn( - |_: &ContextRef, a: f32, b: f32, c: f32, d: f32| -> Result { - Ok(a + b + c + d) - }, - ) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3,4)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("10"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2,3)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4,5)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn five_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn( - |_: &ContextRef, a: f32, b: f32, c: f32, d: f32, e: f32| -> Result { - Ok(a + b + c + d + e) - }, - ) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3,4,5)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("15"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2,3,4)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4,5,6)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn six_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn( - |_: &ContextRef, a: f32, b: f32, c: f32, d: f32, e: f32, f: f32| -> Result { - Ok(a + b + c + d + e + f) - }, - ) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3,4,5,6)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("21"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2,3,4,5)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4,5,6,7)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn seven_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn( - |_: &ContextRef, - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, - g: f32| - -> Result { Ok(a + b + c + d + e + f + g) }, - ) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3,4,5,6,7)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("28"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2,3,4,5,6)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4,5,6,7,8)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } - - #[test] - fn eight_arguments() { - let rt = Runtime::new(); - let ctx = Context::new(rt); - - let the_function = ctx - .new_fn( - |_: &ContextRef, - a: f32, - b: f32, - c: f32, - d: f32, - e: f32, - f: f32, - g: f32, - h: f32| - -> Result { Ok(a + b + c + d + e + f + g + h) }, - ) - .unwrap(); - - ctx.global_object() - .unwrap() - .set_property(&ctx, "the_function", &the_function) - .expect("Should be able to set the function"); - - let val = ctx - .eval("the_function(1,2,3,4,5,6,7,8)", "script", EvalFlags::NONE) - .unwrap(); - - assert_eq!(String::from("36"), val.to_string(&ctx).unwrap()); - - let val = ctx.eval("the_function(1,2,3,4,5,6,7)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - - let val = ctx.eval("the_function(1,2,3,4,5,6,7,8,9)", "script", EvalFlags::NONE); - assert_matches!(val, Err(Error::Exception(..))); - } -} diff --git a/src/graphics.ts b/src/graphics.ts index 9758d38a..944f99c3 100644 --- a/src/graphics.ts +++ b/src/graphics.ts @@ -1,17 +1,13 @@ import * as core from "graphics-core"; -// Clear the screen to the specified color. r, g, and b should vary from 0 to -// 1. export function cls(r: number, g: number, b: number) { core.cls(r, g, b); } -// Print a message to the console. -export function print(...args: unknown[]) { +export function print(...args: string[]) { core.print(args.join(" ")); } -// Draw a sprite in the rectangle from x,y to export function spr( x: number, y: number, @@ -22,7 +18,7 @@ export function spr( sw: number | undefined = undefined, sh: number | undefined = undefined ) { - sw = sw || 1.0; - sh = sh || 1.0; + sw = sw || w; + sh = sh || h; core.spr(x, y, w, h, sx, sy, sw, sh); } diff --git a/src/lib.rs b/src/lib.rs index e432dfef..6bcceb99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ use bytemuck; -use wgpu::util::DeviceExt; use winit::{ event::*, event_loop::{ControlFlow, EventLoop}, @@ -39,20 +38,6 @@ impl Vertex { } } -#[repr(C)] -#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)] -struct ScreenUniforms { - resolution: [f32; 2], -} - -impl ScreenUniforms { - fn new(width: u32, height: u32) -> ScreenUniforms { - ScreenUniforms { - resolution: [width as f32, height as f32], - } - } -} - struct State { surface: wgpu::Surface, device: wgpu::Device, @@ -67,10 +52,6 @@ struct State { diffuse_bind_group: wgpu::BindGroup, - screen_uniform: ScreenUniforms, - screen_uniform_buffer: wgpu::Buffer, - screen_uniform_bind_group: wgpu::BindGroup, - // Garbage mouse_x: f64, mouse_y: f64, @@ -190,37 +171,6 @@ impl State { label: Some("diffuse_bind_group"), }); - let screen_uniform = ScreenUniforms::new(size.width, size.height); - let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor { - label: Some("Screen Uniform Buffer"), - contents: bytemuck::cast_slice(&[screen_uniform]), - usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST, - }); - - let screen_uniform_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStages::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, - min_binding_size: None, - }, - count: None, - }], - label: Some("screen_bind_group_layout"), - }); - - let screen_uniform_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &screen_uniform_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: screen_uniform_buffer.as_entire_binding(), - }], - label: Some("camera_bind_group"), - }); - let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor { label: Some("Shader"), source: wgpu::ShaderSource::Wgsl(include_str!("shader.wgsl").into()), @@ -229,10 +179,7 @@ impl State { let render_pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { label: Some("Render Pipeline Layout"), - bind_group_layouts: &[ - &texture_bind_group_layout, - &screen_uniform_bind_group_layout, - ], + bind_group_layouts: &[&texture_bind_group_layout], push_constant_ranges: &[], }); @@ -295,9 +242,6 @@ impl State { vertex_buffer, max_vertices, diffuse_bind_group, - screen_uniform, - screen_uniform_buffer, - screen_uniform_bind_group, mouse_x: 0.0, mouse_y: 0.0, @@ -321,14 +265,7 @@ impl State { false } - fn update(&mut self) { - self.screen_uniform = ScreenUniforms::new(self.size.width, self.size.height); - self.queue.write_buffer( - &self.screen_uniform_buffer, - 0, - bytemuck::cast_slice(&[self.screen_uniform]), - ); - } + fn update(&mut self) {} fn render(&mut self, commands: Vec) -> Result<(), wgpu::SurfaceError> { let output = self.surface.get_current_texture()?; @@ -412,19 +349,19 @@ impl State { }); vertices.push(Vertex { position: [sc.x, sc.y + sc.h, 0.0], - tex_coords: [sc.u, sc.v + sc.sh], + tex_coords: [sc.u, sc.v], }); vertices.push(Vertex { position: [sc.x, sc.y + sc.h, 0.0], - tex_coords: [sc.u, sc.v + sc.sh], + 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], + 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.sw, sc.v + sc.sh], + tex_coords: [sc.u, sc.v], }); } @@ -438,7 +375,6 @@ impl State { .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_bind_group(1, &self.screen_uniform_bind_group, &[]); render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); render_pass.draw(0..(vertices.len() as u32), 0..1); } diff --git a/src/main.ts b/src/main.js similarity index 61% rename from src/main.ts rename to src/main.js index 0a372f56..fd8099f1 100644 --- a/src/main.ts +++ b/src/main.js @@ -1,4 +1,4 @@ -import { cls, print, spr } from "./graphics.ts"; +import { cls, print, spr } from "./src/graphics.ts"; export function init() { print("Hello world!"); @@ -8,5 +8,5 @@ export function update() {} export function draw() { cls(0.1, 0.2, 0.3); - spr(0, 0, 320, 240, 0, 0); + spr(0, 0, 0.5, 0.5, 0, 0); } diff --git a/src/script.rs b/src/script.rs index 67bdc032..80e4cb5a 100644 --- a/src/script.rs +++ b/src/script.rs @@ -1,16 +1,166 @@ use oden_js::{ module::loader::{ModuleLoader, ModuleSource}, - Context, ContextRef, Result, Runtime, Value, + Context, ContextRef, Error, Result, Runtime, Value, }; +use std::cell::RefCell; use std::ffi::OsStr; use std::path::Path; +use std::rc::Rc; use std::sync::mpsc::{channel, Receiver}; +use swc_common::{ + self, comments::SingleThreadedComments, errors::Diagnostic, sync::Lrc, FileName, Globals, Mark, + SourceMap, GLOBALS, +}; +use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; +use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax}; +use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver}; +use swc_ecma_transforms_typescript::strip; +use swc_ecma_visit::FoldWith; + pub mod graphics; use graphics::GraphicsCommand; -mod typescript; -use typescript::transpile_to_javascript; +struct DiagnosticCollector { + cell: Rc>>, +} + +impl DiagnosticCollector { + pub fn into_handler(self) -> swc_common::errors::Handler { + swc_common::errors::Handler::with_emitter(true, false, Box::new(self)) + } +} + +impl swc_common::errors::Emitter for DiagnosticCollector { + fn emit(&mut self, db: &swc_common::errors::DiagnosticBuilder<'_>) { + use std::ops::Deref; + self.cell.borrow_mut().push(db.deref().clone()); + } +} + +fn is_fatal_swc_diagnostic(diagnostic: &Diagnostic) -> bool { + use swc_common::errors::Level; + match diagnostic.level { + Level::Bug + | Level::Cancelled + | Level::FailureNote + | Level::Fatal + | Level::PhaseFatal + | Level::Error => true, + Level::Help | Level::Note | Level::Warning => false, + } +} +fn format_swc_diagnostic(source_map: &SourceMap, diagnostic: &Diagnostic) -> String { + if let Some(span) = &diagnostic.span.primary_span() { + let file_name = source_map.span_to_filename(*span); + let loc = source_map.lookup_char_pos(span.lo); + format!( + "{} at {}:{}:{}", + diagnostic.message(), + file_name, + loc.line, + loc.col_display + 1, + ) + } else { + diagnostic.message() + } +} + +fn ensure_no_fatal_swc_diagnostics<'a>( + name: &str, + source_map: &SourceMap, + diagnostics: impl Iterator, +) -> Result<()> { + let fatal_diagnostics = diagnostics + .filter(|d| is_fatal_swc_diagnostic(d)) + .collect::>(); + if !fatal_diagnostics.is_empty() { + Err(Error::ParseError( + name.into(), + fatal_diagnostics + .iter() + .map(|d| format_swc_diagnostic(source_map, d)) + .collect::>() + .join("\n\n"), + )) + } else { + Ok(()) + } +} + +fn transpile_to_javascript(path: &str, input: String) -> Result { + // NOTE: This was taken almost verbatim from + // https://github.com/swc-project/swc/blob/main/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs + // This appears to be similar to what deno_ast does, but this has + // the advantage of actually compiling. :P + let cm: Lrc = Default::default(); + let diagnostics_cell: Rc>> = Rc::new(RefCell::new(Vec::new())); + let handler = DiagnosticCollector { + cell: diagnostics_cell.clone(), + } + .into_handler(); + + let fm = cm.new_source_file(FileName::Custom(path.into()), input.into()); + let comments = SingleThreadedComments::default(); + + let lexer = Lexer::new( + Syntax::Typescript(Default::default()), + Default::default(), + StringInput::from(&*fm), + Some(&comments), + ); + + let mut parser = Parser::new_from(lexer); + + for e in parser.take_errors() { + e.into_diagnostic(&handler).emit(); + } + + let module = parser + .parse_module() + .map_err(|e| e.into_diagnostic(&handler).emit()) + .expect("failed to parse module."); + + let globals = Globals::default(); + GLOBALS.set(&globals, || { + let unresolved_mark = Mark::new(); + let top_level_mark = Mark::new(); + + // Optionally transforms decorators here before the resolver pass + // as it might produce runtime declarations. + + // Conduct identifier scope analysis + let module = module.fold_with(&mut resolver(unresolved_mark, top_level_mark, true)); + + // Remove typescript types + let module = module.fold_with(&mut strip(top_level_mark)); + + // Fix up any identifiers with the same name, but different contexts + let module = module.fold_with(&mut hygiene()); + + // Ensure that we have enough parenthesis. + let module = module.fold_with(&mut fixer(Some(&comments))); + + let mut buf = vec![]; + { + let mut emitter = Emitter { + cfg: swc_ecma_codegen::Config { + minify: false, + ..Default::default() + }, + cm: cm.clone(), + comments: Some(&comments), + wr: JsWriter::new(cm.clone(), "\n", &mut buf, None), + }; + + emitter.emit_module(&module).unwrap(); + } + + let diagnostics = diagnostics_cell.borrow(); + ensure_no_fatal_swc_diagnostics(path, &cm, diagnostics.iter())?; + Ok(String::from_utf8(buf).expect("non-utf8?")) + }) +} struct Loader {} @@ -22,7 +172,6 @@ impl Loader { impl ModuleLoader for Loader { fn load(&self, _context: &ContextRef, name: &str) -> Result { - eprintln!("Loading {name}..."); let path = Path::new(name); let contents = std::fs::read_to_string(path)?; let contents = if path.extension().and_then(OsStr::to_str) == Some("ts") { @@ -59,8 +208,9 @@ impl ScriptContext { let gfx = graphics::GraphicsAPI::define(&context, gfx_send) .expect("Graphics module should load without error"); + let js = include_str!("main.js"); let module = context - .import_module("./src/main.ts", "") + .eval_module(js, "main.js") .expect("Unable to load main"); let init = module diff --git a/src/script/graphics.rs b/src/script/graphics.rs index b3058396..af708126 100644 --- a/src/script/graphics.rs +++ b/src/script/graphics.rs @@ -2,17 +2,14 @@ use oden_js::{module, ContextRef, Value, ValueResult}; use std::sync::mpsc::Sender; use std::sync::Arc; -#[derive(Debug)] pub struct PrintCommand { pub text: String, } -#[derive(Debug)] pub struct ClearCommand { pub color: [f64; 4], } -#[derive(Debug)] pub struct SpriteCommand { pub x: f32, pub y: f32, @@ -24,7 +21,6 @@ pub struct SpriteCommand { pub sh: f32, } -#[derive(Debug)] pub enum GraphicsCommand { Clear(ClearCommand), Print(PrintCommand), diff --git a/src/script/typescript.rs b/src/script/typescript.rs deleted file mode 100644 index 19bfc75b..00000000 --- a/src/script/typescript.rs +++ /dev/null @@ -1,154 +0,0 @@ -use oden_js::{Error, Result}; -use std::cell::RefCell; -use std::rc::Rc; - -use swc_common::{ - self, comments::SingleThreadedComments, errors::Diagnostic, sync::Lrc, FileName, Globals, Mark, - SourceMap, GLOBALS, -}; -use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; -use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax}; -use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene, resolver}; -use swc_ecma_transforms_typescript::strip; -use swc_ecma_visit::FoldWith; - -struct DiagnosticCollector { - cell: Rc>>, -} - -impl DiagnosticCollector { - pub fn into_handler(self) -> swc_common::errors::Handler { - swc_common::errors::Handler::with_emitter(true, false, Box::new(self)) - } -} - -impl swc_common::errors::Emitter for DiagnosticCollector { - fn emit(&mut self, db: &swc_common::errors::DiagnosticBuilder<'_>) { - use std::ops::Deref; - self.cell.borrow_mut().push(db.deref().clone()); - } -} - -fn is_fatal_swc_diagnostic(diagnostic: &Diagnostic) -> bool { - use swc_common::errors::Level; - match diagnostic.level { - Level::Bug - | Level::Cancelled - | Level::FailureNote - | Level::Fatal - | Level::PhaseFatal - | Level::Error => true, - Level::Help | Level::Note | Level::Warning => false, - } -} -fn format_swc_diagnostic(source_map: &SourceMap, diagnostic: &Diagnostic) -> String { - if let Some(span) = &diagnostic.span.primary_span() { - let file_name = source_map.span_to_filename(*span); - let loc = source_map.lookup_char_pos(span.lo); - format!( - "{} at {}:{}:{}", - diagnostic.message(), - file_name, - loc.line, - loc.col_display + 1, - ) - } else { - diagnostic.message() - } -} - -fn ensure_no_fatal_swc_diagnostics<'a>( - name: &str, - source_map: &SourceMap, - diagnostics: impl Iterator, -) -> Result<()> { - let fatal_diagnostics = diagnostics - .filter(|d| is_fatal_swc_diagnostic(d)) - .collect::>(); - if !fatal_diagnostics.is_empty() { - Err(Error::ParseError( - name.into(), - fatal_diagnostics - .iter() - .map(|d| format_swc_diagnostic(source_map, d)) - .collect::>() - .join("\n\n"), - )) - } else { - Ok(()) - } -} - -pub fn transpile_to_javascript(path: &str, input: String) -> Result { - // NOTE: This was taken almost verbatim from - // https://github.com/swc-project/swc/blob/main/crates/swc_ecma_transforms_typescript/examples/ts_to_js.rs - // This appears to be similar to what deno_ast does, but this has - // the advantage of actually compiling. :P - let cm: Lrc = Default::default(); - let diagnostics_cell: Rc>> = Rc::new(RefCell::new(Vec::new())); - let handler = DiagnosticCollector { - cell: diagnostics_cell.clone(), - } - .into_handler(); - - let fm = cm.new_source_file(FileName::Custom(path.into()), input.into()); - let comments = SingleThreadedComments::default(); - - let lexer = Lexer::new( - Syntax::Typescript(Default::default()), - Default::default(), - StringInput::from(&*fm), - Some(&comments), - ); - - let mut parser = Parser::new_from(lexer); - - for e in parser.take_errors() { - e.into_diagnostic(&handler).emit(); - } - - let module = parser - .parse_module() - .map_err(|e| e.into_diagnostic(&handler).emit()) - .expect("failed to parse module."); - - let globals = Globals::default(); - GLOBALS.set(&globals, || { - let unresolved_mark = Mark::new(); - let top_level_mark = Mark::new(); - - // Optionally transforms decorators here before the resolver pass - // as it might produce runtime declarations. - - // Conduct identifier scope analysis - let module = module.fold_with(&mut resolver(unresolved_mark, top_level_mark, true)); - - // Remove typescript types - let module = module.fold_with(&mut strip(top_level_mark)); - - // Fix up any identifiers with the same name, but different contexts - let module = module.fold_with(&mut hygiene()); - - // Ensure that we have enough parenthesis. - let module = module.fold_with(&mut fixer(Some(&comments))); - - let mut buf = vec![]; - { - let mut emitter = Emitter { - cfg: swc_ecma_codegen::Config { - minify: false, - ..Default::default() - }, - cm: cm.clone(), - comments: Some(&comments), - wr: JsWriter::new(cm.clone(), "\n", &mut buf, None), - }; - - emitter.emit_module(&module).unwrap(); - } - - let diagnostics = diagnostics_cell.borrow(); - ensure_no_fatal_swc_diagnostics(path, &cm, diagnostics.iter())?; - Ok(String::from_utf8(buf).expect("non-utf8?")) - }) -} diff --git a/src/shader.wgsl b/src/shader.wgsl index 331b4543..800e4538 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,58 +1,31 @@ // Vertex shader -struct ScreenUniform { - resolution : vec2f, -}; -@group(1) @binding(0) // 1. - var screen : ScreenUniform; - struct VertexInput { - @location(0) position : vec3, @location(1) tex_coords : vec2, + @location(0) position: vec3, + @location(1) tex_coords: vec2, }; struct VertexOutput { - @builtin(position) clip_position : vec4, - @location(0) tex_coords : vec2, + @builtin(position) clip_position: vec4, + @location(0) tex_coords: vec2, }; -const RES = vec2f(320.0, 240.0); // The logical resolution of the screen. - -@vertex fn vs_main(model : VertexInput)->VertexOutput { - var out : VertexOutput; - out.tex_coords = model.tex_coords; - - let RES_AR = RES.x / RES.y; // The aspect ratio of the logical screen. - - // the actual resolution of the screen. - let screen_ar = screen.resolution.x / screen.resolution.y; - - // Compute the difference in resolution ... correctly? - // - // nudge is the amount to add to the logical resolution so that the pixels - // stay the same size but we respect the aspect ratio of the screen. (So - // there's more of them in either the x or y direction.) - var nudge = vec2f(0.0); - if (screen_ar > RES_AR) { - nudge.x = (RES.y * screen_ar) - RES.x; - } else { - nudge.y = (RES.x / screen_ar) - RES.y; - } - var new_logical_resolution = RES + nudge; - - // Now we can convert the incoming position to clip space, in the new screen. - let in_pos = vec2f(model.position.x, model.position.y); - let centered = in_pos + (nudge / 2.0); - let position = (2.0 * centered / new_logical_resolution) - 1.0; - - out.clip_position = vec4f(position, model.position.z, 1.0); - return out; +@vertex +fn vs_main( + model: VertexInput, +) -> VertexOutput { + var out: VertexOutput; + out.tex_coords = model.tex_coords; + out.clip_position = vec4(model.position, 1.0); + return out; } // Fragment shader -@group(0) @binding(0) var t_diffuse : texture_2d; -@group(0) @binding(1) var s_diffuse : sampler; +@group(0) @binding(0) var t_diffuse: texture_2d; +@group(0) @binding(1) var s_diffuse: sampler; -@fragment fn fs_main(in : VertexOutput)->@location(0) vec4 { - return textureSample(t_diffuse, s_diffuse, in.tex_coords); +@fragment +fn fs_main(in: VertexOutput) -> @location(0) vec4 { + return textureSample(t_diffuse, s_diffuse, in.tex_coords); } diff --git a/types/graphics-core.d.ts b/types/graphics-core.d.ts index 5f79ec8d..41f83ec4 100644 --- a/types/graphics-core.d.ts +++ b/types/graphics-core.d.ts @@ -1,5 +1,3 @@ -// These are the functions exposed by the native graphics module. -// export function cls(r: number, g: number, b: number); export function print(msg: string); export function spr(