Compare commits
3 commits
fd7e19e529
...
aa90cea4a3
| Author | SHA1 | Date | |
|---|---|---|---|
| aa90cea4a3 | |||
| c7903382a0 | |||
| af12dccd5d |
6 changed files with 309 additions and 85 deletions
|
|
@ -104,3 +104,14 @@ impl TryFromValue for Value {
|
||||||
Ok(value.dup(ctx))
|
Ok(value.dup(ctx))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: TryFromValue> TryFromValue for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
fn try_from_value(value: &ValueRef, ctx: &ContextRef) -> Result<Self> {
|
||||||
|
if value.is_undefined() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(T::try_from_value(value, ctx)?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,11 +48,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, A, F> RustFunction<PhantomData<(&R, &A, &F)>> for F
|
impl<R, A, FN> RustFunction<PhantomData<(&R, &A, &FN)>> for FN
|
||||||
where
|
where
|
||||||
R: IntoRustFunctionResult,
|
R: IntoRustFunctionResult,
|
||||||
A: TryFromValue,
|
A: TryFromValue,
|
||||||
F: Fn(&ContextRef, A) -> R + Sized,
|
FN: Fn(&ContextRef, A) -> R + Sized,
|
||||||
{
|
{
|
||||||
fn argument_count() -> usize {
|
fn argument_count() -> usize {
|
||||||
1
|
1
|
||||||
|
|
@ -72,12 +72,12 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, A, B, F> RustFunction<PhantomData<(&R, &A, &B, &F)>> for F
|
impl<R, A, B, FN> RustFunction<PhantomData<(&R, &A, &B, &FN)>> for FN
|
||||||
where
|
where
|
||||||
R: IntoRustFunctionResult,
|
R: IntoRustFunctionResult,
|
||||||
A: TryFromValue,
|
A: TryFromValue,
|
||||||
B: TryFromValue,
|
B: TryFromValue,
|
||||||
F: Fn(&ContextRef, A, B) -> R + Sized,
|
FN: Fn(&ContextRef, A, B) -> R + Sized,
|
||||||
{
|
{
|
||||||
fn argument_count() -> usize {
|
fn argument_count() -> usize {
|
||||||
2
|
2
|
||||||
|
|
@ -98,13 +98,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, A, B, C, F> RustFunction<PhantomData<(&R, &A, &B, &C, &F)>> for F
|
impl<R, A, B, C, FN> RustFunction<PhantomData<(&R, &A, &B, &C, &FN)>> for FN
|
||||||
where
|
where
|
||||||
R: IntoRustFunctionResult,
|
R: IntoRustFunctionResult,
|
||||||
A: TryFromValue,
|
A: TryFromValue,
|
||||||
B: TryFromValue,
|
B: TryFromValue,
|
||||||
C: TryFromValue,
|
C: TryFromValue,
|
||||||
F: Fn(&ContextRef, A, B, C) -> R + Sized,
|
FN: Fn(&ContextRef, A, B, C) -> R + Sized,
|
||||||
{
|
{
|
||||||
fn argument_count() -> usize {
|
fn argument_count() -> usize {
|
||||||
3
|
3
|
||||||
|
|
@ -126,14 +126,14 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, A, B, C, D, F> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &F)>> for F
|
impl<R, A, B, C, D, FN> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &FN)>> for FN
|
||||||
where
|
where
|
||||||
R: IntoRustFunctionResult,
|
R: IntoRustFunctionResult,
|
||||||
A: TryFromValue,
|
A: TryFromValue,
|
||||||
B: TryFromValue,
|
B: TryFromValue,
|
||||||
C: TryFromValue,
|
C: TryFromValue,
|
||||||
D: TryFromValue,
|
D: TryFromValue,
|
||||||
F: Fn(&ContextRef, A, B, C, D) -> R + Sized,
|
FN: Fn(&ContextRef, A, B, C, D) -> R + Sized,
|
||||||
{
|
{
|
||||||
fn argument_count() -> usize {
|
fn argument_count() -> usize {
|
||||||
4
|
4
|
||||||
|
|
@ -156,7 +156,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R, A, B, C, D, E, F> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &F)>> for F
|
impl<R, A, B, C, D, E, FN> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &FN)>> for FN
|
||||||
where
|
where
|
||||||
R: IntoRustFunctionResult,
|
R: IntoRustFunctionResult,
|
||||||
A: TryFromValue,
|
A: TryFromValue,
|
||||||
|
|
@ -164,7 +164,7 @@ where
|
||||||
C: TryFromValue,
|
C: TryFromValue,
|
||||||
D: TryFromValue,
|
D: TryFromValue,
|
||||||
E: TryFromValue,
|
E: TryFromValue,
|
||||||
F: Fn(&ContextRef, A, B, C, D, E) -> R + Sized,
|
FN: Fn(&ContextRef, A, B, C, D, E) -> R + Sized,
|
||||||
{
|
{
|
||||||
fn argument_count() -> usize {
|
fn argument_count() -> usize {
|
||||||
5
|
5
|
||||||
|
|
@ -187,3 +187,113 @@ where
|
||||||
res.into_res(context)
|
res.into_res(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<R, A, B, C, D, E, F, FN> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &F, &FN)>> 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<R, A, B, C, D, E, F, G, FN> RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &F, &G, &FN)>>
|
||||||
|
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<R, A, B, C, D, E, F, G, H, FN>
|
||||||
|
RustFunction<PhantomData<(&R, &A, &B, &C, &D, &E, &F, &G, &H, &FN)>> 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -128,3 +128,13 @@ impl<T: Class> TryIntoValue for T {
|
||||||
self.into_value(ctx)
|
self.into_value(ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: TryIntoValue> TryIntoValue for Option<T> {
|
||||||
|
#[inline]
|
||||||
|
fn try_into_value(self, ctx: &ContextRef) -> ValueResult {
|
||||||
|
match self {
|
||||||
|
None => Ok(ctx.undefined()),
|
||||||
|
Some(v) => v.try_into_value(ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
144
src/lib.rs
144
src/lib.rs
|
|
@ -1,5 +1,4 @@
|
||||||
use bytemuck;
|
use bytemuck;
|
||||||
use wgpu::util::DeviceExt;
|
|
||||||
use winit::{
|
use winit::{
|
||||||
event::*,
|
event::*,
|
||||||
event_loop::{ControlFlow, EventLoop},
|
event_loop::{ControlFlow, EventLoop},
|
||||||
|
|
@ -8,13 +7,13 @@ use winit::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod script;
|
mod script;
|
||||||
use script::graphics::{ClearCommand, GraphicsCommand, PrintCommand};
|
use script::graphics::GraphicsCommand;
|
||||||
mod texture;
|
mod texture;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
#[derive(Copy, Clone, Debug, bytemuck::Pod, bytemuck::Zeroable)]
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
position: [f32; 3],
|
position: [f32; 3], // TODO: Why do I pass in a Z here?
|
||||||
tex_coords: [f32; 2],
|
tex_coords: [f32; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,8 +73,7 @@ struct State {
|
||||||
render_pipeline: wgpu::RenderPipeline,
|
render_pipeline: wgpu::RenderPipeline,
|
||||||
|
|
||||||
vertex_buffer: wgpu::Buffer,
|
vertex_buffer: wgpu::Buffer,
|
||||||
index_buffer: wgpu::Buffer,
|
max_vertices: usize,
|
||||||
num_indices: u32, // Indices in index_buffer
|
|
||||||
|
|
||||||
diffuse_bind_group: wgpu::BindGroup,
|
diffuse_bind_group: wgpu::BindGroup,
|
||||||
|
|
||||||
|
|
@ -248,17 +246,15 @@ impl State {
|
||||||
multiview: None,
|
multiview: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
let vertex_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
let max_vertices: usize = 4096;
|
||||||
|
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
label: Some("Vertex Buffer"),
|
label: Some("Vertex Buffer"),
|
||||||
contents: bytemuck::cast_slice(VERTICES),
|
size: (max_vertices * std::mem::size_of::<Vertex>())
|
||||||
usage: wgpu::BufferUsages::VERTEX,
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
|
mapped_at_creation: false,
|
||||||
|
usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST,
|
||||||
});
|
});
|
||||||
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 {
|
Self {
|
||||||
window,
|
window,
|
||||||
|
|
@ -269,8 +265,7 @@ impl State {
|
||||||
size,
|
size,
|
||||||
render_pipeline,
|
render_pipeline,
|
||||||
vertex_buffer,
|
vertex_buffer,
|
||||||
index_buffer,
|
max_vertices,
|
||||||
num_indices,
|
|
||||||
diffuse_bind_group,
|
diffuse_bind_group,
|
||||||
|
|
||||||
mouse_x: 0.0,
|
mouse_x: 0.0,
|
||||||
|
|
@ -302,11 +297,6 @@ impl State {
|
||||||
let view = output
|
let view = output
|
||||||
.texture
|
.texture
|
||||||
.create_view(&wgpu::TextureViewDescriptor::default());
|
.create_view(&wgpu::TextureViewDescriptor::default());
|
||||||
let mut encoder = self
|
|
||||||
.device
|
|
||||||
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
|
||||||
label: Some("Render Encoder"),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Group the commands into passes.
|
// Group the commands into passes.
|
||||||
struct Pass {
|
struct Pass {
|
||||||
|
|
@ -316,8 +306,8 @@ impl State {
|
||||||
let mut passes = Vec::new();
|
let mut passes = Vec::new();
|
||||||
for command in commands {
|
for command in commands {
|
||||||
match command {
|
match command {
|
||||||
GraphicsCommand::Clear(ClearCommand { color }) => passes.push(Pass {
|
GraphicsCommand::Clear(cc) => passes.push(Pass {
|
||||||
color: Some(color),
|
color: Some(cc.color),
|
||||||
commands: Vec::new(),
|
commands: Vec::new(),
|
||||||
}),
|
}),
|
||||||
GraphicsCommand::EndFrame => (),
|
GraphicsCommand::EndFrame => (),
|
||||||
|
|
@ -331,39 +321,91 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut vertices = Vec::new();
|
||||||
for pass in passes {
|
for pass in passes {
|
||||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
// TODO: It would be great if we could use multiple passes in a
|
||||||
label: Some("Render Pass"),
|
// single encoder but right now because of the dyanmic
|
||||||
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
// nature of vertices we can't, I think? Because
|
||||||
view: &view,
|
// queue.write_buffer doesn't actually happen until we call
|
||||||
resolve_target: None,
|
// submit...
|
||||||
ops: wgpu::Operations {
|
let mut encoder = self
|
||||||
load: if let Some([r, g, b, a]) = pass.color {
|
.device
|
||||||
wgpu::LoadOp::Clear(wgpu::Color {
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
|
||||||
r, //0.1,
|
label: Some("Render Encoder"),
|
||||||
g, //0.2,
|
});
|
||||||
b,
|
|
||||||
a,
|
{
|
||||||
})
|
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
} else {
|
label: Some("Render Pass"),
|
||||||
wgpu::LoadOp::Load
|
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,
|
||||||
},
|
},
|
||||||
store: true,
|
})],
|
||||||
},
|
depth_stencil_attachment: None,
|
||||||
})],
|
});
|
||||||
depth_stencil_attachment: None,
|
|
||||||
});
|
|
||||||
|
|
||||||
for command in pass.commands {
|
vertices.clear();
|
||||||
match command {
|
for command in pass.commands {
|
||||||
GraphicsCommand::Print(PrintCommand { text }) => {
|
match command {
|
||||||
println!("{}", text);
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// {
|
// {
|
||||||
|
|
@ -397,8 +439,6 @@ impl State {
|
||||||
// render_pass.draw_indexed(0..self.num_indices, 0, 0..1);
|
// 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();
|
output.present();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { cls, print } from "graphics";
|
import { cls, print, spr } from "graphics";
|
||||||
|
|
||||||
export function init() {
|
export function init() {
|
||||||
print("Hello world!");
|
print("Hello world!");
|
||||||
|
|
@ -8,4 +8,5 @@ export function update() {}
|
||||||
|
|
||||||
export function draw() {
|
export function draw() {
|
||||||
cls(0.1, 0.2, 0.3);
|
cls(0.1, 0.2, 0.3);
|
||||||
|
spr(0, 0, 0.5, 0.5, 0, 0, 0.5, 0.5);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use oden_js::{module, ContextRef, Error, Value, ValueRef, ValueResult};
|
use oden_js::{module, ContextRef, Value, ValueRef, ValueResult};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -10,9 +10,21 @@ pub struct ClearCommand {
|
||||||
pub color: [f64; 4],
|
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 {
|
pub enum GraphicsCommand {
|
||||||
Clear(ClearCommand),
|
Clear(ClearCommand),
|
||||||
Print(PrintCommand),
|
Print(PrintCommand),
|
||||||
|
Sprite(SpriteCommand),
|
||||||
EndFrame,
|
EndFrame,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,22 +51,37 @@ impl GraphicsImpl {
|
||||||
Ok(Value::undefined(ctx))
|
Ok(Value::undefined(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cls_fn(&self, ctx: &ContextRef, args: &[&ValueRef]) -> ValueResult {
|
fn cls_fn(&self, ctx: &ContextRef, r: f64, g: f64, b: f64) -> 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 {
|
let _ = self.sender.send(GraphicsCommand::Clear(ClearCommand {
|
||||||
color: [r, g, b, 1.0],
|
color: [r, g, b, 1.0],
|
||||||
}));
|
}));
|
||||||
Ok(Value::undefined(ctx))
|
Ok(Value::undefined(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn spr_fn(
|
||||||
|
&self,
|
||||||
|
ctx: &ContextRef,
|
||||||
|
x: f32,
|
||||||
|
y: f32,
|
||||||
|
w: f32,
|
||||||
|
h: f32,
|
||||||
|
u: f32,
|
||||||
|
v: f32,
|
||||||
|
sw: Option<f32>,
|
||||||
|
sh: Option<f32>,
|
||||||
|
) -> 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 {
|
pub struct GraphicsAPI {
|
||||||
|
|
@ -64,18 +91,43 @@ pub struct GraphicsAPI {
|
||||||
impl GraphicsAPI {
|
impl GraphicsAPI {
|
||||||
pub fn define(ctx: &ContextRef, sender: Sender<GraphicsCommand>) -> oden_js::Result<Self> {
|
pub fn define(ctx: &ContextRef, sender: Sender<GraphicsCommand>) -> oden_js::Result<Self> {
|
||||||
let gfx = Arc::new(GraphicsImpl::new(sender));
|
let gfx = Arc::new(GraphicsImpl::new(sender));
|
||||||
let gfx_a = gfx.clone();
|
let mut builder = module::NativeModuleBuilder::new(ctx);
|
||||||
let gfx_b = gfx.clone();
|
{
|
||||||
module::NativeModuleBuilder::new(ctx)
|
let gfx = gfx.clone();
|
||||||
.export(
|
builder.export(
|
||||||
"print",
|
"print",
|
||||||
ctx.new_dynamic_fn(move |ctx, _, args| gfx_a.print_fn(ctx, args))?,
|
ctx.new_dynamic_fn(move |ctx, _, args| gfx.print_fn(ctx, args))?,
|
||||||
)?
|
)?;
|
||||||
.export(
|
}
|
||||||
|
{
|
||||||
|
let gfx = gfx.clone();
|
||||||
|
builder.export(
|
||||||
"cls",
|
"cls",
|
||||||
ctx.new_dynamic_fn(move |ctx, _, args| gfx_b.cls_fn(ctx, args))?,
|
ctx.new_fn(move |ctx: &ContextRef, r: f64, g: f64, b: f64| {
|
||||||
)?
|
gfx.cls_fn(ctx, r, g, b)
|
||||||
.build("graphics")?;
|
})?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
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<f32>,
|
||||||
|
sh: Option<f32>| {
|
||||||
|
gfx.spr_fn(ctx, x, y, w, h, u, v, sw, sh)
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
builder.build("graphics")?;
|
||||||
Ok(GraphicsAPI { gfx })
|
Ok(GraphicsAPI { gfx })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue