Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
4b57d3b
Depend on root Retrofire crate in demos
jdahlstrom Nov 2, 2025
6a6dabb
Add uniform distribs for u32 and usize
jdahlstrom Nov 2, 2025
f7ec08e
Add uniform distrib for colors
jdahlstrom Nov 2, 2025
1ebf545
Update READMEs, add screenshots
jdahlstrom Nov 3, 2025
fa2c1c5
Rename Mat4x4 to Mat4, same for 3 and 2
jdahlstrom Oct 27, 2025
a4e1ec0
Change matrix aliases to take source and dest spaces directly
jdahlstrom Oct 28, 2025
f7fefa0
Add new Distrib impls
jdahlstrom Nov 3, 2025
9b3ac6f
WIP Improve matrix doc comments and tests
jdahlstrom Nov 4, 2025
245553e
Fix rotation matrix handedness, very embarrassing
jdahlstrom Nov 4, 2025
103cd02
Add linear() and translation() methods to Mat4 and Mat3
jdahlstrom Nov 6, 2025
c2c3c4b
Fixup Clippy warning
jdahlstrom Nov 6, 2025
3daef4e
Bump version to 0.4.0 \o/
jdahlstrom Nov 6, 2025
118fb31
Add new() and map() methods to Color, constify methods, add inline at…
jdahlstrom Nov 8, 2025
e4c7b83
Add inherent apply<T>() method to Matrix where Self: Apply<T>
jdahlstrom Nov 8, 2025
d31964f
Use full package name rather than alias
jdahlstrom Nov 8, 2025
1379453
Implement Index and IndexMut for Color
jdahlstrom Nov 8, 2025
7bd773f
Make some Point and Vec functions more concrete to constify them
jdahlstrom Nov 8, 2025
fc4ce70
Customize benchmark profile
jdahlstrom Nov 8, 2025
94f5712
Add some inline attributes
jdahlstrom Nov 8, 2025
ca33df5
Monomorphize some things to reduce generics bloat
jdahlstrom Nov 8, 2025
fe0390c
Constify angle constructors, add Mul<Angle> for f32
jdahlstrom Nov 11, 2025
5312b57
Constify projection and viewport functions
jdahlstrom Nov 11, 2025
b1f6dad
Add Icosphere solid
jdahlstrom Nov 11, 2025
12378e0
Impl Uniform for Angle
jdahlstrom Nov 11, 2025
17d208f
Fix Frame::dt in minifb
jdahlstrom Nov 11, 2025
8f5d620
Fix HD_1280_720 resolution, add more resolutions
jdahlstrom Nov 11, 2025
587ff79
Re-export Frag, ProjVec3, ProjMat3
jdahlstrom Jun 6, 2025
fbe446f
Remove unnecessary Default bound from BBox
jdahlstrom Oct 19, 2025
810b3bc
Remove unnecessary fp feature gates
jdahlstrom Oct 27, 2025
b440cf9
Add Bezier approximation method that takes error value directly
jdahlstrom Oct 19, 2025
c9b1a3d
Allow wrapping render target in a RefCell for easier mutability
jdahlstrom Nov 12, 2025
18afce4
Fix SDL2 Builder::dims() to take a Dims
jdahlstrom Nov 12, 2025
effae8e
Fix minor portability issue in curses
jdahlstrom Nov 12, 2025
3d0e0bf
Add a few new pixel formats
jdahlstrom Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,37 @@ resolver = "2"

[workspace.package]
edition = "2024"
version = "0.4.0-pre4"
version = "0.4.0"
authors = ["Johannes 'Sharlin' Dahlström <johannes.dahlstrom@gmail.com>"]
license = "MIT OR Apache-2.0"
repository = "https://github.com/jdahlstrom/retrofire"
keywords = ["graphics", "gamedev", "demoscene", "retrocomputing", "rendering"]
categories = ["graphics", "game-development", "no-std"]

[workspace.lints.clippy]
manual_range_contains = "allow"
collapsible_if = "allow"
[workspace.lints]
clippy.manual_range_contains = "allow"
clippy.collapsible_if = "allow"

[features]
default = ["std"]
std = ["retrofire-core/std", "retrofire-geom/std"]

[dependencies]
retrofire-core = { version = "0.4.0-pre4", path = "core" }
retrofire-front = { version = "0.4.0-pre4", path = "front" }
retrofire-geom = { version = "0.4.0-pre4", path = "geom" }
retrofire-core = { version = "0.4.0", path = "core" }
retrofire-front = { version = "0.4.0", path = "front" }
retrofire-geom = { version = "0.4.0", path = "geom" }

[profile.release]
opt-level = 2
codegen-units = 1
lto = "thin"
debug = 1

[profile.bench]
opt-level = 3
codegen-units = 1
lto = "fat"

[profile.dev]
opt-level = 1
split-debuginfo = "unpacked"
34 changes: 24 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

*Note: This document is best viewed on an 80-column VGA terminal.*

Retrofire is a software 3D rendering library
Retrofire is a software 3D rendering library focusing on performance,
correctness, and pedagogical value.

