wip: move Bsp in with Direction

This commit is contained in:
🪞👃🪞 2025-01-01 18:46:21 +01:00
parent a6a4eb80fd
commit 01dacd407d
3 changed files with 72 additions and 175 deletions

View file

@ -1,133 +0,0 @@
use crate::*;
/// Renders multiple things on top of each other,
#[macro_export] macro_rules! lay {
($($expr:expr),* $(,)?) => {{
let bsp = ();
$(let bsp = Bsp::b(bsp, $expr);)*;
bsp
}}
}
/// Stack southward.
#[macro_export] macro_rules! col {
($($expr:expr),* $(,)?) => {{
let bsp = ();
$(let bsp = Bsp::s(bsp, $expr);)*;
bsp
}};
}
/// Stack northward.
#[macro_export] macro_rules! col_up {
($($expr:expr),* $(,)?) => {{
let bsp = ();
$(let bsp = Bsp::n(bsp, $expr);)*;
bsp
}}
}
/// Stack eastward.
#[macro_export] macro_rules! row {
($($expr:expr),* $(,)?) => {{
let bsp = ();
$(let bsp = Bsp::e(bsp, $expr);)*;
bsp
}};
}
pub enum Bsp<E: Engine, X: Content<E>, Y: Content<E>> {
/// X is north of Y
North(Option<f64>, Option<X>, Option<Y>),
/// X is south of Y
South(Option<f64>, Option<X>, Option<Y>),
/// X is east of Y
East(Option<f64>, Option<X>, Option<Y>),
/// X is west of Y
West(Option<f64>, Option<X>, Option<Y>),
/// X is above Y
Above(Option<X>, Option<Y>),
/// X is below Y
Below(Option<X>, Option<Y>),
/// Should be avoided.
Null(PhantomData<E>),
}
impl<E: Engine, X: Content<E>, Y: Content<E>> Bsp<E, X, Y> {
pub fn n (x: X, y: Y) -> Self { Self::North(None, Some(x), Some(y)) }
pub fn s (x: X, y: Y) -> Self { Self::South(None, Some(x), Some(y)) }
pub fn e (x: X, y: Y) -> Self { Self::East(None, Some(x), Some(y)) }
pub fn w (x: X, y: Y) -> Self { Self::West(None, Some(x), Some(y)) }
pub fn a (x: X, y: Y) -> Self { Self::Above(Some(x), Some(y)) }
pub fn b (x: X, y: Y) -> Self { Self::Below(Some(x), Some(y)) }
pub fn areas (&self, outer: E::Area) -> [E::Area;2] {
let [x, y, w, h] = outer.xywh();
match self {
Self::Null(_) => [[x, y, 0.into(), 0.into()].into(), [x, y, 0.into(), 0.into()].into()],
Self::Above(a, b) | Self::Below(a, b) => [a.layout(outer), b.layout(outer)],
Self::North(_, a, b) => {
let a = a.layout(outer);
let b = b.layout([x, y, w, h.minus(a.h())].into());
[a, b]
}
Self::South(_, a, b) => {
let a = a.layout(outer);
let b = b.layout([x, y + a.h(), w, h.minus(a.h())].into());
[a, b]
},
Self::East(_, a, b) => {
let a = a.layout(outer);
let b = b.layout([x + a.w(), y, w.minus(a.w()), h].into());
[a, b]
},
Self::West(_, a, b) => {
let a = a.layout(outer);
let b = b.layout([x, y, w.minus(a.w()), h].into());
[a, b]
},
}
}
}
impl<E: Engine, X: Content<E>, Y: Content<E>> Default for Bsp<E, X, Y> {
fn default () -> Self {
Self::Null(Default::default())
}
}
impl<E: Engine, X: Content<E>, Y: Content<E>> Content<E> for Bsp<E, X, Y> {
fn layout (&self, outer: E::Area) -> E::Area {
let [a, b] = self.areas(outer);
let [x, y] = outer.center();
match self {
Self::Null(_) =>
[x, y, 0.into(), 0.into()],
Self::North(_, _, _) =>
[a.x().min(b.x()), a.y().min(b.y()), a.w().max(b.w()), a.h() + b.h()],
Self::South(_, _, _) =>
[a.x().min(b.x()), a.y().min(b.y()), a.w().max(b.w()), a.h() + b.h()],
Self::East(_, _, _) =>
[a.x().min(b.x()), a.y().min(b.y()), a.w() + b.w(), a.h().max(b.h())],
Self::West(_, _, _) =>
[a.x().min(b.x()), a.y().min(b.y()), a.w() + b.w(), a.h().max(b.h())],
Self::Above(_, _) | Self::Below(_, _) =>
[a.x().min(b.x()), a.y().min(b.y()), a.w().max(b.w()), a.h().max(b.h())]
}.into()
}
fn render (&self, to: &mut E::Output) {
let [area_a, area_b] = self.areas(to.area());
match self {
Self::North(_, a, b) |
Self::South(_, a, b) |
Self::East(_, a, b) |
Self::West(_, a, b) |
Self::Above(a, b) |
Self::Below(a, b) => {
to.place(area_a, a);
to.place(area_b, b);
},
_ => {},
}
}
}

View file

