From 679ee9a2ce569dce1729c20aa70466a912dd898b Mon Sep 17 00:00:00 2001
From: griffi-gh <prasol258@gmail.com>
Date: Mon, 3 Mar 2025 18:16:07 +0100
Subject: [PATCH] more crappy code

---
 hui-painter-wip/src/paint/command.rs          |  3 +-
 hui-painter-wip/src/paint/command/list.rs     | 21 ++++++++---
 .../src/paint/command/rectangle.rs            | 29 ++++++++++-----
 hui-painter-wip/src/paint/command/text.rs     | 10 +++--
 .../src/paint/command/transform.rs            | 37 +++++++++++++++++--
 hui-shared/src/rect/rect.rs                   | 12 ++++++
 6 files changed, 91 insertions(+), 21 deletions(-)

diff --git a/hui-painter-wip/src/paint/command.rs b/hui-painter-wip/src/paint/command.rs
index 265e5b2..749649e 100644
--- a/hui-painter-wip/src/paint/command.rs
+++ b/hui-painter-wip/src/paint/command.rs
@@ -1,6 +1,7 @@
 use std::hash::Hash;
 
 use glam::Vec2;
+use hui_shared::rect::Rect;
 use crate::{paint::buffer::PaintBuffer, PainterInstance};
 
 // mod root;
@@ -37,7 +38,7 @@ pub trait PaintCommand {
   /// Must be unique for each possilbe combination of parameters
   fn cache_hash(&self) -> u64;
 
-  fn size(&self, ctx: &PainterInstance) -> Vec2;
+  fn bounds(&self, ctx: &PainterInstance) -> Rect;
 }
 
 // TODO move paint_root to PaintCommand instead of separate trait?
diff --git a/hui-painter-wip/src/paint/command/list.rs b/hui-painter-wip/src/paint/command/list.rs
index 57f4ba0..15e2c26 100644
--- a/hui-painter-wip/src/paint/command/list.rs
+++ b/hui-painter-wip/src/paint/command/list.rs
@@ -1,5 +1,7 @@
 use std::hash::Hasher;
 
+use hui_shared::rect::Rect;
+
 use crate::PainterInstance;
 
 use super::PaintCommand;
@@ -53,11 +55,20 @@ impl PaintCommand for PaintList {
     hasher.finish()
   }
 