The Retrofire project began as a shamelessly nostalgic effort to explore
the state of graphics programming as it was in the mid-to-late 90s in
Expand Down Expand Up @@ -88,10 +89,11 @@ for custom allocators is planned in order to make `alloc` optional as well.

Retrofire is split into several packages:

* core: math, renderer, utilities; no-std compatible
* geom: geometric shapes, mesh builders, model loading
* front: frontends for writing simple graphical applications
* demos: binaries showcasing retrofire features
* retrofire: a metapackage that just re-exports core, geom, and front
* retrofire-core: math, renderer, utilities; no-std compatible
* retrofire-geom: geometric shapes, mesh builders, model loading
* retrofire-front: frontends for writing simple graphical applications
* retrofire-demos: binaries showcasing retrofire features.

# Dependencies

Expand All @@ -103,13 +105,25 @@ functions, the package is not fully functional unless either the `std`,
`libm`, or `mm` feature is enabled. Activating `std` additionally enables
APIs that do I/O.

The `front` package depends on either `sdl2`, `minifb`, or `wasm-bindgen`
and `web-sys`, depending on enabled features.
The `retrofire-front` package depends on either `sdl2`, `minifb`, or
`wasm-bindgen` and `web-sys`, depending on enabled features.

The `geom` package has no external dependencies. It only requires `alloc`;
activating the optional feature `std` enables APIs that do I/O.
The `retrofire-geom` package has no external dependencies. It only requires
`alloc`; activating the optional feature `std` enables APIs that do I/O.

The `retrofire-demos` package depends on `retrofire-front`.
The `retrofire-demos` package depends on `retrofire`.

# Screenshots

The classic Stanford bunny.
![The classic Stanford bunny 3D model.](docs/bunny.jpg)

A first-person mouse-and-keyboard scene with many "Rust crates" strewn on a
checkered floor.
![Many wooden crates on a plane, each with the Rust logo](docs/crates.jpg)

Ten thousand spherical particles positioned randomly in a sphere.
![Ten thousand spherical particles in random positions.](docs/sprites.jpg)

# License

Expand Down
4 changes: 3 additions & 1 deletion core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@

# Retrofire-core

Core functionality of the `retrofire` project.
Core functionality of the [`retrofire`][1] project.

Includes a math library with strongly typed points, vectors, matrices,
colors, and angles; basic geometry primitives; a software 3D renderer with
customizable shaders; with more to come.

[1]: https://crates.io/crates/retrofire

## Crate features

* `std`:
Expand Down
5 changes: 2 additions & 3 deletions core/examples/hello_tri.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use retrofire_core::geom::tri;
use retrofire_core::{prelude::*, util::*};

fn main() {
Expand All @@ -10,7 +9,7 @@ fn main() {

#[cfg(feature = "fp")]
let shader = shader::new(
|v: Vertex3<Color3f>, mvp: &Mat4x4<ModelToProj>| {
|v: Vertex3<Color3f>, mvp: &ProjMat3<Model>| {
// Transform vertex position from model to projection space
// Interpolate vertex colors in linear color space
vertex(mvp.apply(&v.pos), v.attrib.to_linear())
Expand All @@ -19,7 +18,7 @@ fn main() {
);
#[cfg(not(feature = "fp"))]
let shader = shader::new(
|v: Vertex3<Color3f>, mvp: &Mat4x4<ModelToProj>| {
|v: Vertex3<Color3f>, mvp: &ProjMat3<Model>| {
// Transform vertex position from model to projection space
// Interpolate vertex colors in normal sRGB color space
vertex(mvp.apply(&v.pos), v.attrib)
Expand Down
15 changes: 8 additions & 7 deletions core/src/geom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ use alloc::vec::Vec;
use core::fmt::Debug;

use crate::math::{
Affine, Lerp, Linear, Mat4x4, Parametric, Point2, Point3, Vec2, Vec3,
Vector, mat::RealToReal, space::Real, vec2, vec3,
Affine, Lerp, Linear, Mat4, Parametric, Point2, Point3, Vec2, Vec3, Vector,
space::Real, vec2, vec3,
};

use crate::render::Model;

pub use mesh::Mesh;
Expand Down Expand Up @@ -517,7 +518,7 @@ impl<B> Plane3<B> {
///
/// assert_approx_eq!(m.apply(&Point3::origin()), pt3(0.0, 0.5, 0.5));
/// ```
pub fn basis<F>(&self) -> Mat4x4<RealToReal<3, F, B>> {
pub fn basis<F>(&self) -> Mat4<F, B> {
let up = self.abc();

let right: Vec3<B> =
Expand All @@ -531,7 +532,7 @@ impl<B> Plane3<B> {

let origin = self.offset() * up;

Mat4x4::from_affine(right, up, fwd, origin.to_pt())
Mat4::from_affine(right, up, fwd, origin.to_pt())
}

/// Helper that returns the plane normal non-normalized.
Expand Down Expand Up @@ -864,8 +865,8 @@ mod tests {

#[test]
fn singleton_polyline_eval() {
let pl = Polyline(vec![3.14]);
assert_eq!(pl.eval(0.0), 3.14);
assert_eq!(pl.eval(1.0), 3.14);
let pl = Polyline(vec![1.23]);
assert_eq!(pl.eval(0.0), 1.23);
assert_eq!(pl.eval(1.0), 1.23);
}
}
21 changes: 13 additions & 8 deletions core/src/geom/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::{
};

use crate::{
math::{Apply, Linear, Mat4x4, Point3, mat::RealToReal},
math::{Linear, Mat4, Point3},
render::Model,
};

Expand Down Expand Up @@ -79,12 +79,7 @@ impl<A, B> Mesh<A, B> {
let faces: Vec<_> = faces.into_iter().collect();
let verts: Vec<_> = verts.into_iter().collect();

for (i, Tri(vs)) in faces.iter().enumerate() {
assert!(
vs.iter().all(|&j| j < verts.len()),
"vertex index out of bounds at faces[{i}]: {vs:?}"
)
}
assert_indices_in_bounds(&faces, verts.len());
Self { faces, verts }
}

Expand All @@ -109,6 +104,16 @@ impl<A, B> Mesh<A, B> {
}
}

#[inline(never)]
fn assert_indices_in_bounds(faces: &[Tri<usize>], len: usize) {
for (Tri(vs), i) in zip(faces.iter(), 0..) {
assert!(
vs.iter().all(|&j| j < len),
"vertex index out of bounds at faces[{i}]: {vs:?}"
)
}
}

impl<A> Mesh<A> {
/// Returns a new mesh builder.
pub fn builder() -> Builder<A> {
Expand Down Expand Up @@ -173,7 +178,7 @@ impl<A> Builder<A> {
///
/// This is an eager operation, that is, only vertices *currently*
/// added to the builder are transformed.
pub fn transform(self, tf: &Mat4x4<RealToReal<3, Model, Model>>) -> Self {
pub fn transform(self, tf: &Mat4<Model, Model>) -> Self {
self.warp(|v| vertex(tf.apply(&v.pos), v.attrib))
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub mod prelude {
Mesh, Normal2, Normal3, Tri, Vertex, Vertex2, Vertex3, tri, vertex,
},
math::*,
render::{raster::Frag, *},
render::*,
util::buf::{AsMutSlice2, AsSlice2, Buf2, MutSlice2, Slice2},
};
}
6 changes: 4 additions & 2 deletions core/src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub use {
approx::ApproxEq,
color::{Color, Color3, Color3f, Color4, Color4f, rgb, rgba},
mat::{
Apply, Mat2x2, Mat3x3, Mat4x4, Matrix, orthographic, perspective,
Apply, Mat2, Mat3, Mat4, Matrix, ProjMat3, orthographic, perspective,
scale, scale3, translate, translate3, viewport,
},
param::Parametric,
point::{Point, Point2, Point2u, Point3, pt2, pt3},
space::{Affine, Linear},
spline::{BezierSpline, CubicBezier, smootherstep, smoothstep},
vary::Vary,
vec::{Vec2, Vec2i, Vec3, Vec3i, Vector, splat, vec2, vec3},
vec::{ProjVec3, Vec2, Vec2i, Vec3, Vec3i, Vector, splat, vec2, vec3},
};
#[cfg(feature = "fp")]
pub use {
Expand Down Expand Up @@ -177,6 +177,7 @@ where
/// let p1 = pt2(-5.0, 0.0);
/// assert_eq!(p0.lerp(&p1, 0.4),pt2(-8.0, 3.0));
/// ```
#[inline]
fn lerp(&self, other: &Self, t: f32) -> Self {
self.add(&other.sub(self).mul(t))
}
Expand All @@ -187,6 +188,7 @@ impl Lerp for () {
}

impl<U: Lerp, V: Lerp> Lerp for (U, V) {
#[inline]
fn lerp(&self, (u, v): &Self, t: f32) -> Self {
(self.0.lerp(u, t), self.1.lerp(v, t))
}
Expand Down
14 changes: 11 additions & 3 deletions core/src/math/angle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ pub type SphericalVec<B = ()> = Vector<[f32; 3], Spherical<B>>;
//

/// Returns an angle of `a` radians.
pub fn rads(a: f32) -> Angle {
pub const fn rads(a: f32) -> Angle {
Angle(a)
}

/// Returns an angle of `a` degrees.
pub fn degs(a: f32) -> Angle {
pub const fn degs(a: f32) -> Angle {
Angle(a * RADS_PER_DEG)
}

/// Returns an angle of `a` turns.
pub fn turns(a: f32) -> Angle {
pub const fn turns(a: f32) -> Angle {
Angle(a * RADS_PER_TURN)
}

Expand Down Expand Up @@ -546,6 +546,14 @@ impl Rem for Angle {
}
}

impl Mul<Angle> for f32 {
type Output = Angle;

fn mul(self, rhs: Angle) -> Self::Output {
rhs * self
}
}

#[cfg(feature = "fp")]
impl<B> From<PolarVec<B>> for Vec2<B> {
/// Converts a polar vector into the equivalent Cartesian vector.
Expand Down
Loading
Loading