@ -1,52 +1,83 @@
use crate::*;
pub use self::Direction::*;
/// A cardinal direction.
#[derive(Copy, Clone, PartialEq)]
pub enum Direction { North, South, West, East, }
pub use self::Direction::*;
pub enum Direction { North, South, East, West, Above, Below }
impl Direction {
pub fn is_north (&self) -> bool { matches!(self, Self::North) }
pub fn is_south (&self) -> bool { matches!(self, Self::South) }
pub fn is_east (&self) -> bool { matches!(self, Self::West) }
pub fn is_west (&self) -> bool { matches!(self, Self::East) }
/// Return next direction clockwise
pub fn cw (&self) -> Self {
match self {
Self::North => Self::East,
Self::South => Self::West,
Self::West => Self::North,
Self::East => Self::South,
}
}
/// Return next direction counterclockwise01.
pub fn ccw (&self) -> Self {
match self {
Self::North => Self::West,
Self::South => Self::East,
Self::West => Self::South,
Self::East => Self::North,
}
}
pub fn split_fixed <N: Coordinate> (self, area: impl Area<N>, a: N) -> ([N;4],[N;4]) {
let [x, y, w, h] = area.xywh();
match self {
North => (
[area.x(), (area.y()+area.h()).minus(a), area.w(), a],
[area.x(), area.y(), area.w(), area.h().minus(a)],
),
South => (
[area.x(), area.y(), area.w(), a],
[area.x(), area.y() + a, area.w(), area.h().minus(a)],
),
East => (
[area.x(), area.y(), a, area.h()],
[area.x() + a, area.y(), area.w().minus(a), area.h()],
),
West => (
[area.x() + area.w() - a, area.y(), a, area.h()],
[area.x(), area.y(), area.w() - a, area.h()],
),
North => ([x, (y+h).minus(a), w, a], [x, y, w, h.minus(a)]),
South => ([x, y, w, a], [x, y + a, w, h.minus(a)]),
East => ([x, y, a, h], [x + a, y, w.minus(a), h]),
West => ([(x+w).minus(a), y, a, h], [x, y, w - a, h]),
Above | Below => (area.xywh(), area.xywh())
}
}
}
pub struct Bsp<E: Engine, X: Content<E>, Y: Content<E>>(Direction, X, Y, PhantomData<E>);
impl<E: Engine, A: Content<E>, B: Content<E>> Bsp<E, A, B> {
pub fn n (a: A, b: B) -> Self { Self(North, a, b, Default::default()) }
pub fn s (a: A, b: B) -> Self { Self(South, a, b, Default::default()) }
pub fn e (a: A, b: B) -> Self { Self(East, a, b, Default::default()) }
pub fn w (a: A, b: B) -> Self { Self(West, a, b, Default::default()) }
pub fn a (a: A, b: B) -> Self { Self(Above, a, b, Default::default()) }
pub fn b (a: A, b: B) -> Self { Self(Below, a, b, Default::default()) }
pub fn contents (&self) -> (&A, &B) { (&self.1, &self.2) }
pub fn areas (&self, outer: E::Area) -> [E::Area;2] {
let [x, y, w, h] = outer.xywh();
let (a, b) = self.contents();
let a = a.layout(outer);
let b = match self.0 {
North => b.layout([x, y, w, h.minus(a.h())].into()),
South => b.layout([x, y + a.h(), w, h.minus(a.h())].into()),
East => b.layout([x + a.w(), y, w.minus(a.w()), h].into()),
West => b.layout([x, y, w.minus(a.w()), h].into()),
Above | Below => b.layout(outer),
};
[a, b]
}
}
impl<E: Engine, A: Content<E>, B: Content<E>> Content<E> for Bsp<E, A, B> {
fn layout (&self, outer: E::Area) -> E::Area {
let [a, b] = self.areas(outer);
let [ax, ay, aw, ah] = a.xywh();
let [bx, by, bw, bh] = b.xywh();
match self.0 {
North | South => [ax.min(bx), ay.min(by), aw.max(bw), ah + bh ],
East | West => [ax.min(bx), ay.min(by), aw + bw, ah.max(bh)],
Above | Below => [ax.min(bx), ay.min(by), aw.max(bw), ah.max(bh)],
}.into()
}
fn render (&self, to: &mut E::Output) {
let [area_a, area_b] = self.areas(to.area());
let (a, b) = self.contents();
to.place(area_a, a);
to.place(area_b, b);
}
}
/// Renders multiple things on top of each other,
#[macro_export] macro_rules! lay {
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::b(bsp, $expr);)*; bsp }}
}
/// Stack southward.
#[macro_export] macro_rules! col {
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::s(bsp, $expr);)*; bsp }};
}
/// Stack northward.
#[macro_export] macro_rules! col_up {
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::n(bsp, $expr);)*; bsp }}
}
/// Stack eastward.
#[macro_export] macro_rules! row {
($($expr:expr),* $(,)?) => {{ let bsp = (); $(let bsp = Bsp::e(bsp, $expr);)*; bsp }};
}

View file

@ -1,7 +1,6 @@
//mod collection; pub use self::collection::*;
mod align; pub use self::align::*;
mod bsp; pub use self::bsp::*;
mod direction; pub use self::direction::*;
mod measure; pub use self::measure::*;
mod ops; pub use self::ops::*;