From 34adc4fead3c33422eeed74bb36f463ff2869f3d Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Fri, 27 Mar 2026 00:22:54 +0000 Subject: [PATCH 1/9] Add a method to get the current puppet bounds --- inox2d/src/math.rs | 1 + inox2d/src/math/rect.rs | 34 ++++++++++++++++++++++++++++++++++ inox2d/src/puppet.rs | 25 +++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 inox2d/src/math/rect.rs diff --git a/inox2d/src/math.rs b/inox2d/src/math.rs index 952b312d..6d314b9d 100644 --- a/inox2d/src/math.rs +++ b/inox2d/src/math.rs @@ -2,4 +2,5 @@ pub mod camera; pub mod deform; pub mod interp; pub mod matrix; +pub mod rect; pub mod transform; diff --git a/inox2d/src/math/rect.rs b/inox2d/src/math/rect.rs new file mode 100644 index 00000000..6c5f9723 --- /dev/null +++ b/inox2d/src/math/rect.rs @@ -0,0 +1,34 @@ +use glam::Vec2; + +#[derive(Clone, Copy)] +pub struct Rect { + top_left: Vec2, + bottom_right: Vec2, +} + +impl Rect { + pub fn from_point(point: Vec2) -> Self { + Rect { + top_left: point, + bottom_right: point, + } + } + + pub fn with_union_point(&self, point: Vec2) -> Self { + let mut child = *self; + + if point.x < child.top_left.x { + child.top_left.x = point.x; + } else if child.bottom_right.x > point.x { + child.bottom_right.x = point.x; + } + + if point.y < child.top_left.y { + child.top_left.y = point.y; + } else if child.bottom_right.y > point.y { + child.bottom_right.y = point.y; + } + + child + } +} diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index 7cdcbfa1..52be5b5c 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -5,11 +5,14 @@ mod world; use std::collections::HashMap; +use crate::math::rect::Rect; +use crate::node::drawables::TexturedMeshComponents; use crate::node::{InoxNode, InoxNodeUuid}; use crate::params::{Param, ParamCtx}; use crate::physics::{PhysicsCtx, PuppetPhysics}; use crate::render::RenderCtx; +use glam::Vec4Swizzles; use meta::PuppetMeta; use transforms::TransformCtx; pub use tree::InoxNodeTree; @@ -167,4 +170,26 @@ impl Puppet { render_ctx.update(&self.nodes, &mut self.node_comps); } } + + /// Compute the bounds of the puppet's current state. + pub fn bounds(&self) -> Option { + let mut out = None; + for node in self.nodes.iter() { + if let Some(tmc) = self.node_comps.get::(node.uuid) { + let mvp = tmc.transform; + + for index in &tmc.mesh.indices { + if let Some(vert) = tmc.mesh.vertices.get(*index as usize) { + let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 0.0)).xy(); + out = match out { + None => Some(Rect::from_point(vert)), + Some(rect) => Some(rect.with_union_point(vert)), + }; + } + } + } + } + + out + } } From b1309870cebf2ababe3d52716b2e10a76e5d435d Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Fri, 27 Mar 2026 00:30:47 +0000 Subject: [PATCH 2/9] Add methods to get the width, height, and boundary points of a rectangle --- inox2d/src/math/rect.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/inox2d/src/math/rect.rs b/inox2d/src/math/rect.rs index 6c5f9723..852b7caf 100644 --- a/inox2d/src/math/rect.rs +++ b/inox2d/src/math/rect.rs @@ -31,4 +31,20 @@ impl Rect { child } + + pub fn width(&self) -> f32 { + self.bottom_right.x - self.top_left.x + } + + pub fn height(&self) -> f32 { + self.bottom_right.y - self.top_left.y + } + + pub fn top_left_point(&self) -> Vec2 { + self.top_left + } + + pub fn bottom_right_point(&self) -> Vec2 { + self.bottom_right + } } From 35bf94b0adf1025f8ef50daf82ec53b0e767a266 Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Fri, 27 Mar 2026 14:12:35 +0000 Subject: [PATCH 3/9] Grab the two components we need manually as TexturedMeshComponents does not actually exist in the ECS world. --- inox2d/src/puppet.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index 52be5b5c..4040c687 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -6,7 +6,7 @@ mod world; use std::collections::HashMap; use crate::math::rect::Rect; -use crate::node::drawables::TexturedMeshComponents; +use crate::node::components::{Mesh, TransformStore}; use crate::node::{InoxNode, InoxNodeUuid}; use crate::params::{Param, ParamCtx}; use crate::physics::{PhysicsCtx, PuppetPhysics}; @@ -175,11 +175,11 @@ impl Puppet { pub fn bounds(&self) -> Option { let mut out = None; for node in self.nodes.iter() { - if let Some(tmc) = self.node_comps.get::(node.uuid) { - let mvp = tmc.transform; + if let (Some(transform), Some(mesh)) = (self.node_comps.get::(node.uuid), self.node_comps.get::(node.uuid)) { + let mvp = transform.absolute; - for index in &tmc.mesh.indices { - if let Some(vert) = tmc.mesh.vertices.get(*index as usize) { + for index in &mesh.indices { + if let Some(vert) = mesh.vertices.get(*index as usize) { let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 0.0)).xy(); out = match out { None => Some(Rect::from_point(vert)), From a6a96e7709de9454eab24b97b1dc4c3915830d5e Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Fri, 27 Mar 2026 14:12:50 +0000 Subject: [PATCH 4/9] Fix rectangle union logic --- inox2d/src/math/rect.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inox2d/src/math/rect.rs b/inox2d/src/math/rect.rs index 852b7caf..12220eae 100644 --- a/inox2d/src/math/rect.rs +++ b/inox2d/src/math/rect.rs @@ -19,13 +19,13 @@ impl Rect { if point.x < child.top_left.x { child.top_left.x = point.x; - } else if child.bottom_right.x > point.x { + } else if point.x > child.bottom_right.x { child.bottom_right.x = point.x; } if point.y < child.top_left.y { child.top_left.y = point.y; - } else if child.bottom_right.y > point.y { + } else if point.y > child.bottom_right.y { child.bottom_right.y = point.y; } From 0777e720d28d26878dc6d228623af4bfad3d3079 Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Sun, 29 Mar 2026 13:58:00 +0000 Subject: [PATCH 5/9] Oops, I forgot how projective coordinates work. --- inox2d/src/puppet.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index 4040c687..b06d5db3 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -175,12 +175,15 @@ impl Puppet { pub fn bounds(&self) -> Option { let mut out = None; for node in self.nodes.iter() { - if let (Some(transform), Some(mesh)) = (self.node_comps.get::(node.uuid), self.node_comps.get::(node.uuid)) { + if let (Some(transform), Some(mesh)) = ( + self.node_comps.get::(node.uuid), + self.node_comps.get::(node.uuid), + ) { let mvp = transform.absolute; for index in &mesh.indices { if let Some(vert) = mesh.vertices.get(*index as usize) { - let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 0.0)).xy(); + let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 1.0)).xy(); out = match out { None => Some(Rect::from_point(vert)), Some(rect) => Some(rect.with_union_point(vert)), From 19874b34b14519d5c05f3506e75f53257e39dad8 Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Sun, 24 May 2026 17:49:24 +0000 Subject: [PATCH 6/9] Compute bounds using vertices directly, ignore indexed rendering entirely. This is about a 4-5x speedup of bounds calculation on myself. I haven't found out why yet; I assume it either results in way better vector codegen or the index list has a lot of repeats. Probably both. --- inox2d/src/puppet.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index b06d5db3..a7777964 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -181,14 +181,12 @@ impl Puppet { ) { let mvp = transform.absolute; - for index in &mesh.indices { - if let Some(vert) = mesh.vertices.get(*index as usize) { - let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 1.0)).xy(); - out = match out { - None => Some(Rect::from_point(vert)), - Some(rect) => Some(rect.with_union_point(vert)), - }; - } + for vert in &mesh.vertices { + let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 1.0)).xy(); + out = match out { + None => Some(Rect::from_point(vert)), + Some(rect) => Some(rect.with_union_point(vert)), + }; } } } From a0aa948cce171deed0e41de52bcee1aecc7ef3e9 Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Sat, 30 May 2026 18:35:12 +0000 Subject: [PATCH 7/9] Rename `Rect` to `RectBounds` as requested by Speykious --- inox2d/src/math/rect.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inox2d/src/math/rect.rs b/inox2d/src/math/rect.rs index 12220eae..aba72069 100644 --- a/inox2d/src/math/rect.rs +++ b/inox2d/src/math/rect.rs @@ -1,14 +1,14 @@ use glam::Vec2; #[derive(Clone, Copy)] -pub struct Rect { +pub struct RectBounds { top_left: Vec2, bottom_right: Vec2, } -impl Rect { +impl RectBounds { pub fn from_point(point: Vec2) -> Self { - Rect { + RectBounds { top_left: point, bottom_right: point, } From 175db56af0c2a2eb552246adee685301da0edafc Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Sat, 30 May 2026 18:43:47 +0000 Subject: [PATCH 8/9] Apparently, the rename symbol option in VSCode doesn't actually rename it everywhere. --- inox2d/src/puppet.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index a7777964..6e0633ba 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -5,7 +5,7 @@ mod world; use std::collections::HashMap; -use crate::math::rect::Rect; +use crate::math::rect::RectBounds; use crate::node::components::{Mesh, TransformStore}; use crate::node::{InoxNode, InoxNodeUuid}; use crate::params::{Param, ParamCtx}; @@ -172,7 +172,7 @@ impl Puppet { } /// Compute the bounds of the puppet's current state. - pub fn bounds(&self) -> Option { + pub fn bounds(&self) -> Option { let mut out = None; for node in self.nodes.iter() { if let (Some(transform), Some(mesh)) = ( From be77a867835ac38d2b17c92ff086c72d46798246 Mon Sep 17 00:00:00 2001 From: Arcturus Emrys Date: Sat, 30 May 2026 18:54:03 +0000 Subject: [PATCH 9/9] The amount of times I've had to push commits that just rename Rect to RectBounds has become Comical --- inox2d/src/puppet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inox2d/src/puppet.rs b/inox2d/src/puppet.rs index 6e0633ba..0089e406 100644 --- a/inox2d/src/puppet.rs +++ b/inox2d/src/puppet.rs @@ -184,7 +184,7 @@ impl Puppet { for vert in &mesh.vertices { let vert = mvp.mul_vec4(glam::Vec4::new(vert.x, vert.y, 0.0, 1.0)).xy(); out = match out { - None => Some(Rect::from_point(vert)), + None => Some(RectBounds::from_point(vert)), Some(rect) => Some(rect.with_union_point(vert)), }; }