Skip to content

Commit

Permalink
WIP Change project to use Point
Browse files Browse the repository at this point in the history
  • Loading branch information
jdahlstrom committed Dec 4, 2024
1 parent 05a3ed4 commit bbe5b32
Show file tree
Hide file tree
Showing 16 changed files with 208 additions and 102 deletions.
4 changes: 4 additions & 0 deletions core/src/geom.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Basic geometric primitives.
use crate::math::point::Point3;
use crate::math::vec::{Vec2, Vec3};

use crate::render::Model;
pub use mesh::Mesh;

pub mod mesh;
Expand All @@ -13,6 +15,8 @@ pub struct Vertex<P, A> {
pub attrib: A,
}

pub type Vertex3<A, B = Model> = Vertex<Point3<B>, A>;

/// Triangle, defined by three vertices.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)]
Expand Down
30 changes: 14 additions & 16 deletions core/src/geom/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,12 @@ use alloc::{vec, vec::Vec};

use crate::math::{
mat::{Mat4x4, RealToReal},
point::Point3,
space::Linear,
vec::Vec3,
};
use crate::render::Model;

use super::{vertex, Normal3, Tri};

/// Convenience type alias for a mesh vertex.
pub type Vertex<A, B = Model> = super::Vertex<Vec3<B>, A>;
use super::{vertex, Normal3, Tri, Vertex3};

/// A triangle mesh.
///
Expand All @@ -32,7 +29,7 @@ pub struct Mesh<Attrib, Basis = Model> {
/// to the `verts` vector. Several faces can share a vertex.
pub faces: Vec<Tri<usize>>,
/// The vertices of the mesh.
pub verts: Vec<Vertex<Attrib, Basis>>,
pub verts: Vec<Vertex3<Attrib, Basis>>,
}

