diff --git a/core/src/geom.rs b/core/src/geom.rs index d0b5208c..0fca2e26 100644 --- a/core/src/geom.rs +++ b/core/src/geom.rs @@ -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; @@ -13,6 +15,8 @@ pub struct Vertex { pub attrib: A, } +pub type Vertex3 = Vertex, A>; + /// Triangle, defined by three vertices. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[repr(transparent)] diff --git a/core/src/geom/mesh.rs b/core/src/geom/mesh.rs index ce204d5b..e2860256 100644 --- a/core/src/geom/mesh.rs +++ b/core/src/geom/mesh.rs @@ -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 = super::Vertex, A>; +use super::{vertex, Normal3, Tri, Vertex3}; /// A triangle mesh. /// @@ -32,7 +29,7 @@ pub struct Mesh { /// to the `verts` vector. Several faces can share a vertex. pub faces: Vec>, /// The vertices of the mesh. - pub verts: Vec>, + pub verts: Vec>, } /// A builder type for creating meshes. @@ -54,16 +51,17 @@ impl Mesh { /// # 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]), @@ -78,7 +76,7 @@ impl Mesh { pub fn new(faces: F, verts: V) -> Self where F: IntoIterator>, - V: IntoIterator>, + V: IntoIterator>, { let faces: Vec<_> = faces.into_iter().collect(); let verts: Vec<_> = verts.into_iter().collect(); @@ -129,16 +127,16 @@ impl Builder { } /// 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(&mut self, verts: Vs) where - Vs: IntoIterator, + Vs: IntoIterator, { - 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); } @@ -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() diff --git a/core/src/math/mat.rs b/core/src/math/mat.rs index 9a19e2e4..4ec04163 100644 --- a/core/src/math/mat.rs +++ b/core/src/math/mat.rs @@ -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; @@ -218,6 +219,13 @@ impl Mat4x4> { /// ``` #[must_use] pub fn apply(&self, v: &Vec3) -> Vec3 { + 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) -> Point3 { let v = [v.x(), v.y(), v.z(), 1.0].into(); array::from_fn(|i| self.row_vec(i).dot(&v)).into() } @@ -365,8 +373,8 @@ impl Mat4x4> { /// \ · · M33 / \ 1 / /// ``` #[must_use] - pub fn apply(&self, v: &Vec3) -> ProjVec4 { - let v = Vector::from([v.x(), v.y(), v.z(), 1.0]); + pub fn apply(&self, p: &Point3) -> 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), diff --git a/core/src/math/point.rs b/core/src/math/point.rs index 6a1a5c9a..63dd593a 100644 --- a/core/src/math/point.rs +++ b/core/src/math/point.rs @@ -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(pub Repr, Pd); @@ -10,6 +19,9 @@ pub type Point2 = Point<[f32; 2], Real<2, Basis>>; /// A 3-point with `f32` components. pub type Point3 = Point<[f32; 3], Real<3, Basis>>; +/// A 2-point with `u32` components. +pub type Point2u = Point<[u32; 2], Real<2, Basis>>; + /// Returns a real 2-point with `x` and `y` components. pub const fn pt2(x: Sc, y: Sc) -> Point<[Sc; 2], Real<2, B>> { Point([x, y], Pd) @@ -24,6 +36,11 @@ impl Point { pub fn new(repr: R) -> Self { Self(repr, Pd) } + + #[inline] + pub fn to(self) -> Point { + Point(self.0, Pd) + } } impl Point<[f32; N], Real> { @@ -36,6 +53,23 @@ impl Point<[f32; N], Real> { 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 Point> @@ -117,6 +151,13 @@ impl Default for Point { } } +impl Debug for Point { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + write!(f, "Point<{:?}>", Sp::default())?; + Debug::fmt(&self.0, f) + } +} + impl Eq for Point {} impl PartialEq for Point { @@ -131,3 +172,25 @@ impl From for Point { Self(repr, Pd) } } + +impl Add<::Diff> for Point +where + Self: Affine, +{ + type Output = Self; + + fn add(self, other: ::Diff) -> Self { + Affine::add(&self, &other) + } +} + +impl Sub for Point +where + Self: Affine, +{ + type Output = ::Diff; + + fn sub(self, other: Self) -> Self::Output { + Affine::sub(&self, &other) + } +} diff --git a/core/src/math/space.rs b/core/src/math/space.rs index 5475dda9..ecdf7768 100644 --- a/core/src/math/space.rs +++ b/core/src/math/space.rs @@ -158,7 +158,7 @@ impl Affine for u32 { impl Vary for V where - Self: Linear, + Self: Affine + Clone>, { type Iter = Iter; type Diff = ::Diff; @@ -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!() } } diff --git a/core/src/math/spline.rs b/core/src/math/spline.rs index 796e1755..edd13022 100644 --- a/core/src/math/spline.rs +++ b/core/src/math/spline.rs @@ -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. /// @@ -75,7 +75,7 @@ where } impl CubicBezier where - T: Linear + Clone, + T: Affine> + Clone, { pub fn fast_eval(&self, t: f32) -> T { let [p0, p1, p2, p3] = &self.0; @@ -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) } } @@ -118,7 +126,10 @@ where #[derive(Debug, Clone, Eq, PartialEq)] pub struct BezierSpline(Vec); -impl + Copy> BezierSpline { +impl BezierSpline +where + T: Affine + 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. /// @@ -153,7 +164,7 @@ impl + Copy> BezierSpline { /// 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) } @@ -201,7 +212,7 @@ impl + Copy> BezierSpline { /// 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 { + pub fn approximate(&self, halt: impl Fn(&T::Diff) -> bool) -> Vec { 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); @@ -214,7 +225,7 @@ impl + Copy> BezierSpline { a: f32, b: f32, max_dep: u32, - halt: &impl Fn(&T) -> bool, + halt: &impl Fn(&T::Diff) -> bool, accum: &mut Vec, ) { let mid = a.lerp(&b, 0.5); diff --git a/core/src/math/vec.rs b/core/src/math/vec.rs index 55737e7a..fae809a3 100644 --- a/core/src/math/vec.rs +++ b/core/src/math/vec.rs @@ -11,6 +11,7 @@ use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign}; use crate::math::approx::ApproxEq; use crate::math::float::f32; +use crate::math::point::Point; use crate::math::space::{Affine, Linear, Proj4, Real}; // @@ -97,7 +98,13 @@ impl Vector { // TODO Cannot be const (yet?) due to E0493 :( #[inline] pub fn to(self) -> Vector { - Vector::new(self.0) + Vector(self.0, Pd) + } + + /// Returns the affine point equivalent to `self`. + #[inline] + pub fn to_pt(self) -> Point { + Point::new(self.0) } } @@ -329,6 +336,7 @@ where Sc::Diff: Linear + Copy, { type Space = Sp; + // TODO Vectors always Linear once Point used for affine stuff type Diff = Vector<[Sc::Diff; DIM], Sp>; /// The dimension (number of components) of `Self`. diff --git a/core/src/render.rs b/core/src/render.rs index ffc14e3e..0a5e2816 100644 --- a/core/src/render.rs +++ b/core/src/render.rs @@ -15,6 +15,7 @@ use crate::math::{ vec::{vec3, ProjVec4, Vec3}, }; +use crate::math::point::pt3; use clip::{view_frustum, Clip, ClipVert}; use ctx::{Context, DepthSort, FaceCull}; use raster::tri_fill; @@ -126,19 +127,19 @@ pub fn render( for Tri(vs) in clipped { // Transform to screen space let vs = vs.map(|v| { - let [x, y, _, w] = v.pos.0; // Perspective division (projection to the real plane) // // We use the screen-space z coordinate to store the reciprocal // of the original view-space depth. The interpolated reciprocal // is used in fragment processing for depth testing (larger values // are closer) and for perspective correction of the varyings. - let pos = vec3(x, y, 1.0).z_div(w); + let [x, y, ..] = (v.pos / v.pos.w()).0; + let pos = pt3(x, y, 1.0); Vertex { // Viewport transform - pos: to_screen.apply(&pos), + pos: to_screen.apply_pt(&pos), // Perspective correction - attrib: v.attrib.z_div(w), + attrib: v.attrib.z_div(v.pos.w()), } }); diff --git a/core/src/render/batch.rs b/core/src/render/batch.rs index 9de94c1e..58eff8f4 100644 --- a/core/src/render/batch.rs +++ b/core/src/render/batch.rs @@ -3,7 +3,7 @@ use alloc::vec::Vec; use core::borrow::Borrow; -use crate::geom::{mesh, Mesh, Tri}; +use crate::geom::{Mesh, Tri, Vertex3}; use crate::math::{mat::Mat4x4, vary::Vary}; use super::{ctx::Context, target::Target, NdcToScreen, Shader}; @@ -77,7 +77,7 @@ impl Batch { pub fn mesh( self, mesh: &Mesh, - ) -> Batch, Uni, Shd, Tgt, Ctx> { + ) -> Batch, Uni, Shd, Tgt, Ctx> { let faces = mesh.faces.clone(); let verts = mesh.verts.clone(); update!(verts faces; self uniform shader viewport target ctx) diff --git a/core/src/util/buf.rs b/core/src/util/buf.rs index 3acc4070..e67ae76a 100644 --- a/core/src/util/buf.rs +++ b/core/src/util/buf.rs @@ -347,6 +347,7 @@ pub mod inner { ops::{Deref, DerefMut, Index, IndexMut, Range}, }; + use crate::math::point::Point2u; use crate::{math::vec::Vec2u, util::rect::Rect, util::Dims}; use super::{AsSlice2, MutSlice2, Slice2}; @@ -662,7 +663,7 @@ pub mod inner { impl Index for Inner where D: Deref, - Pos: Into, + Pos: Into, { type Output = T; @@ -680,7 +681,7 @@ pub mod inner { impl IndexMut for Inner where D: DerefMut, - Pos: Into, + Pos: Into, { /// Returns a mutable reference to the element at position `pos`. /// diff --git a/demos/src/bin/bezier.rs b/demos/src/bin/bezier.rs index d647c7d1..370b32b6 100644 --- a/demos/src/bin/bezier.rs +++ b/demos/src/bin/bezier.rs @@ -1,15 +1,16 @@ +use re::math::point::{pt2, Point2, Point2u}; use std::mem::swap; use std::ops::ControlFlow::Continue; use re::math::rand::{Distrib, Uniform, UnitDisk, Xorshift64}; use re::math::spline::BezierSpline; use re::prelude::*; -use re::util::Dims; +use re_front::dims::SVGA_800_600; use re_front::minifb::Window; use re_front::Frame; -fn line([mut p0, mut p1]: [Vec2; 2]) -> impl Iterator { +fn line([mut p0, mut p1]: [Point2; 2]) -> impl Iterator { if p0.y() > p1.y() { swap(&mut p0, &mut p1); } @@ -23,11 +24,11 @@ fn line([mut p0, mut p1]: [Vec2; 2]) -> impl Iterator { }; p0.vary(step, Some(n as u32)) - .map(|p| vec2(p.x() as u32, p.y() as u32)) + .map(|p| pt2(p.x() as u32, p.y() as u32)) } fn main() { - let dims @ (w, h) = (640, 480); + let dims @ (w, h) = SVGA_800_600; let mut win = Window::builder() .title("retrofire//bezier") @@ -39,8 +40,11 @@ fn main() { let pos = Uniform(vec2(0.0, 0.0)..vec2(w as f32, h as f32)); let vel = UnitDisk; - let (mut pts, mut deltas): (Vec, Vec) = - (pos, vel).samples(rng).take(4).unzip(); + let (mut pts, mut deltas): (Vec, Vec) = (pos, vel) + .samples(rng) + .take(4) + .map(|(p, v)| (p.to_pt(), v)) + .unzip(); win.run(|Frame { dt, buf, .. }| { let b = BezierSpline::new(&pts); @@ -54,16 +58,16 @@ fn main() { } } - let max = vec2((w - 1) as f32, (h - 1) as f32); + let max = pt2((w - 1) as f32, (h - 1) as f32); let secs = dt.as_secs_f32(); for (p, d) in pts.iter_mut().zip(deltas.iter_mut()) { - *p = (*p + *d * 200.0 * secs).clamp(&Vec2::zero(), &max); - - if p[0] == 0.0 || p[0] == max.x() { - d[0] = -d[0]; + *p = (*p + *d * 200.0 * secs).clamp(&pt2(0.0, 0.0), &max); + let [dx, dy] = &mut d.0; + if p.x() == 0.0 || p.x() == max.x() { + *dx = -*dx; } - if p[1] == 0.0 || p[1] == max.y() { - d[1] = -d[1]; + if p.y() == 0.0 || p.y() == max.y() { + *dy = -*dy; } } Continue(()) diff --git a/demos/src/bin/crates.rs b/demos/src/bin/crates.rs index a600cf6c..b8b04bd4 100644 --- a/demos/src/bin/crates.rs +++ b/demos/src/bin/crates.rs @@ -3,6 +3,7 @@ use core::ops::ControlFlow::*; use re::prelude::*; use re::math::color::gray; +use re::math::point::pt3; use re::render::{ batch::Batch, cam::{Camera, FirstPerson}, @@ -119,7 +120,7 @@ fn floor() -> Mesh { for i in -size..=size { let even_odd = ((i & 1) ^ (j & 1)) == 1; - let pos = vec3(i as f32, -1.0, j as f32); + let pos = pt3(i as f32, -1.0, j as f32); let col = if even_odd { gray(0.2) } else { gray(0.9) }; bld.push_vert(pos, col); diff --git a/demos/src/bin/solids.rs b/demos/src/bin/solids.rs index 4b347769..0dcedeea 100644 --- a/demos/src/bin/solids.rs +++ b/demos/src/bin/solids.rs @@ -1,14 +1,16 @@ use core::ops::ControlFlow::Continue; use minifb::{Key, KeyRepeat}; +use re::geom::Vertex3; use re::prelude::*; use re::math::{ - color::gray, mat::RealToReal, spline::smootherstep, vec::ProjVec4, + color::gray, mat::RealToReal, point::pt2, spline::smootherstep, + vec::ProjVec4, }; use re::render::batch::Batch; -use re::render::{cam::Camera, Model, ModelToProj, ModelToWorld}; +use re::render::{cam::Camera, ModelToProj, ModelToWorld}; use re_front::{minifb::Window, Frame}; use re_geom::{io::parse_obj, solids::*}; @@ -62,7 +64,7 @@ fn main() { .perspective(1.5, 0.1..1000.0) .viewport(vec2(10, 10)..vec2(w - 10, h - 10)); - type VertexIn = Vertex, Normal3>; + type VertexIn = Vertex3; type VertexOut = Vertex; type Uniform<'a> = (&'a Mat4x4, &'a Mat4x4>); @@ -156,11 +158,11 @@ fn objects(res: u32) -> [Mesh; 13] { fn lathe(secs: u32) -> Mesh { Lathe::new( vec![ - vertex(vec2(0.75, -0.5), vec2(1.0, 1.0)), - vertex(vec2(0.55, -0.25), vec2(1.0, 0.5)), - vertex(vec2(0.5, 0.0), vec2(1.0, 0.0)), - vertex(vec2(0.55, 0.25), vec2(1.0, -0.5)), - vertex(vec2(0.75, 0.5), vec2(1.0, 1.0)), + vertex(pt2(0.75, -0.5), vec2(1.0, 1.0)), + vertex(pt2(0.55, -0.25), vec2(1.0, 0.5)), + vertex(pt2(0.5, 0.0), vec2(1.0, 0.0)), + vertex(pt2(0.55, 0.25), vec2(1.0, -0.5)), + vertex(pt2(0.75, 0.5), vec2(1.0, 1.0)), ], secs, ) diff --git a/demos/src/bin/square.rs b/demos/src/bin/square.rs index 880c4c71..56a04e66 100644 --- a/demos/src/bin/square.rs +++ b/demos/src/bin/square.rs @@ -2,15 +2,17 @@ use std::ops::ControlFlow::*; use re::prelude::*; -use re::render::{ctx::Context, render, tex::SamplerClamp, Model, ModelToProj}; +use re::geom::Vertex3; +use re::math::point::pt3; +use re::render::{ctx::Context, render, tex::SamplerClamp, ModelToProj}; use re_front::minifb::Window; fn main() { - let verts: [Vertex, TexCoord>; 4] = [ - vertex(vec3(-1.0, -1.0, 0.0), uv(0.0, 0.0)), - vertex(vec3(-1.0, 1.0, 0.0), uv(0.0, 1.0)), - vertex(vec3(1.0, -1.0, 0.0), uv(1.0, 0.0)), - vertex(vec3(1.0, 1.0, 0.0), uv(1.0, 1.0)), + let verts: [Vertex3; 4] = [ + vertex(pt3(-1.0, -1.0, 0.0), uv(0.0, 0.0)), + vertex(pt3(-1.0, 1.0, 0.0), uv(0.0, 1.0)), + vertex(pt3(1.0, -1.0, 0.0), uv(1.0, 0.0)), + vertex(pt3(1.0, 1.0, 0.0), uv(1.0, 1.0)), ]; let mut win = Window::builder() diff --git a/geom/src/io.rs b/geom/src/io.rs index f16b52d0..18a65b76 100644 --- a/geom/src/io.rs +++ b/geom/src/io.rs @@ -178,7 +178,9 @@ pub fn parse_obj(src: impl IntoIterator) -> Result> { .into_iter() .map(|Tri(vs)| Tri(vs.map(|i| i.pos))); - let verts = verts.into_iter().map(|pos| vertex(pos, ())); + let verts = verts + .into_iter() + .map(|pos| vertex(pos.to_pt(), ())); Ok(Mesh::new(faces, verts).into_builder()) } diff --git a/geom/src/solids.rs b/geom/src/solids.rs index eb3382a5..b795d5a7 100644 --- a/geom/src/solids.rs +++ b/geom/src/solids.rs @@ -6,11 +6,12 @@ use core::ops::Range; use alloc::{vec, vec::Vec}; use re::geom::{mesh::Builder, vertex, Mesh, Normal2, Normal3, Vertex}; +use re::math::point::{pt2, pt3, Point2, Point3}; use re::math::{ angle::{degs, polar, turns, Angle}, mat::rotate_y, vary::Vary, - vec::{splat, vec2, vec3, Vec2, Vec3}, + vec::{splat, vec2, vec3, Vec3}, }; use re::render::tex::{uv, TexCoord}; @@ -100,7 +101,7 @@ pub struct Icosahedron; #[derive(Clone, Debug, Default)] pub struct Lathe { /// The polyline defining the shape. - pub pts: Vec>, + pub pts: Vec>, /// The number of facets used to approximate the surface of revolution. pub sectors: u32, /// Whether to add flat caps to both ends of the object. Has no effect @@ -174,7 +175,7 @@ impl Tetrahedron { for (i, vs) in Self::FACES.into_iter().enumerate() { b.push_face(3 * i, 3 * i + 1, 3 * i + 2); for v in vs { - b.push_vert(coords[v], norms[i]); + b.push_vert(coords[v].to_pt(), norms[i]); } } b.build() @@ -260,13 +261,13 @@ impl Box { } impl Octahedron { - const COORDS: [Vec3; 6] = [ - vec3(-1.0, 0.0, 0.0), - vec3(0.0, -1.0, 0.0), - vec3(0.0, 0.0, -1.0), - vec3(0.0, 1.0, 0.0), - vec3(0.0, 0.0, 1.0), - vec3(1.0, 0.0, 0.0), + const COORDS: [Point3; 6] = [ + pt3(-1.0, 0.0, 0.0), + pt3(0.0, -1.0, 0.0), + pt3(0.0, 0.0, -1.0), + pt3(0.0, 1.0, 0.0), + pt3(0.0, 0.0, 1.0), + pt3(1.0, 0.0, 0.0), ]; const NORMS: [Normal3; 8] = [ vec3(-1.0, -1.0, -1.0), @@ -377,7 +378,7 @@ impl Dodecahedron { b.push_face(i5, i5 + 2, i5 + 3); b.push_face(i5, i5 + 3, i5 + 4); for &j in face { - b.push_vert(Self::COORDS[j].normalize(), n); + b.push_vert(Self::COORDS[j].normalize().to_pt(), n); } } b.build() @@ -422,7 +423,7 @@ impl Icosahedron { let n = Self::NORMALS[i].normalize(); b.push_face(3 * i, 3 * i + 1, 3 * i + 2); for vi in *vs { - b.push_vert(Self::COORDS[vi].normalize(), n); + b.push_vert(Self::COORDS[vi].normalize().to_pt(), n); } } b.build() @@ -430,7 +431,7 @@ impl Icosahedron { } impl Lathe { - pub fn new(pts: Vec>, sectors: u32) -> Self { + pub fn new(pts: Vec>, sectors: u32) -> Self { assert!(sectors >= 3, "sectors must be at least 3, was {sectors}"); Self { pts, @@ -461,12 +462,12 @@ impl Lathe { // Create vertices for Vertex { pos, attrib: n } in &pts { - let mut pos = start.apply(&vec3(pos.x(), pos.y(), 0.0)); + let mut pos = start.apply_pt(&pt3(pos.x(), pos.y(), 0.0)); let mut norm = start.apply(&vec3(n.x(), n.y(), 0.0)).normalize(); for _ in 0..=secs { b.push_vert(pos, norm); - pos = rot.apply(&pos); + pos = rot.apply_pt(&pos); norm = rot.apply(&norm); } } @@ -521,7 +522,7 @@ impl Sphere { let pts = degs(-90.0) .vary_to(degs(90.0), segments) .map(|alt| polar(radius, alt).to_cart()) - .map(|pos| vertex(pos, pos)) + .map(|pos| vertex(pos.to_pt(), pos)) .collect(); Lathe::new(pts, sectors).build() @@ -534,7 +535,7 @@ impl Torus { let pts = turns(0.0) .vary_to(turns(1.0), self.minor_sectors) .map(|alt| polar(self.minor_radius, alt).to_cart()) - .map(|v| vertex(vec2(self.major_radius, 0.0) + v, v)) + .map(|v| vertex(pt2(self.major_radius, 0.0) + v, v)) .collect(); Lathe::new(pts, self.major_sectors).build() @@ -558,8 +559,8 @@ impl Cylinder { impl Cone { /// Builds the conical mesh. pub fn build(self) -> Mesh { - let base_pt = vec2(self.base_radius, -1.0); - let apex_pt = vec2(self.apex_radius, 1.0); + let base_pt = pt2(self.base_radius, -1.0); + let apex_pt = pt2(self.apex_radius, 1.0); let n = apex_pt - base_pt; let n = vec2(n.y(), -n.x()); let pts = vec![vertex(base_pt, n), vertex(apex_pt, n)]; @@ -578,14 +579,14 @@ impl Capsule { let bottom_pts: Vec<_> = degs(-90.0) .vary_to(degs(0.0), cap_segments) .map(|alt| polar(radius, alt).to_cart()) - .map(|v| vertex(vec2(0.0, -1.0) + v, v)) + .map(|v| vertex(pt2(0.0, -1.0) + v, v)) .collect(); // Top hemisphere let top_pts = bottom_pts .iter() .map(|Vertex { pos, attrib: n }| { - vertex(vec2(pos.x(), -pos.y()), vec2(n.x(), -n.y())) + vertex(pt2(pos.x(), -pos.y()), vec2(n.x(), -n.y())) }) .rev();