add rectangle and circle shapes
This commit is contained in:
parent
50094c3872
commit
7933057062
|
@ -1,6 +1,7 @@
|
|||
use alloc::vec::Vec;
|
||||
use tiny_skia::{
|
||||
BlendMode, Color, LineCap, Paint, PathBuilder, Pixmap, Shader, Stroke as SStroke, Transform,
|
||||
BlendMode, Color, LineCap, Paint, PathBuilder, Pixmap, Rect, Shader, Stroke as SStroke,
|
||||
Transform,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -132,6 +133,46 @@ impl<'a> Renderer<'a> {
|
|||
None,
|
||||
);
|
||||
}
|
||||
|
||||
Shape::Rect(position, size) => {
|
||||
let mut pb = PathBuilder::new();
|
||||
if let Some(rect) =
|
||||
tiny_skia::Rect::from_xywh(position.x, position.y, size.x, size.y)
|
||||
{
|
||||
pb.push_rect(rect);
|
||||
}
|
||||
let path = pb.finish().unwrap();
|
||||
|
||||
self.pixmap_mut().stroke_path(
|
||||
&path,
|
||||
&paint,
|
||||
&SStroke {
|
||||
width: stroke.thickness,
|
||||
line_cap: LineCap::Square,
|
||||
..Default::default()
|
||||
},
|
||||
transform,
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
Shape::Circle(position, radius) => {
|
||||
let mut pb = PathBuilder::new();
|
||||
pb.push_circle(position.x, position.y, radius);
|
||||
let path = pb.finish().unwrap();
|
||||
|
||||
self.pixmap_mut().stroke_path(
|
||||
&path,
|
||||
&paint,
|
||||
&SStroke {
|
||||
width: stroke.thickness,
|
||||
line_cap: LineCap::Square,
|
||||
..Default::default()
|
||||
},
|
||||
transform,
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -102,7 +102,7 @@ pub mod fns {
|
|||
use alloc::vec::Vec;
|
||||
|
||||
use crate::{
|
||||
value::{List, Ref, Rgba, Scribble, Shape, Stroke, Value, Vec4},
|
||||
value::{List, Ref, Rgba, Scribble, Shape, Stroke, Value, Vec2, Vec4},
|
||||
vm::{Exception, FnArgs, Vm},
|
||||
};
|
||||
|
||||
|
@ -139,6 +139,8 @@ pub mod fns {
|
|||
|
||||
0xc0 "to-shape" => to_shape_f,
|
||||
0xc1 "line" => line,
|
||||
0xc2 "rect" => rect,
|
||||
0xc3 "circle" => circle,
|
||||
0xe0 "stroke" => stroke,
|
||||
}
|
||||
}
|
||||
|
@ -410,7 +412,7 @@ pub mod fns {
|
|||
None
|
||||
}
|
||||
}
|
||||
Value::Vec4(vec) => Some(Shape::Point(vec)),
|
||||
Value::Vec4(vec) => Some(Shape::Point(vec.into())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -436,7 +438,50 @@ pub mod fns {
|
|||
let start = args.get_vec4(vm, 0, ERROR)?;
|
||||
let end = args.get_vec4(vm, 1, ERROR)?;
|
||||
|
||||
let id = vm.create_ref(Ref::Shape(Shape::Line(start, end)))?;
|
||||
let id = vm.create_ref(Ref::Shape(Shape::Line(start.into(), end.into())))?;
|
||||
Ok(Value::Ref(id))
|
||||
}
|
||||
|
||||
pub fn rect(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||
static ARGS2: &str = "arguments to 2-argument (rect) must be (vec)";
|
||||
static ARGS4: &str = "arguments to 4-argument (rect) must be numbers";
|
||||
|
||||
let (position, size) = match args.num() {
|
||||
2 => (args.get_vec4(vm, 0, ARGS2)?.into(), args.get_vec4(vm, 1, ARGS2)?.into()),
|
||||
4 => (
|
||||
Vec2 {
|
||||
x: args.get_number(vm, 0, ARGS4)?,
|
||||
y: args.get_number(vm, 1, ARGS4)?,
|
||||
},
|
||||
Vec2 {
|
||||
x: args.get_number(vm, 2, ARGS4)?,
|
||||
y: args.get_number(vm, 3, ARGS4)?,
|
||||
},
|
||||
),
|
||||
_ => return Err(vm.create_exception("(rect) expects 2 arguments (rect position size) or 4 arguments (rect x y width height)"))
|
||||
};
|
||||
|
||||
let id = vm.create_ref(Ref::Shape(Shape::Rect(position, size)))?;
|
||||
Ok(Value::Ref(id))
|
||||
}
|
||||
|
||||
pub fn circle(vm: &mut Vm, args: FnArgs) -> Result<Value, Exception> {
|
||||
static ARGS2: &str = "arguments to 2-argument (circle) must be (vec) and a number";
|
||||
static ARGS3: &str = "arguments to 3-argument (circle) must be numbers";
|
||||
|
||||
let (position, radius) = match args.num() {
|
||||
2 => (args.get_vec4(vm, 0, ARGS2)?.into(), args.get_number(vm, 1, ARGS2)?),
|
||||
3 => (
|
||||
Vec2 {
|
||||
x: args.get_number(vm, 0, ARGS3)?,
|
||||
y: args.get_number(vm, 1, ARGS3)?,
|
||||
},
|
||||
args.get_number(vm, 2, ARGS3)?
|
||||
),
|
||||
_ => return Err(vm.create_exception("(circle) expects 2 arguments (circle position radius) or 3 arguments (circle x y radius)"))
|
||||
};
|
||||
|
||||
let id = vm.create_ref(Ref::Shape(Shape::Circle(position, radius)))?;
|
||||
Ok(Value::Ref(id))
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,21 @@ impl From<f32> for Value {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
|
||||
pub struct Vec2 {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
}
|
||||
|
||||
impl From<Vec4> for Vec2 {
|
||||
fn from(value: Vec4) -> Self {
|
||||
Self {
|
||||
x: value.x,
|
||||
y: value.y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
|
||||
pub struct Vec4 {
|
||||
pub x: f32,
|
||||
|
@ -151,8 +166,10 @@ pub struct List {
|
|||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Shape {
|
||||
Point(Vec4),
|
||||
Line(Vec4, Vec4),
|
||||
Point(Vec2),
|
||||
Line(Vec2, Vec2),
|
||||
Rect(Vec2, Vec2),
|
||||
Circle(Vec2, f32),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -32,6 +32,8 @@ pub struct Vm {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct VmImage {
|
||||
stack: usize,
|
||||
call_stack: usize,
|
||||
refs: usize,
|
||||
defs: usize,
|
||||
fuel: usize,
|
||||
|
@ -76,6 +78,8 @@ impl Vm {
|
|||
"cannot image VM while running code"
|
||||
);
|
||||
VmImage {
|
||||
stack: self.stack.len(),
|
||||
call_stack: self.call_stack.len(),
|
||||
refs: self.refs.len(),
|
||||
defs: self.defs.len(),
|
||||
fuel: self.fuel,
|
||||
|
@ -84,10 +88,21 @@ impl Vm {
|
|||
}
|
||||
|
||||
pub fn restore_image(&mut self, image: &VmImage) {
|
||||
assert!(
|
||||
self.stack.is_empty() && self.call_stack.is_empty(),
|
||||
"cannot restore VM image while running code"
|
||||
);
|
||||
// NOTE: My initial assumption here was that system functions should not be able to restore
|
||||
// the VM if it's running code.
|
||||
// Turns out that was a bad assumption to make, because the VM may fail with an exception,
|
||||
// in which case the call stack and stack may not be empty.
|
||||
// assert!(
|
||||
// self.stack.is_empty() && self.call_stack.is_empty(),
|
||||
// "cannot restore VM image while running code"
|
||||
// );
|
||||
|
||||
self.stack.resize_with(image.stack, || {
|
||||
panic!("image must be a subset of the current VM")
|
||||
});
|
||||
self.call_stack.resize_with(image.call_stack, || {
|
||||
panic!("image must be a subset of the current VM")
|
||||
});
|
||||
self.refs.resize_with(image.refs, || {
|
||||
panic!("image must be a subset of the current VM")
|
||||
});
|
||||
|
@ -95,6 +110,7 @@ impl Vm {
|
|||
panic!("image must be a subset of the current VM")
|
||||
});
|
||||
self.fuel = image.fuel;
|
||||
self.memory = image.memory;
|
||||
}
|
||||
|
||||
pub fn apply_defs(&mut self, defs: &Defs) {
|
||||
|
|
Loading…
Reference in a new issue