add rectangle and circle shapes
This commit is contained in:
parent
50094c3872
commit
7933057062
|
@ -1,6 +1,7 @@
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use tiny_skia::{
|
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::{
|
use crate::{
|
||||||
|
@ -132,6 +133,46 @@ impl<'a> Renderer<'a> {
|
||||||
None,
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -102,7 +102,7 @@ pub mod fns {
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{
|
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},
|
vm::{Exception, FnArgs, Vm},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -139,6 +139,8 @@ pub mod fns {
|
||||||
|
|
||||||
0xc0 "to-shape" => to_shape_f,
|
0xc0 "to-shape" => to_shape_f,
|
||||||
0xc1 "line" => line,
|
0xc1 "line" => line,
|
||||||
|
0xc2 "rect" => rect,
|
||||||
|
0xc3 "circle" => circle,
|
||||||
0xe0 "stroke" => stroke,
|
0xe0 "stroke" => stroke,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -410,7 +412,7 @@ pub mod fns {
|
||||||
None
|
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 start = args.get_vec4(vm, 0, ERROR)?;
|
||||||
let end = args.get_vec4(vm, 1, 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))
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
|
||||||
pub struct Vec4 {
|
pub struct Vec4 {
|
||||||
pub x: f32,
|
pub x: f32,
|
||||||
|
@ -151,8 +166,10 @@ pub struct List {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Shape {
|
pub enum Shape {
|
||||||
Point(Vec4),
|
Point(Vec2),
|
||||||
Line(Vec4, Vec4),
|
Line(Vec2, Vec2),
|
||||||
|
Rect(Vec2, Vec2),
|
||||||
|
Circle(Vec2, f32),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -32,6 +32,8 @@ pub struct Vm {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct VmImage {
|
pub struct VmImage {
|
||||||
|
stack: usize,
|
||||||
|
call_stack: usize,
|
||||||
refs: usize,
|
refs: usize,
|
||||||
defs: usize,
|
defs: usize,
|
||||||
fuel: usize,
|
fuel: usize,
|
||||||
|
@ -76,6 +78,8 @@ impl Vm {
|
||||||
"cannot image VM while running code"
|
"cannot image VM while running code"
|
||||||
);
|
);
|
||||||
VmImage {
|
VmImage {
|
||||||
|
stack: self.stack.len(),
|
||||||
|
call_stack: self.call_stack.len(),
|
||||||
refs: self.refs.len(),
|
refs: self.refs.len(),
|
||||||
defs: self.defs.len(),
|
defs: self.defs.len(),
|
||||||
fuel: self.fuel,
|
fuel: self.fuel,
|
||||||
|
@ -84,10 +88,21 @@ impl Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn restore_image(&mut self, image: &VmImage) {
|
pub fn restore_image(&mut self, image: &VmImage) {
|
||||||
assert!(
|
// NOTE: My initial assumption here was that system functions should not be able to restore
|
||||||
self.stack.is_empty() && self.call_stack.is_empty(),
|
// the VM if it's running code.
|
||||||
"cannot restore VM image while 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, || {
|
self.refs.resize_with(image.refs, || {
|
||||||
panic!("image must be a subset of the current VM")
|
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")
|
panic!("image must be a subset of the current VM")
|
||||||
});
|
});
|
||||||
self.fuel = image.fuel;
|
self.fuel = image.fuel;
|
||||||
|
self.memory = image.memory;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_defs(&mut self, defs: &Defs) {
|
pub fn apply_defs(&mut self, defs: &Defs) {
|
||||||
|
|
Loading…
Reference in a new issue