[oden] Garbage assets, need to rewrite to IO
This commit is contained in:
parent
75fcc427ac
commit
17805fa4a6
17 changed files with 240 additions and 94 deletions
|
|
@ -69,7 +69,7 @@ where
|
||||||
*ret
|
*ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::Exception(e, _)) => unsafe {
|
Err(Error::Exception(e, _, _)) => unsafe {
|
||||||
// If we returned `Error::Exception` then we're propagating an
|
// If we returned `Error::Exception` then we're propagating an
|
||||||
// exception through the JS stack, just flip it.
|
// exception through the JS stack, just flip it.
|
||||||
let exc = &e.val;
|
let exc = &e.val;
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,12 @@ impl ContextRef {
|
||||||
pub(crate) fn exception_error(&self) -> Error {
|
pub(crate) fn exception_error(&self) -> Error {
|
||||||
let exc = self.exception();
|
let exc = self.exception();
|
||||||
let desc = exc.to_string(&self).unwrap_or_else(|_| String::new());
|
let desc = exc.to_string(&self).unwrap_or_else(|_| String::new());
|
||||||
Error::Exception(exc, desc)
|
let stack = exc
|
||||||
|
.get_property(&self, "stack")
|
||||||
|
.and_then(|stack| stack.to_string(&self))
|
||||||
|
.unwrap_or_else(|_| String::new());
|
||||||
|
|
||||||
|
Error::Exception(exc, desc, stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{ContextRef, Error, Result, Value, ValueRef};
|
use crate::{ContextRef, Error, Result, Value, ValueRef, ValueType};
|
||||||
use std::num::TryFromIntError;
|
use std::num::TryFromIntError;
|
||||||
|
|
||||||
pub trait TryFromValue: Sized {
|
pub trait TryFromValue: Sized {
|
||||||
|
|
@ -105,10 +105,24 @@ impl TryFromValue for Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryFromValue for () {
|
||||||
|
#[inline]
|
||||||
|
fn try_from_value(value: &ValueRef, _ctx: &ContextRef) -> Result<Self> {
|
||||||
|
if value.is_undefined() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::InvalidType {
|
||||||
|
expected: ValueType::Undefined,
|
||||||
|
found: value.value_type(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: TryFromValue> TryFromValue for Option<T> {
|
impl<T: TryFromValue> TryFromValue for Option<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result<Self> {
|
fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result<Self> {
|
||||||
if value.is_undefined() {
|
if value.is_null() || value.is_undefined() {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(T::try_from_value(value, ctx)?))
|
Ok(Some(T::try_from_value(value, ctx)?))
|
||||||
|
|
|
||||||
|
|
@ -7,21 +7,21 @@ pub trait TryIntoValue {
|
||||||
impl TryIntoValue for u8 {
|
impl TryIntoValue for u8 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
ctx.new_u64(self)
|
ctx.new_u32(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryIntoValue for u16 {
|
impl TryIntoValue for u16 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
ctx.new_u64(self)
|
ctx.new_u32(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryIntoValue for u32 {
|
impl TryIntoValue for u32 {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
ctx.new_u64(self)
|
ctx.new_u32(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,7 +116,7 @@ impl TryIntoValue for Error {
|
||||||
}
|
}
|
||||||
Error::ConversionError(e) => Err(Error::ConversionError(e)),
|
Error::ConversionError(e) => Err(Error::ConversionError(e)),
|
||||||
Error::RustFunctionError(e) => Err(Error::RustFunctionError(e)),
|
Error::RustFunctionError(e) => Err(Error::RustFunctionError(e)),
|
||||||
Error::Exception(v, d) => Err(Error::Exception(v.dup(ctx), d)),
|
Error::Exception(v, d, s) => Err(Error::Exception(v.dup(ctx), d, s)),
|
||||||
Error::OutOfMemory => Err(Error::OutOfMemory),
|
Error::OutOfMemory => Err(Error::OutOfMemory),
|
||||||
Error::IOError(e) => Err(Error::IOError(e)),
|
Error::IOError(e) => Err(Error::IOError(e)),
|
||||||
Error::ParseError(name, err) => Err(Error::ParseError(name, err)),
|
Error::ParseError(name, err) => Err(Error::ParseError(name, err)),
|
||||||
|
|
@ -135,8 +135,15 @@ impl<T: TryIntoValue> TryIntoValue for Option<T> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
match self {
|
match self {
|
||||||
None => Ok(ctx.undefined()),
|
None => Ok(ctx.null()),
|
||||||
Some(v) => v.try_into_value(ctx),
|
Some(v) => v.try_into_value(ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryIntoValue for () {
|
||||||
|
#[inline]
|
||||||
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
|
Ok(ctx.undefined())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ pub use conversion::*;
|
||||||
pub use runtime::Runtime;
|
pub use runtime::Runtime;
|
||||||
pub use value::{Value, ValueRef, ValueType};
|
pub use value::{Value, ValueRef, ValueType};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Debug, Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("too many classes have been registered")]
|
#[error("too many classes have been registered")]
|
||||||
TooManyClasses,
|
TooManyClasses,
|
||||||
|
|
@ -39,8 +39,8 @@ pub enum Error {
|
||||||
ConversionError(String),
|
ConversionError(String),
|
||||||
#[error("an error occurred calling a rust function: {0}")]
|
#[error("an error occurred calling a rust function: {0}")]
|
||||||
RustFunctionError(String),
|
RustFunctionError(String),
|
||||||
#[error("an exception was thrown during evaluation: {1}")]
|
#[error("an exception was thrown during evaluation: {1}\nStack: {2}")]
|
||||||
Exception(Value, String),
|
Exception(Value, String, String),
|
||||||
#[error("out of memory")]
|
#[error("out of memory")]
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
#[error("an io error occurred: {0}")]
|
#[error("an io error occurred: {0}")]
|
||||||
|
|
@ -66,7 +66,7 @@ pub type ValueResult = core::result::Result<Value, Error>;
|
||||||
|
|
||||||
pub(crate) fn throw_error(context: &ContextRef, error: Error) -> sys::JSValue {
|
pub(crate) fn throw_error(context: &ContextRef, error: Error) -> sys::JSValue {
|
||||||
match error {
|
match error {
|
||||||
Error::Exception(v, _) => unsafe {
|
Error::Exception(v, _, _) => unsafe {
|
||||||
sys::JS_DupValue(context.ctx, v.val);
|
sys::JS_DupValue(context.ctx, v.val);
|
||||||
sys::JS_Throw(context.ctx, v.val)
|
sys::JS_Throw(context.ctx, v.val)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ unsafe extern "C" fn init_func<T: NativeModule>(
|
||||||
let context = ContextRef::from_raw(ctx);
|
let context = ContextRef::from_raw(ctx);
|
||||||
match NativeModuleState::<T>::define(&context, m) {
|
match NativeModuleState::<T>::define(&context, m) {
|
||||||
Ok(_) => 0,
|
Ok(_) => 0,
|
||||||
Err(Error::Exception(e, _)) => unsafe {
|
Err(Error::Exception(e, _, _)) => unsafe {
|
||||||
// If we returned `Error::Exception` then we're propagating an
|
// If we returned `Error::Exception` then we're propagating an
|
||||||
// exception through the JS stack, just flip it.
|
// exception through the JS stack, just flip it.
|
||||||
let exc = &e.val;
|
let exc = &e.val;
|
||||||
|
|
|
||||||
|
|
@ -137,9 +137,7 @@ impl ValueRef {
|
||||||
let mut res: u32 = 0;
|
let mut res: u32 = 0;
|
||||||
let ret = sys::JS_ToUint32(ctx.ctx, &mut res, self.val);
|
let ret = sys::JS_ToUint32(ctx.ctx, &mut res, self.val);
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
let exc = ctx.exception();
|
Err(ctx.exception_error())
|
||||||
let desc = exc.to_string(&ctx).unwrap_or_else(|_| String::new());
|
|
||||||
Err(Error::Exception(exc, desc))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
src/assets.ts
Normal file
5
src/assets.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import * as core from "asset-core";
|
||||||
|
|
||||||
|
export function load_texture(path: string): number {
|
||||||
|
return core.load_texture(path);
|
||||||
|
}
|
||||||
|
|
@ -51,3 +51,12 @@ export function spr(
|
||||||
sh = sh || h;
|
sh = sh || h;
|
||||||
core.spr(x, y, w, h, sx, sy, sw, sh);
|
core.spr(x, y, w, h, sx, sy, sw, sh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the specified texture as the current texture for calls to e.g. spr().
|
||||||
|
*
|
||||||
|
* @param id - The identifier of the texture to use.
|
||||||
|
*/
|
||||||
|
export function use_texture(id: number) {
|
||||||
|
core.use_texture(id);
|
||||||
|
}
|
||||||
|
|
|
||||||
94
src/lib.rs
94
src/lib.rs
|
|
@ -1,4 +1,5 @@
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
|
use std::collections::HashMap;
|
||||||
use wgpu::util::DeviceExt;
|
use wgpu::util::DeviceExt;
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
|
|
@ -65,7 +66,8 @@ struct State {
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
max_vertices: usize,
|
max_vertices: usize,
|
||||||
|
|
||||||
diffuse_bind_group: wgpu::BindGroup,
|
sprite_bind_group_layout: wgpu::BindGroupLayout,
|
||||||
|
sprite_textures: HashMap<u32, wgpu::BindGroup>,
|
||||||
|
|
||||||
screen_uniform: ScreenUniforms,
|
screen_uniform: ScreenUniforms,
|
||||||
screen_uniform_buffer: wgpu::Buffer,
|
screen_uniform_buffer: wgpu::Buffer,
|
||||||
|
|
@ -146,11 +148,12 @@ impl State {
|
||||||
};
|
};
|
||||||
surface.configure(&device, &config);
|
surface.configure(&device, &config);
|
||||||
|
|
||||||
let diffuse_bytes = include_bytes!("happy-tree.png");
|
// TODO: DELETE THIS
|
||||||
let diffuse_texture =
|
// let diffuse_bytes = include_bytes!("happy-tree.png");
|
||||||
texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
|
// let diffuse_texture =
|
||||||
|
// texture::Texture::from_bytes(&device, &queue, diffuse_bytes, "happy-tree.png").unwrap();
|
||||||
|
|
||||||
let texture_bind_group_layout =
|
let sprite_bind_group_layout =
|
||||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||||
entries: &[
|
entries: &[
|
||||||
wgpu::BindGroupLayoutEntry {
|
wgpu::BindGroupLayoutEntry {
|
||||||
|
|
@ -172,23 +175,24 @@ impl State {
|
||||||
count: None,
|
count: None,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
label: Some("texture_bind_group_layout"),
|
label: Some("sprite_bind_group_layout"),
|
||||||
});
|
});
|
||||||
|
|
||||||
let diffuse_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
// TODO: DELETE THIS
|
||||||
layout: &texture_bind_group_layout,
|
// let sprite_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
entries: &[
|
// layout: &sprite_bind_group_layout,
|
||||||
wgpu::BindGroupEntry {
|
// entries: &[
|
||||||
binding: 0,
|
// wgpu::BindGroupEntry {
|
||||||
resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
|
// binding: 0,
|
||||||
},
|
// resource: wgpu::BindingResource::TextureView(&diffuse_texture.view),
|
||||||
wgpu::BindGroupEntry {
|
// },
|
||||||
binding: 1,
|
// wgpu::BindGroupEntry {
|
||||||
resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
|
// binding: 1,
|
||||||
},
|
// resource: wgpu::BindingResource::Sampler(&diffuse_texture.sampler),
|
||||||
],
|
// },
|
||||||
label: Some("diffuse_bind_group"),
|
// ],
|
||||||
});
|
// label: Some("diffuse_bind_group"),
|
||||||
|
// });
|
||||||
|
|
||||||
let screen_uniform = ScreenUniforms::new(size.width, size.height);
|
let screen_uniform = ScreenUniforms::new(size.width, size.height);
|
||||||
let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let screen_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||||
|
|
@ -229,10 +233,7 @@ impl State {
|
||||||
let render_pipeline_layout =
|
let render_pipeline_layout =
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
label: Some("Render Pipeline Layout"),
|
label: Some("Render Pipeline Layout"),
|
||||||
bind_group_layouts: &[
|
bind_group_layouts: &[&sprite_bind_group_layout, &screen_uniform_bind_group_layout],
|
||||||
&texture_bind_group_layout,
|
|
||||||
&screen_uniform_bind_group_layout,
|
|
||||||
],
|
|
||||||
push_constant_ranges: &[],
|
push_constant_ranges: &[],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -294,7 +295,8 @@ impl State {
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
max_vertices,
|
max_vertices,
|
||||||
diffuse_bind_group,
|
sprite_bind_group_layout,
|
||||||
|
sprite_textures: HashMap::new(),
|
||||||
screen_uniform,
|
screen_uniform,
|
||||||
screen_uniform_buffer,
|
screen_uniform_buffer,
|
||||||
screen_uniform_bind_group,
|
screen_uniform_bind_group,
|
||||||
|
|
@ -348,6 +350,31 @@ impl State {
|
||||||
color: Some(cc.color),
|
color: Some(cc.color),
|
||||||
commands: Vec::new(),
|
commands: Vec::new(),
|
||||||
}),
|
}),
|
||||||
|
GraphicsCommand::CreateTexture(ct) => {
|
||||||
|
let texture = texture::Texture::from_image(
|
||||||
|
&self.device,
|
||||||
|
&self.queue,
|
||||||
|
&ct.image,
|
||||||
|
Some(&ct.label),
|
||||||
|
);
|
||||||
|
let sprite_bind_group =
|
||||||
|
self.device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||||
|
layout: &self.sprite_bind_group_layout,
|
||||||
|
entries: &[
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 0,
|
||||||
|
resource: wgpu::BindingResource::TextureView(&texture.view),
|
||||||
|
},
|
||||||
|
wgpu::BindGroupEntry {
|
||||||
|
binding: 1,
|
||||||
|
resource: wgpu::BindingResource::Sampler(&texture.sampler),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
label: Some(&ct.label),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.sprite_textures.insert(ct.id, sprite_bind_group);
|
||||||
|
}
|
||||||
GraphicsCommand::EndFrame => (),
|
GraphicsCommand::EndFrame => (),
|
||||||
other => match passes.last_mut() {
|
other => match passes.last_mut() {
|
||||||
Some(pass) => pass.commands.push(other),
|
Some(pass) => pass.commands.push(other),
|
||||||
|
|
@ -395,6 +422,7 @@ impl State {
|
||||||
depth_stencil_attachment: None,
|
depth_stencil_attachment: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut texture_id = None;
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
for command in pass.commands {
|
for command in pass.commands {
|
||||||
match command {
|
match command {
|
||||||
|
|
@ -428,20 +456,30 @@ impl State {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphicsCommand::UseTexture(id) => texture_id = Some(id),
|
||||||
|
GraphicsCommand::CreateTexture(_) => (), // Already handled
|
||||||
GraphicsCommand::Clear(_) => (), // Already handled
|
GraphicsCommand::Clear(_) => (), // Already handled
|
||||||
GraphicsCommand::EndFrame => (), // Should never appear
|
GraphicsCommand::EndFrame => (), // Should never appear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(id) = texture_id {
|
||||||
assert!(vertices.len() < self.max_vertices); // !
|
assert!(vertices.len() < self.max_vertices); // !
|
||||||
self.queue
|
self.queue.write_buffer(
|
||||||
.write_buffer(&self.vertex_buffer, 0, bytemuck::cast_slice(&vertices));
|
&self.vertex_buffer,
|
||||||
|
0,
|
||||||
|
bytemuck::cast_slice(&vertices),
|
||||||
|
);
|
||||||
render_pass.set_pipeline(&self.render_pipeline);
|
render_pass.set_pipeline(&self.render_pipeline);
|
||||||
render_pass.set_bind_group(0, &self.diffuse_bind_group, &[]);
|
|
||||||
|
let bind_group = self.sprite_textures.get(&id).unwrap();
|
||||||
|
render_pass.set_bind_group(0, bind_group, &[]);
|
||||||
|
|
||||||
render_pass.set_bind_group(1, &self.screen_uniform_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.set_vertex_buffer(0, self.vertex_buffer.slice(..));
|
||||||
render_pass.draw(0..(vertices.len() as u32), 0..1);
|
render_pass.draw(0..(vertices.len() as u32), 0..1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Submit will accept anything that implements IntoIter
|
// Submit will accept anything that implements IntoIter
|
||||||
self.queue.submit(std::iter::once(encoder.finish()));
|
self.queue.submit(std::iter::once(encoder.finish()));
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
import { cls, print, spr } from "./graphics.ts";
|
import { cls, print, spr, use_texture } from "./graphics.ts";
|
||||||
|
import { load_texture } from "./assets.ts";
|
||||||
|
|
||||||
|
let the_texture = 0;
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
print("Hello world!");
|
print("Hello world!");
|
||||||
|
the_texture = load_texture("./src/happy-tree.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function update() {}
|
export function update() {}
|
||||||
|
|
||||||
export function draw() {
|
export function draw() {
|
||||||
cls(0.1, 0.2, 0.3);
|
cls(0.1, 0.2, 0.3);
|
||||||
|
use_texture(the_texture);
|
||||||
spr((320 - 256) / 2, 0, 256, 240, 0, 0);
|
spr((320 - 256) / 2, 0, 256, 240, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,8 @@ use graphics::GraphicsCommand;
|
||||||
mod typescript;
|
mod typescript;
|
||||||
use typescript::transpile_to_javascript;
|
use typescript::transpile_to_javascript;
|
||||||
|
|
||||||
|
pub mod assets;
|
||||||
|
|
||||||
struct Loader {}
|
struct Loader {}
|
||||||
|
|
||||||
impl Loader {
|
impl Loader {
|
||||||
|
|
@ -42,6 +44,7 @@ pub struct ScriptContext {
|
||||||
draw: Value,
|
draw: Value,
|
||||||
|
|
||||||
gfx: graphics::GraphicsAPI,
|
gfx: graphics::GraphicsAPI,
|
||||||
|
_assets: assets::AssetsAPI,
|
||||||
gfx_receive: Receiver<graphics::GraphicsCommand>,
|
gfx_receive: Receiver<graphics::GraphicsCommand>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,8 +59,10 @@ impl ScriptContext {
|
||||||
|
|
||||||
let (gfx_send, gfx_receive) = channel();
|
let (gfx_send, gfx_receive) = channel();
|
||||||
|
|
||||||
let gfx = graphics::GraphicsAPI::define(&context, gfx_send)
|
let gfx = graphics::GraphicsAPI::define(&context, gfx_send.clone())
|
||||||
.expect("Graphics module should load without error");
|
.expect("Graphics module should load without error");
|
||||||
|
let assets = assets::AssetsAPI::define(&context, gfx_send.clone())
|
||||||
|
.expect("Assets module should load without error");
|
||||||
|
|
||||||
let module = context
|
let module = context
|
||||||
.import_module("./src/main.ts", "")
|
.import_module("./src/main.ts", "")
|
||||||
|
|
@ -82,6 +87,8 @@ impl ScriptContext {
|
||||||
|
|
||||||
gfx,
|
gfx,
|
||||||
gfx_receive,
|
gfx_receive,
|
||||||
|
|
||||||
|
_assets: assets,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
56
src/script/assets.rs
Normal file
56
src/script/assets.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use crate::script::graphics::{CreateTextureCommand, GraphicsCommand};
|
||||||
|
use oden_js::{module::native::NativeModuleBuilder, ContextRef, Error, Result};
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
struct AssetsImpl {
|
||||||
|
next_texture_id: AtomicU32,
|
||||||
|
gfx_sender: Sender<GraphicsCommand>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AssetsImpl {
|
||||||
|
fn new(sender: Sender<GraphicsCommand>) -> Self {
|
||||||
|
AssetsImpl {
|
||||||
|
gfx_sender: sender,
|
||||||
|
next_texture_id: AtomicU32::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_texture(&self, path: &str) -> Result<u32> {
|
||||||
|
let bytes = std::fs::read(path)?;
|
||||||
|
let image = match image::load_from_memory(&bytes) {
|
||||||
|
Ok(i) => i,
|
||||||
|
Err(e) => return Err(Error::RustFunctionError(format!("{e}"))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let id = self.next_texture_id.fetch_add(1, Ordering::SeqCst);
|
||||||
|
let _ = self
|
||||||
|
.gfx_sender
|
||||||
|
.send(GraphicsCommand::CreateTexture(CreateTextureCommand {
|
||||||
|
id,
|
||||||
|
image,
|
||||||
|
label: path.into(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
Ok(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AssetsAPI {}
|
||||||
|
|
||||||
|
impl AssetsAPI {
|
||||||
|
pub fn define(ctx: &ContextRef, sender: Sender<GraphicsCommand>) -> oden_js::Result<Self> {
|
||||||
|
let assets = Arc::new(AssetsImpl::new(sender));
|
||||||
|
let mut builder = NativeModuleBuilder::new(ctx);
|
||||||
|
{
|
||||||
|
let assets = assets.clone();
|
||||||
|
builder.export(
|
||||||
|
"load_texture",
|
||||||
|
ctx.new_fn(move |_ctx: &ContextRef, p: String| assets.load_texture(&p))?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
builder.build("asset-core")?;
|
||||||
|
Ok(AssetsAPI {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use oden_js::{module, ContextRef, Value, ValueResult};
|
use oden_js::{module, ContextRef};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -24,11 +24,20 @@ pub struct SpriteCommand {
|
||||||
pub sh: f32,
|
pub sh: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CreateTextureCommand {
|
||||||
|
pub id: u32,
|
||||||
|
pub image: image::DynamicImage,
|
||||||
|
pub label: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum GraphicsCommand {
|
pub enum GraphicsCommand {
|
||||||
Clear(ClearCommand),
|
Clear(ClearCommand),
|
||||||
Print(PrintCommand),
|
Print(PrintCommand),
|
||||||
Sprite(SpriteCommand),
|
Sprite(SpriteCommand),
|
||||||
|
CreateTexture(CreateTextureCommand),
|
||||||
|
UseTexture(u32),
|
||||||
EndFrame,
|
EndFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,33 +50,19 @@ impl GraphicsImpl {
|
||||||
GraphicsImpl { sender }
|
GraphicsImpl { sender }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_fn(&self, ctx: &ContextRef, text: String) -> ValueResult {
|
fn print(&self, text: String) -> () {
|
||||||
let _ = self
|
let _ = self
|
||||||
.sender
|
.sender
|
||||||
.send(GraphicsCommand::Print(PrintCommand { text }));
|
.send(GraphicsCommand::Print(PrintCommand { text }));
|
||||||
|
|
||||||
Ok(Value::undefined(ctx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cls_fn(&self, ctx: &ContextRef, r: f64, g: f64, b: f64) -> ValueResult {
|
fn cls(&self, r: f64, g: f64, b: f64) -> () {
|
||||||
let _ = self.sender.send(GraphicsCommand::Clear(ClearCommand {
|
let _ = self.sender.send(GraphicsCommand::Clear(ClearCommand {
|
||||||
color: [r, g, b, 1.0],
|
color: [r, g, b, 1.0],
|
||||||
}));
|
}));
|
||||||
Ok(Value::undefined(ctx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spr_fn(
|
fn spr(&self, x: f32, y: f32, w: f32, h: f32, u: f32, v: f32, sw: f32, sh: f32) {
|
||||||
&self,
|
|
||||||
ctx: &ContextRef,
|
|
||||||
x: f32,
|
|
||||||
y: f32,
|
|
||||||
w: f32,
|
|
||||||
h: f32,
|
|
||||||
u: f32,
|
|
||||||
v: f32,
|
|
||||||
sw: f32,
|
|
||||||
sh: f32,
|
|
||||||
) -> ValueResult {
|
|
||||||
let _ = self.sender.send(GraphicsCommand::Sprite(SpriteCommand {
|
let _ = self.sender.send(GraphicsCommand::Sprite(SpriteCommand {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
|
@ -78,7 +73,10 @@ impl GraphicsImpl {
|
||||||
sw,
|
sw,
|
||||||
sh,
|
sh,
|
||||||
}));
|
}));
|
||||||
Ok(Value::undefined(ctx))
|
}
|
||||||
|
|
||||||
|
fn use_texture(&self, id: u32) {
|
||||||
|
let _ = self.sender.send(GraphicsCommand::UseTexture(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,16 +92,14 @@ impl GraphicsAPI {
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"print",
|
"print",
|
||||||
ctx.new_fn(move |ctx: &ContextRef, t: String| gfx.print_fn(ctx, t))?,
|
ctx.new_fn(move |_: &ContextRef, t: String| gfx.print(t))?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let gfx = gfx.clone();
|
let gfx = gfx.clone();
|
||||||
builder.export(
|
builder.export(
|
||||||
"cls",
|
"cls",
|
||||||
ctx.new_fn(move |ctx: &ContextRef, r: f64, g: f64, b: f64| {
|
ctx.new_fn(move |_: &ContextRef, r: f64, g: f64, b: f64| gfx.cls(r, g, b))?,
|
||||||
gfx.cls_fn(ctx, r, g, b)
|
|
||||||
})?,
|
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
|
@ -111,7 +107,7 @@ impl GraphicsAPI {
|
||||||
builder.export(
|
builder.export(
|
||||||
"spr",
|
"spr",
|
||||||
ctx.new_fn(
|
ctx.new_fn(
|
||||||
move |ctx: &ContextRef,
|
move |_: &ContextRef,
|
||||||
x: f32,
|
x: f32,
|
||||||
y: f32,
|
y: f32,
|
||||||
w: f32,
|
w: f32,
|
||||||
|
|
@ -119,12 +115,17 @@ impl GraphicsAPI {
|
||||||
u: f32,
|
u: f32,
|
||||||
v: f32,
|
v: f32,
|
||||||
sw: f32,
|
sw: f32,
|
||||||
sh: f32| {
|
sh: f32| gfx.spr(x, y, w, h, u, v, sw, sh),
|
||||||
gfx.spr_fn(ctx, x, y, w, h, u, v, sw, sh)
|
|
||||||
},
|
|
||||||
)?,
|
)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let gfx = gfx.clone();
|
||||||
|
builder.export(
|
||||||
|
"use_texture",
|
||||||
|
ctx.new_fn(move |_: &ContextRef, id: u32| gfx.use_texture(id))?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
builder.build("graphics-core")?;
|
builder.build("graphics-core")?;
|
||||||
Ok(GraphicsAPI { gfx })
|
Ok(GraphicsAPI { gfx })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
use anyhow::*;
|
|
||||||
use image::GenericImageView;
|
use image::GenericImageView;
|
||||||
|
|
||||||
pub struct Texture {
|
pub struct Texture {
|
||||||
|
|
@ -8,22 +7,22 @@ pub struct Texture {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Texture {
|
impl Texture {
|
||||||
pub fn from_bytes(
|
// pub fn from_bytes(
|
||||||
device: &wgpu::Device,
|
// device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
// queue: &wgpu::Queue,
|
||||||
bytes: &[u8],
|
// bytes: &[u8],
|
||||||
label: &str,
|
// label: &str,
|
||||||
) -> Result<Self> {
|
// ) -> Result<Self> {
|
||||||
let img = image::load_from_memory(bytes)?;
|
// let img = image::load_from_memory(bytes)?;
|
||||||
Self::from_image(device, queue, &img, Some(label))
|
// Ok(Self::from_image(device, queue, &img, Some(label)))
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn from_image(
|
pub fn from_image(
|
||||||
device: &wgpu::Device,
|
device: &wgpu::Device,
|
||||||
queue: &wgpu::Queue,
|
queue: &wgpu::Queue,
|
||||||
img: &image::DynamicImage,
|
img: &image::DynamicImage,
|
||||||
label: Option<&str>,
|
label: Option<&str>,
|
||||||
) -> Result<Self> {
|
) -> Self {
|
||||||
let rgba = img.to_rgba8();
|
let rgba = img.to_rgba8();
|
||||||
let dimensions = img.dimensions();
|
let dimensions = img.dimensions();
|
||||||
|
|
||||||
|
|
@ -70,10 +69,10 @@ impl Texture {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
Ok(Self {
|
Self {
|
||||||
texture,
|
texture,
|
||||||
view,
|
view,
|
||||||
sampler,
|
sampler,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
types/asset-core.d.ts
vendored
Normal file
1
types/asset-core.d.ts
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
export function load_texture(path: string): number;
|
||||||
1
types/graphics-core.d.ts
vendored
1
types/graphics-core.d.ts
vendored
|
|
@ -12,3 +12,4 @@ export function spr(
|
||||||
sw: number,
|
sw: number,
|
||||||
sh: number
|
sh: number
|
||||||
);
|
);
|
||||||
|
export function use_texture(id: number);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue