diff --git a/core/src/geom.rs b/core/src/geom.rs
index 5ba5b6f4..74e732fe 100644
--- a/core/src/geom.rs
+++ b/core/src/geom.rs
@@ -1,3 +1,5 @@
+//! Basic geometric primitives.
+
/// Vertex with position and arbitrary other attributes.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Vertex
{
@@ -5,7 +7,7 @@ pub struct Vertex
{
pub attrib: A,
}
-/// Triangle, consisting of three vertices.
+/// Triangle, defined by three vertices.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Tri(pub [V; 3]);
diff --git a/core/src/lib.rs b/core/src/lib.rs
index 8f834c5c..3bbf8469 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -9,10 +9,20 @@
//! /_____,´
//! ```
//!
+//! Core functionality of the `retrofire` project.
+//!
+//! Includes a math library with vectors, matrices, colors, and angles; basic
+//! geometry primitives; a software 3D renderer with customizable shaders;
//! # Features
-//! * `std`: Enables `std` support.
-//! This makes available items requiring `std::time` or floating-point
-//! functions. Disabled by default; only `alloc` is required.
+//! * `std`:
+//! Makes available items requiring floating-point functions or
+//! `std::time`. If disabled, this crate only depends on `alloc`.
+//!
+//! * `micromath`:
+//! Provides an alternative, no-std implementation of floating-point
+//! functions via [micromath](https://crates.io/crates/micromath).
+//!
+//! All features are disabled by default.
#![cfg_attr(not(feature = "std"), no_std)]
diff --git a/core/src/math.rs b/core/src/math.rs
index 1df03d1d..55a61a75 100644
--- a/core/src/math.rs
+++ b/core/src/math.rs
@@ -1,3 +1,22 @@
+//! Linear algebra and more.
+//!
+//! Includes [vectors][self::vec], [matrices][mat], [colors][color], and
+//! [angles][angle], as well as support for custom "linear" types usable as
+//! [varyings][vary] and utilities such as approximate equality comparisons.
+//! TODO: Bezier splines and pseudorandom numbers.
+//!
+//! This library is more strongly typed than many other similar ones. It aims
+//! to prevent at compile time many errors that might otherwise only manifest
+//! as graphical glitches, runtime panics, or even (particularly in languages
+//! that are unsafe-by-default) undefined behavior.
+//!
+//! In particular, vectors and colors are tagged with a type that represents
+//! the *space* they're embedded in, and values in different spaces cannot be
+//! mixed without explicit conversion (transformation). Matrices, similarly,
+//! are tagged by both source and destination space, and can only be applied
+//! to matching vectors. Angles are strongly typed as well, to allow working
+//! with different angular units without confusion.
+
pub use angle::{degs, rads, turns, Angle};
pub use mat::{Mat3x3, Mat4x4, Matrix};
pub use vec::{vec2, vec3, vec4};
diff --git a/core/src/math/angle.rs b/core/src/math/angle.rs
index 3ba7098d..83f20ae0 100644
--- a/core/src/math/angle.rs
+++ b/core/src/math/angle.rs
@@ -95,8 +95,8 @@ impl Angle {
/// assert_approx_eq!(degs(400.0).wrap(Angle::ZERO, Angle::FULL), degs(40.0))
/// ```
#[must_use]
- pub fn wrap(self, Self(min): Self, Self(max): Self) -> Self {
- Self(min + (self.0 - min).rem_euclid(max - min))
+ pub fn wrap(self, min: Self, max: Self) -> Self {
+ Self(min.0 + (self.0 - min.0).rem_euclid(max.0 - min.0))
}
}
diff --git a/core/src/math/approx.rs b/core/src/math/approx.rs
index ea31125b..29155501 100644
--- a/core/src/math/approx.rs
+++ b/core/src/math/approx.rs
@@ -85,16 +85,16 @@ impl> ApproxEq for Option {
/// If the given values are not approximately equal.
///
/// # Examples
-///
-/// The following assertion passes even though `assert_eq` fails:
+/// `assert_eq` would fail, but `assert_approx_eq` passes:
/// ```
/// # use retrofire_core::assert_approx_eq;
+/// assert_ne!(0.1 + 0.2, 0.3);
/// assert_approx_eq!(0.1 + 0.2, 0.3);
-/// //assert_eq!(0.1 + 0.2, 0.3); Would panic!
/// ```
/// A relative epsilon is used:
/// ```
/// # use retrofire_core::assert_approx_eq;
+/// assert_ne!(1e7, 1e7 + 1.0);
/// assert_approx_eq!(1e7, 1e7 + 1.0);
/// ```
/// A custom epsilon can be given:
@@ -102,13 +102,13 @@ impl> ApproxEq for Option {
/// # use retrofire_core::assert_approx_eq;
/// assert_approx_eq!(100.0, 101.0, eps = 0.01);
/// ```
-/// Like `assert_eq`, supports custom panic messages. The epsilon is
-/// optional but must come before the format string.
+/// Like `assert_eq`, this macro supports custom panic messages.
+/// The epsilon, if present, must come before the format string.
/// ```should_panic
/// # use std::f32;
/// # use retrofire_core::assert_approx_eq;
/// assert_approx_eq!(f32::sin(3.14), 0.0, eps = 0.001,
-/// "3.14 is not close enough to {}!", f32::consts::PI);
+/// "3.14 is not a good approximation of {}!", f32::consts::PI);
/// ```
#[macro_export]
macro_rules! assert_approx_eq {
diff --git a/core/src/render/raster.rs b/core/src/render/raster.rs
index bc7ff842..4f750512 100644
--- a/core/src/render/raster.rs
+++ b/core/src/render/raster.rs
@@ -142,11 +142,11 @@ where
}
/// Returns an iterator that emits a scanline for each line from `y0` to `y1`,
-/// interpolating fragment values from `l0` to `l1` on the left side and from
-/// `r0` to `r1` on the right side.
+/// interpolating varyings from `l0` to `l1` on the left and from `r0` to `r1`
+/// on the right side.
///
-/// The three input ranges define a *trapezoid* with horizontal top and bottom
-/// edges, or, in the special case where `l0 == r0` or `l1 == r1`, a triangle:
+/// The three input ranges define a *trapezoid* with horizontal bases, or, in
+/// the special case where `l0 == r0` or `l1 == r1`, a triangle:
/// ```text
/// l0___________ r0
/// y0 _|____________| .next()
@@ -158,9 +158,9 @@ where
/// Any convex polygon can be converted into scanlines by dividing it into
/// trapezoidal segments and calling this function for each segment.
///
-/// Which exact pixels to draw is determined by whether the vector shape
-/// *covers* a pixel or not. A pixel is covered, and drawn, if and only if
-/// its center point lies inside the shape. This ensures that if two polygons
+/// The exact pixels that are drawn are determined by whether the vector shape
+/// *covers* a pixel or not. A pixel is covered, and drawn, if and only if its
+/// center point lies inside the shape. This ensures that if two polygons
/// share an edge, or several share a vertex, each pixel at the boundary will
/// be drawn by exactly one of the polygons, with no gaps or overdrawn pixels.
pub fn scan(
diff --git a/core/src/util.rs b/core/src/util.rs
index 09c3b578..fc5c601c 100644
--- a/core/src/util.rs
+++ b/core/src/util.rs
@@ -1,2 +1,4 @@
+//! Various utility types and functions.
+
pub mod buf;
pub mod rect;
diff --git a/core/src/util/buf.rs b/core/src/util/buf.rs
index fc2ddaff..c4dce121 100644
--- a/core/src/util/buf.rs
+++ b/core/src/util/buf.rs
@@ -1,3 +1,7 @@
+//! Two-dimensional buffers, with owned and borrowed variants.
+//!
+//! Useful for storing pixel data of any kind, among other things.
+
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter};
use core::iter::repeat;
@@ -9,14 +13,14 @@ use inner::Inner;
// Traits
//
-/// A trait for types that can provide a view of their data as a `Slice2`
+/// A trait for types that can provide a view of their data as a [`Slice2`].
pub trait AsSlice2 {
/// Returns a borrowed `Slice2` view of `Self`.
fn as_slice2(&self) -> Slice2;
}
/// A trait for types that can provide a mutable view of their data
-/// as a `MutSlice2`
+/// as a [`MutSlice2`].
pub trait AsMutSlice2 {
/// Returns a mutably borrowed `MutSlice2` view of `Self`.
fn as_mut_slice2(&mut self) -> MutSlice2;
@@ -28,8 +32,11 @@ pub trait AsMutSlice2 {
/// A rectangular 2D buffer that owns its elements, backed by a `Vec`.
///
+/// Unlike `Vec`, however, `Buf2` cannot be resized after construction
+/// without explicitly copying the contents to a new, larger buffer.
+///
/// `Buf2` stores its elements contiguously, in standard row-major order,
-/// such that element (x, y) maps to element at index
+/// such that the coordinate pair (x, y) maps to the index
/// ```text
/// buf.width() * y + x
/// ```
@@ -79,8 +86,8 @@ pub struct MutSlice2<'a, T>(Inner);
//
impl Buf2 {
- /// Returns a buffer with size `w` × `h`, with elements initialized
- /// with values from `init` in row-major order.
+ /// Returns a buffer with size `w` × `h`, with elements initialized in
+ /// row-major order with values yielded by `init`.
///
/// # Panics
/// If there are fewer than `w * h` elements in `init`.
diff --git a/core/src/util/rect.rs b/core/src/util/rect.rs
index 1628f11c..48d69d40 100644
--- a/core/src/util/rect.rs
+++ b/core/src/util/rect.rs
@@ -1,3 +1,5 @@
+//! Rectangular regions; essentially two-dimensional ranges.
+
use core::fmt::Debug;
use core::ops::{Bound::*, RangeBounds, RangeFull, Sub};
@@ -5,9 +7,13 @@ use crate::math::vec::{Real, Vector};
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
pub struct Rect {
+ /// The left bound of `self`, if any.
pub left: Option,
+ /// The top bound of `self`, if any.
pub top: Option,
+ /// The right bound of `self`, if any.
pub right: Option,
+ /// The bottom bound of `self`, if any.
pub bottom: Option,
}
diff --git a/front/src/lib.rs b/front/src/lib.rs
index 292e56a5..c61d4ebf 100644
--- a/front/src/lib.rs
+++ b/front/src/lib.rs
@@ -1,13 +1,22 @@
+//! Frontends for creating simple applications with `retrofire`.
+
+use std::time::Duration;
+
+use retrofire_core::render::target::Framebuf;
+use retrofire_core::util::buf::MutSlice2;
+
#[cfg(feature = "minifb")]
pub mod minifb;
#[cfg(feature = "sdl2")]
pub mod sdl2;
+/// Per-frame state. [`Window::run`][minifb::Window::run] passes an instance
+/// of `Frame` to the callback function on every iteration of the main loop.
pub struct Frame<'a> {
- // Time since first frame.
+ /// Time since the first frame.
pub t: Duration,
- // Time since last frame.
+ /// Time since the previous frame.
pub dt: Duration,
// Framebuffer in which to draw.
pub buf: Framebuf, MutSlice2<'a, f32>>,
diff --git a/front/src/minifb.rs b/front/src/minifb.rs
index d39086ed..fcda6372 100644
--- a/front/src/minifb.rs
+++ b/front/src/minifb.rs
@@ -3,13 +3,14 @@
use std::ops::ControlFlow::{self, Break};
use std::time::{Duration, Instant};
-use minifb::{Key, KeyRepeat, WindowOptions};
+use minifb::{Key, WindowOptions};
use retrofire_core::render::target::Framebuf;
use retrofire_core::util::buf::{AsMutSlice2, Buf2};
use crate::Frame;
+/// A lightweight wrapper of a `minibuf` window.
pub struct Window {
/// The wrapped minifb window.
pub imp: minifb::Window,
@@ -47,7 +48,8 @@ impl<'t> Builder<'t> {
self.title = title;
self
}
- /// Sets the fps cap of the window.
+ /// Sets the frame rate cap of the window. `None` means unlimited
+ /// frame rate (the main loop runs as fast as possible).
pub fn max_fps(mut self, fps: Option) -> Self {
self.max_fps = fps;
self
@@ -84,14 +86,23 @@ impl Window {
Builder::default()
}
- /// Updates the window content with `fb`.
+ /// Updates the window content with pixel data from `fb`.
+ ///
+ /// The data is interpreted as colors in `0x00_RR_GG_BB` format.
/// # Panics
+ /// If `fb.len() < self.size.0 * self.size.1`.
pub fn present(&mut self, fb: &[u32]) {
let (w, h) = self.size;
self.imp.update_with_buffer(fb, w, h).unwrap();
}
- /// Repeatedly calls `frame_fn`
+ /// Runs the main loop of the program, invoking the callback on each
+ /// iteration to compute and draw the next frame.
+ ///
+ /// The main loop stops and this function returns if:
+ /// * the user closes the window via the GUI (eg. titlebar close button);
+ /// * the Esc key is pressed; or
+ /// * the callback returns `ControlFlow::Break`.
pub fn run(&mut self, mut frame_fn: F)
where
F: FnMut(&mut Frame) -> ControlFlow<()>,
@@ -103,11 +114,7 @@ impl Window {
let start = Instant::now();
let mut last = Instant::now();
loop {
- if !self.imp.is_open()
- || self
- .imp
- .is_key_pressed(Key::Escape, KeyRepeat::No)
- {
+ if !self.imp.is_open() || self.imp.is_key_down(Key::Escape) {
return;
}