/// A builder type for creating meshes.
Expand All @@ -54,16 +51,17 @@ impl<A, B> Mesh<A, B> {
/// # Examples
/// ```
/// # use retrofire_core::geom::{Tri, Mesh, vertex};
/// # use retrofire_core::math::vec3;
/// # use retrofire_core::math::point::pt3;
/// let verts = [
/// vec3(0.0, 0.0, 0.0),
/// vec3(1.0, 0.0, 0.0),
/// vec3(0.0, 1.0, 0.0),
/// vec3(0.0, 0.0, 1.0)
/// pt3(0.0, 0.0, 0.0),
/// pt3(1.0, 0.0, 0.0),
/// pt3(0.0, 1.0, 0.0),
/// pt3(0.0, 0.0, 1.0)
/// ]
/// .map(|v| vertex(v, ()));
///
/// let faces = [
/// // Indices point to the verts array
/// Tri([0, 1, 2]),
/// Tri([0, 1, 3]),
/// Tri([0, 2, 3]),
Expand All @@ -78,7 +76,7 @@ impl<A, B> Mesh<A, B> {
pub fn new<F, V>(faces: F, verts: V) -> Self
where
F: IntoIterator<Item = Tri<usize>>,
V: IntoIterator<Item = Vertex<A, B>>,
V: IntoIterator<Item = Vertex3<A, B>>,
{
let faces: Vec<_> = faces.into_iter().collect();
let verts: Vec<_> = verts.into_iter().collect();
Expand Down Expand Up @@ -129,16 +127,16 @@ impl<A> Builder<A> {
}

/// Appends a vertex with the given position and attribute.
pub fn push_vert(&mut self, pos: Vec3, attrib: A) {
pub fn push_vert(&mut self, pos: Point3, attrib: A) {
self.mesh.verts.push(vertex(pos.to(), attrib));
}

/// Appends all the vertices yielded by the given iterator.
pub fn push_verts<Vs>(&mut self, verts: Vs)
where
Vs: IntoIterator<Item = (Vec3, A)>,
Vs: IntoIterator<Item = (Point3, A)>,
{
let vs = verts.into_iter().map(|(v, a)| vertex(v.to(), a));
let vs = verts.into_iter().map(|(p, a)| vertex(p.to(), a));
self.mesh.verts.extend(vs);
}

Expand Down Expand Up @@ -167,7 +165,7 @@ impl Builder<()> {
.mesh
.verts
.into_iter()
.map(|v| vertex(tf.apply(&v.pos), v.attrib))
.map(|v| vertex(tf.apply_pt(&v.pos), v.attrib))
.collect(),
};
mesh.into_builder()
Expand Down
12 changes: 10 additions & 2 deletions core/src/math/mat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

//! Matrices and linear transforms.
use crate::math::point::Point3;
use core::array;
use core::fmt::{self, Debug, Formatter};
use core::marker::PhantomData;
Expand Down Expand Up @@ -218,6 +219,13 @@ impl<Src, Dst> Mat4x4<RealToReal<3, Src, Dst>> {
/// ```
#[must_use]
pub fn apply(&self, v: &Vec3<Src>) -> Vec3<Dst> {
let v = [v.x(), v.y(), v.z(), 1.0].into(); // TODO w=0.0
array::from_fn(|i| self.row_vec(i).dot(&v)).into()
}

// TODO Add trait to overload apply or similar
#[must_use]
pub fn apply_pt(&self, v: &Point3<Src>) -> Point3<Dst> {
let v = [v.x(), v.y(), v.z(), 1.0].into();
array::from_fn(|i| self.row_vec(i).dot(&v)).into()
}
Expand Down Expand Up @@ -365,8 +373,8 @@ impl<Src> Mat4x4<RealToProj<Src>> {
/// \ · · M33 / \ 1 /
/// ```
#[must_use]
pub fn apply(&self, v: &Vec3<Src>) -> ProjVec4 {
let v = Vector::from([v.x(), v.y(), v.z(), 1.0]);
pub fn apply(&self, p: &Point3<Src>) -> ProjVec4 {
let v = Vector::from([p.x(), p.y(), p.z(), 1.0]);
[
self.row_vec(0).dot(&v),
self.row_vec(1).dot(&v),
Expand Down
69 changes: 66 additions & 3 deletions core/src/math/point.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
use core::{array, marker::PhantomData as Pd, ops::Index};

use crate::math::{space::Affine, space::Real, vec::Vector, Linear};
use core::{
array,
fmt::Debug,
fmt::Formatter,
marker::PhantomData as Pd,
ops::{Add, Index, Sub},
};

use crate::math::{
space::{Affine, Linear, Real},
vec::Vector,
};

#[repr(transparent)]
pub struct Point<Repr, Space = ()>(pub Repr, Pd<Space>);
Expand All @@ -10,6 +19,9 @@ pub type Point2<Basis = ()> = Point<[f32; 2], Real<2, Basis>>;
/// A 3-point with `f32` components.
pub type Point3<Basis = ()> = Point<[f32; 3], Real<3, Basis>>;

/// A 2-point with `u32` components.
pub type Point2u<Basis = ()> = Point<[u32; 2], Real<2, Basis>>;

/// Returns a real 2-point with `x` and `y` components.
pub const fn pt2<Sc, B>(x: Sc, y: Sc) -> Point<[Sc; 2], Real<2, B>> {
Point([x, y], Pd)
Expand All @@ -24,6 +36,11 @@ impl<R, Sp> Point<R, Sp> {
pub fn new(repr: R) -> Self {
Self(repr, Pd)
}

#[inline]
pub fn to<T>(self) -> Point<R, T> {
Point(self.0, Pd)
}
}

impl<const N: usize, B> Point<[f32; N], Real<N, B>> {
Expand All @@ -36,6 +53,23 @@ impl<const N: usize, B> Point<[f32; N], Real<N, B>> {
pub fn distance_sqr(&self, other: &Self) -> f32 {
Affine::sub(self, other).len_sqr()
}

/// Returns `self` clamped component-wise to the given range.
///
/// In other words, for each component `self[i]`, the result `r` has
/// `r[i]` equal to `self[i].clamp(min[i], max[i])`.
///
/// # Examples
/// ```
/// # use retrofire_core::math::point::{pt3, Point3};
/// let pt = pt3(0.5, 1.5, -2.0);
/// // Clamp to the unit cube
/// let pt = pt.clamp(&pt3(0.0, 0.0, 0.0), &pt3(1.0, 1.0, 1.0));
/// assert_eq!(v, pt3(0.5, 1.0, -1.0));
#[must_use]
pub fn clamp(&self, min: &Self, max: &Self) -> Self {
array::from_fn(|i| self.0[i].clamp(min.0[i], max.0[i])).into()
}
}

impl<R, B, Sc> Point<R, Real<2, B>>
Expand Down Expand Up @@ -117,6 +151,13 @@ impl<R: Default, S> Default for Point<R, S> {
}
}

impl<R: Debug, Sp: Debug + Default> Debug for Point<R, Sp> {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
write!(f, "Point<{:?}>", Sp::default())?;
Debug::fmt(&self.0, f)
}
}

impl<R: Eq, S> Eq for Point<R, S> {}

impl<R: PartialEq, S> PartialEq for Point<R, S> {
Expand All @@ -131,3 +172,25 @@ impl<R, Sp> From<R> for Point<R, Sp> {
Self(repr, Pd)
}
}

impl<R, Sp> Add<<Self as Affine>::Diff> for Point<R, Sp>
where
Self: Affine,
{
type Output = Self;

fn add(self, other: <Self as Affine>::Diff) -> Self {
Affine::add(&self, &other)
}
}

impl<R, Sp> Sub for Point<R, Sp>
where
Self: Affine,
{
type Output = <Self as Affine>::Diff;

fn sub(self, other: Self) -> Self::Output {
Affine::sub(&self, &other)
}
}
6 changes: 3 additions & 3 deletions core/src/math/space.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ impl Affine for u32 {

impl<V: Clone> Vary for V
where
Self: Linear<Scalar = f32>,
Self: Affine<Diff: Linear<Scalar = f32> + Clone>,
{
type Iter = Iter<Self>;
type Diff = <Self as Affine>::Diff;
Expand All @@ -178,8 +178,8 @@ where
self.add(delta)
}

fn z_div(&self, z: f32) -> Self {
self.mul(z.recip())
fn z_div(&self, _z: f32) -> Self {
todo!()
}
}

Expand Down
49 changes: 30 additions & 19 deletions core/src/math/spline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use alloc::vec::Vec;

use crate::math::space::Linear;
use crate::math::Vary;
use crate::math::{Affine, Vary};

/// A cubic Bezier curve, defined by four control points.
///
Expand Down Expand Up @@ -75,7 +75,7 @@ where
}
impl<T> CubicBezier<T>
where
T: Linear<Scalar = f32> + Clone,
T: Affine<Diff: Linear<Scalar = f32>> + Clone,
{
pub fn fast_eval(&self, t: f32) -> T {
let [p0, p1, p2, p3] = &self.0;
Expand All @@ -84,32 +84,40 @@ where
// + (p0 + p2) * 3t^2 - p1 * 6t^2
// + (p1 - p0) * 3t
// + p0
// = ((p3 - p0 + 3(p1 - p2)) * t^3
// + 3(p0 + p2 - 2p1) * t^2
// + 3(p1 - p0) * t
// + p0
// = ((((p3 - p0 + 3(p1 - p2))) * t
// + 3(p0 - p1 + p2 - p1)) * t)
// + 3(p1 - p0)) * t)
// + p0

let term3 = &p1.sub(p2).mul(3.0).add(&p3.sub(p0)).mul(t);
let term2 = &p1.mul(-2.0).add(p0).add(p2).mul(3.0);
let term1 = &p1.sub(p0).mul(3.0 * t);
let term0 = p0;
let co3: &T::Diff = &p3.add(&p1.sub(p2).mul(3.0)).sub(p0);
let co2: &T::Diff = &p0.sub(p1).add(&p2.sub(p1)).mul(3.0);
let co1: &T::Diff = &p1.sub(p0).mul(3.0);
let co0: &T = p0;

term3.add(term2).mul(t * t).add(term1).add(term0)
co0.add(&co3.mul(t).add(co2).mul(t).add(co1).mul(t))
})
}

/// Returns the tangent, or direction vector, of `self` at `t`.
///
/// Clamps `t` to the range [0, 1].
pub fn tangent(&self, t: f32) -> T {
pub fn tangent(&self, t: f32) -> T::Diff {
let [p0, p1, p2, p3] = &self.0;
let t = t.clamp(0.0, 1.0);

// (p1 - p2) * 9t^2 + (p3 - p0) * 3t^2
// + (p0 + p2) * 6t - p1 * 12t
// + (p1 - p0) * 3
// 3 (3 (p1 - p2) + (p3 - p0)) * t^2
// + 6 ((p0 - p1 + p2 - p1) * t
// + 3 (p1 - p0)

let term2 = p1.sub(p2).mul(3.0).add(&p3.sub(p0)).mul(t * t);
let term1 = p1.mul(-2.0).add(p0).add(p2).mul(2.0 * t);
let term0 = p1.sub(p0);
let co2: T::Diff = p1.sub(p2).mul(3.0).add(&p3.sub(p0));
let co1: T::Diff = p0.sub(p1).add(&p2.sub(p1)).mul(2.0);
let co0: T::Diff = p1.sub(p0);

term2.add(&term1).add(&term0).mul(3.0)
co2.mul(t).add(&co1).mul(t).add(&co0).mul(3.0)
}
}

Expand All @@ -118,7 +126,10 @@ where
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct BezierSpline<T>(Vec<T>);

impl<T: Linear<Scalar = f32> + Copy> BezierSpline<T> {
impl<T> BezierSpline<T>
where
T: Affine<Diff: Linear<Scalar = f32> + Copy> + Copy,
{
/// Creates a bezier curve from the given control points. The number of
/// elements in `pts` must be 3n + 1 for some positive integer n.
///
Expand Down Expand Up @@ -153,7 +164,7 @@ impl<T: Linear<Scalar = f32> + Copy> BezierSpline<T> {
/// Returns the tangent of `self` at `t`.
///
/// Clamps `t` to the range [0, 1].
pub fn tangent(&self, t: f32) -> T {
pub fn tangent(&self, t: f32) -> T::Diff {
let (t, seg) = self.segment(t);
CubicBezier(seg).tangent(t)
}
Expand Down Expand Up @@ -201,7 +212,7 @@ impl<T: Linear<Scalar = f32> + Copy> BezierSpline<T> {
/// let approx = curve.approximate(|err| err.len_sqr() < 0.01*0.01);
/// assert_eq!(approx.len(), 17);
/// ```
pub fn approximate(&self, halt: impl Fn(&T) -> bool) -> Vec<T> {
pub fn approximate(&self, halt: impl Fn(&T::Diff) -> bool) -> Vec<T> {
let len = self.0.len();
let mut res = Vec::with_capacity(3 * len);
self.do_approx(0.0, 1.0, 10 + len.ilog2(), &halt, &mut res);
Expand All @@ -214,7 +225,7 @@ impl<T: Linear<Scalar = f32> + Copy> BezierSpline<T> {
a: f32,
b: f32,
max_dep: u32,
halt: &impl Fn(&T) -> bool,
halt: &impl Fn(&T::Diff) -> bool,
accum: &mut Vec<T>,
) {
let mid = a.lerp(&b, 0.5);
Expand Down
Loading

0 comments on commit bbe5b32

Please sign in to comment.