-  fn size(&self, ctx: &PainterInstance) -> glam::Vec2 {
-    let mut size = glam::Vec2::ZERO;
-    for command in &self.commands {
-      size = size.max(command.size(ctx));
+  fn bounds(&self, ctx: &PainterInstance) -> Rect {
+    if self.commands.is_empty() {
+      return Rect::ZERO;
+    }
+    let mut position = glam::Vec2::splat(f32::MAX);
+    let mut size = glam::Vec2::splat(f32::MIN);
+    for command in &self.commands {
+      let bounds = command.bounds(ctx);
+      position = position.min(bounds.position);
+      size = size.max(bounds.size);
+    }
+    Rect {
+      position,
+      size,
     }
-    size
   }
 }
\ No newline at end of file
diff --git a/hui-painter-wip/src/paint/command/rectangle.rs b/hui-painter-wip/src/paint/command/rectangle.rs
index 0f52390..42672d2 100644
--- a/hui-painter-wip/src/paint/command/rectangle.rs
+++ b/hui-painter-wip/src/paint/command/rectangle.rs
@@ -1,6 +1,6 @@
 use std::{hash::Hasher, num::NonZeroU16};
 use glam::{vec2, Vec2};
-use hui_shared::{color, rect::{Corners, FillColor}};
+use hui_shared::{color, rect::{Corners, FillColor, Rect}};
 use crate::{
   paint::{
     buffer::{PaintBuffer, Vertex},
@@ -94,6 +94,11 @@ impl PaintRectangle {
 
 impl PaintCommand for PaintRectangle {
   fn paint(&self, ctx: &mut PainterInstance, into: &mut PaintBuffer) {
+    // Offset from (0, 0) to the actual origin
+    // We calculate positions in the range of [0, size] for simplicity
+    // And then subtract this offset to get the actual position of a rectangle centered at (0, 0)
+    // let origin_offset = self.size / 2.;
+
     // If texture is set:
     // - Get texture UV
     // - Map local UVs to texture UV coords
@@ -166,22 +171,22 @@ impl PaintCommand for PaintRectangle {
       ]);
       into.vertices.extend([
         Vertex {
-          position: vec2(0., 0.) * self.size,
+          position: vec2(0., 0.) * self.size, // - origin_offset,
           uv: uvs.top_left,
           color: colors.top_left,
         },
         Vertex {
-          position: vec2(1., 0.) * self.size,
+          position: vec2(1., 0.) * self.size, // - origin_offset,
           uv: uvs.top_right,
           color: colors.top_right,
         },
         Vertex {
-          position: vec2(0., 1.) * self.size,
+          position: vec2(0., 1.) * self.size, // - origin_offset,
           uv: uvs.bottom_left,
           color: colors.bottom_left,
         },
         Vertex {
-          position: vec2(1., 1.) * self.size,
+          position: vec2(1., 1.) * self.size, // - origin_offset,
           uv: uvs.bottom_right,
           color: colors.bottom_right,
         },
@@ -208,7 +213,7 @@ impl PaintCommand for PaintRectangle {
           uvs.bottom_left * (1. - point_uv.x) * point_uv.y +
           uvs.top_left * (1. - point_uv.x) * (1. - point_uv.y);
         Vertex {
-          position: point,
+          position: point, // - origin_offset,
           color: color_at_point,
           uv: uv_at_point,
         }
@@ -276,8 +281,15 @@ impl PaintCommand for PaintRectangle {
     }
   }
 
-  fn size(&self, ctx: &PainterInstance) -> Vec2 {
-    self.size
+  fn bounds(&self, _: &PainterInstance) -> Rect {
+    // Rect {
+    //   position: -self.size / 2.,
+    //   size: self.size / 2.,
+    // }
+    Rect {
+      position: Vec2::ZERO,
+      size: self.size,
+    }
   }
 
   fn cache_hash(&self) -> u64 {
@@ -288,5 +300,4 @@ impl PaintCommand for PaintRectangle {
     }
     hasher.finish()
   }
-
 }
diff --git a/hui-painter-wip/src/paint/command/text.rs b/hui-painter-wip/src/paint/command/text.rs
index e07dbad..74e10e6 100644
--- a/hui-painter-wip/src/paint/command/text.rs
+++ b/hui-painter-wip/src/paint/command/text.rs
@@ -1,6 +1,7 @@
 use std::{borrow::Cow, hash::{Hash, Hasher}};
 use fontdue::layout::{CoordinateSystem, Layout};
 use glam::{vec2, Vec2};
+use hui_shared::rect::Rect;
 use crate::{
   paint::{
     buffer::PaintBuffer,
@@ -76,10 +77,10 @@ impl PaintCommand for PaintText {
 
     // todo!()
 
-    // TODO text rendering
+    // TODO_IMPORTANT text rendering
   }
 
-  fn size(&self, ctx: &PainterInstance) -> Vec2 {
+  fn bounds(&self, ctx: &PainterInstance) -> Rect {
     let font_array = self.build_font_array(ctx);
     let layout = self.build_layout(&font_array);
 
@@ -91,7 +92,10 @@ impl PaintCommand for PaintText {
     }).unwrap_or(0.);
     let height = layout.height();
 
-    vec2(width, height)
+    Rect {
+      position: vec2(0., 0.),
+      size: vec2(width, height),
+    }
   }
 
   fn cache_hash(&self) -> u64 {
diff --git a/hui-painter-wip/src/paint/command/transform.rs b/hui-painter-wip/src/paint/command/transform.rs
index c2192f8..400d378 100644
--- a/hui-painter-wip/src/paint/command/transform.rs
+++ b/hui-painter-wip/src/paint/command/transform.rs
@@ -1,5 +1,8 @@
 use std::hash::Hasher;
 
+use glam::vec2;
+use hui_shared::rect::Rect;
+
 use crate::{
   PainterInstance,
   paint::{
@@ -25,6 +28,11 @@ impl<T: PaintCommand + 'static> PaintCommand for PaintTransform<T> {
     // paint children node
     self.child.paint(ctx, into);
 
+    if starting_index == into.vertices.len() {
+      // no vertices were added, no need to transform
+      return;
+    }
+
     let mut min_point = glam::Vec2::splat(f32::MAX);
     let mut max_point = glam::Vec2::splat(f32::MIN);
     for vtx in &into.vertices[starting_index..] {
@@ -52,8 +60,31 @@ impl<T: PaintCommand + 'static> PaintCommand for PaintTransform<T> {
     hasher.finish()
   }
 
-  fn size(&self, ctx: &PainterInstance) -> glam::Vec2 {
-    // TODO take transform into account
-    self.child.size(ctx)
+  fn bounds(&self, ctx: &PainterInstance) -> Rect {
+    let Rect { position, size } = self.child.bounds(ctx);
+
+    // XXX: to match the behavior above, transform the corners around the center
+    // FIXME: the behavior may not actually match?
+
+    let half = size / 2.0;
+    let center = position + half;
+    let points = [
+      self.transform.transform_point2(vec2(-half.x, -half.y)) + center,
+      self.transform.transform_point2(vec2( half.x, -half.y)) + center,
+      self.transform.transform_point2(vec2(-half.x,  half.y)) + center,
+      self.transform.transform_point2(vec2( half.x,  half.y)) + center,
+    ];
+
+    let mut min_point = glam::Vec2::splat(f32::MAX);
+    let mut max_point = glam::Vec2::splat(f32::MIN);
+    for point in points {
+      min_point = min_point.min(point);
+      max_point = max_point.max(point);
+    }
+
+    Rect {
+      position: min_point,
+      size: max_point - min_point,
+    }
   }
 }
diff --git a/hui-shared/src/rect/rect.rs b/hui-shared/src/rect/rect.rs
index 988ae3f..d4e2e8d 100644
--- a/hui-shared/src/rect/rect.rs
+++ b/hui-shared/src/rect/rect.rs
@@ -11,6 +11,18 @@ pub struct Rect {
 }
 
 impl Rect {
+  /// A rect with both position and size set to zero.
+  pub const ZERO: Self = Self {
+    position: Vec2::ZERO,
+    size: Vec2::ZERO,
+  };
+
+  /// A rect with size of 1x1 and position of zero.
+  pub const UNIT: Self = Self {
+    position: Vec2::ZERO,
+    size: Vec2::ONE,
+  };
+
   pub const fn new(position: Vec2, size: Vec2) -> Self {
     Self { position, size }
   }