pub struct Transform {
pub cols: [[f32; 3]; 4],
}Expand description
An affine 3x4 transform, column by column: the images of local +X, +Y, +Z, then the translation;
world = M * local. f32 because every format we read and write stores f32 (byte-identical round trips).
A transform composed of several (a hierarchy, an entity placed in another’s space, a tile offset) is computed in
f64 from the stored f32 values and each entry rounded once to f32, never rounded step by step.
Shear and mirroring are allowed; Transform::classify flags them.
Fields§
§cols: [[f32; 3]; 4]Implementations§
Source§impl Transform
impl Transform
pub const IDENTITY: Transform
Sourcepub fn determinant(&self) -> f64
pub fn determinant(&self) -> f64
The determinant of the linear part, in f64: negative for a mirroring transform, which reverses the winding of triangles mapped through it.
Sourcepub fn facing(position: [f32; 3], direction: [f32; 3]) -> Option<Transform>
pub fn facing(position: [f32; 3], direction: [f32; 3]) -> Option<Transform>
A rigid transform at position whose local -Z points along direction (as a light or camera shines) and whose
+Y is as near world +Y as possible (+Z when direction is vertical); None for a zero or non-finite
direction. A point light or round spot cone looks the same under any roll, so no roll is taken from the source.
Sourcepub fn apply(&self, p: [f32; 3]) -> [f32; 3]
pub fn apply(&self, p: [f32; 3]) -> [f32; 3]
Point p through the transform, M p + t, computed in f64 and rounded once to f32.
Sourcepub fn from_columns4(
cols: [[f32; 4]; 4],
tolerance: f32,
) -> Result<Transform, String>
pub fn from_columns4( cols: [[f32; 4]; 4], tolerance: f32, ) -> Result<Transform, String>
A 4x4 matrix given column by column (each column x, y, z, w) as the affine transform it is: refused unless its
last row (the columns’ w) is 0, 0, 0, 1, each within tolerance, the one a format states (0: exactly). The
one rule every reader of a 4x4 matrix holds it to; a format that stores three rows is affine by its storage.
Sourcepub fn compose(&self, inner: &Transform) -> Transform
pub fn compose(&self, inner: &Transform) -> Transform
self after inner (world = self (inner local)): the transform of an entity placed by inner in a space
self places, computed in f64 from the stored values and each entry rounded once to f32. A chain of several
rounds at each link; a chain whose intermediate rounding matters is composed in f64 by its owner.
Sourcepub fn classify(&self) -> TransformKind
pub fn classify(&self) -> TransformKind
What the basis does besides rotating, scaling and translating, the one meaning every reader, writer and mesh operation
that classifies a placement shares: with u_i = c_i / |c_i|, degenerate when some |c_i| < DEGENERATE_BASIS or
|det| <= DEGENERATE_BASIS |c0||c1||c2| (or the determinant is not a number); sheared when some |u_i . u_j| > SHEAR_TOLERANCE; mirrored when
det < 0. Computed in f64.
Trait Implementations§
Source§impl Component for Transform
impl Component for Transform
Source§fn apply_linear(&self, _l: &Linear) -> Linearity<Self>
fn apply_linear(&self, _l: &Linear) -> Linearity<Self>
The placement itself, which a pass baking its non-rigid part replaces: not mapped.
const NAME: &'static str = "core.transform"
Source§const GEOMETRY: Geometry = crate::Geometry::None
const GEOMETRY: Geometry = crate::Geometry::None
Geometry). Stated by every component,
with no default, so data that describes a mesh can’t be left behind by an edit of it unawares: the World’s edit
paths take it from there.Source§fn verify(&self, _e: Entity, _w: &World) -> Result<(), String>
fn verify(&self, _e: Entity, _w: &World) -> Result<(), String>
e (indices in range, stream lengths equal, …). The pass manager
runs it on every component after the reader, after every pass and before the writer, together with the
world’s own check that every entity of Component::references is alive. World-wide rules (one name -> one
payload) are pass::Validators instead.Source§fn to_json(&self) -> Result<Option<Value>, JsonError>
fn to_json(&self) -> Result<Option<Value>, JsonError>
Ok(None) for components
that are not shown (bulk data, handles). The view must never lose a value: components that can be shown
derive serde::Serialize and return crate::json::to_value(self).map(Some), which refuses non-finite
floats instead of writing them as null.Source§const VERSION: u32 = 1
const VERSION: u32 = 1
Source§fn references(&self, _out: &mut Vec<Entity>)
fn references(&self, _out: &mut Vec<Entity>)
out: the edges
World::closure follows. A component holding entity references must declare every one of them.Source§fn payload_bytes(&self) -> u64
fn payload_bytes(&self) -> u64
Source§fn remap_primitives(&self, _from: &[usize]) -> Option<Result<Self, String>>
fn remap_primitives(&self, _from: &[usize]) -> Option<Result<Self, String>>
Geometry::PerPrimitive, Geometry::PerVertex): new primitive i comes from old primitive
from[i] (a source may repeat, when a primitive is split, or be absent, when one is dropped). Such a component
always answers (a value holding nothing per primitive answers with itself); None, the default, is for
components of Geometry::None, and World::remap_primitives refuses a dependent component that gives it.
An index the component does not have is an error. remap_list does the work for a list with one entry per
primitive.Source§fn remap_vertices(
&self,
_primitive: usize,
_from: &[u32],
) -> Option<Result<Self, String>>
fn remap_vertices( &self, _primitive: usize, _from: &[u32], ) -> Option<Result<Self, String>>
primitive were compacted or reordered, for a
component that holds something per vertex (Geometry::PerVertex): new vertex i of that primitive is old
vertex from[i] (a source may repeat or be absent). Such a component always answers (with itself when it holds
nothing for that primitive); None, the default, is for the others, and World::remap_vertices refuses a
per-vertex component that gives it. An index the component does not have is an error. Every pass that compacts
or reorders a primitive’s vertices calls World::remap_vertices. After a rebuild of the primitive list
(World::rebuild_primitives, Component::remap_primitives) a primitive’s per-vertex data is its source
primitive’s, and the vertex map is relative to that source.Source§fn blend_vertices(
&self,
_primitive: usize,
_from: &[VertexBlend],
) -> Option<Result<Self, String>>
fn blend_vertices( &self, _primitive: usize, _from: &[VertexBlend], ) -> Option<Result<Self, String>>
primitive were rebuilt as blends of old ones
(VertexBlend), for a component that holds something per vertex (Geometry::PerVertex): new vertex i
is the combination from[i] of old vertices, in whatever way the component’s data combines (a morph target’s
delta is interpolated, the way the surface it moves is). It answers as Component::remap_vertices does: with
itself when it holds nothing for that primitive; None, the default, is for a component that does not know how
to combine its data, and World::blend_vertices refuses a per-vertex component that gives it. An index the
component does not have is an error. A vertex that is a copy of one old vertex (VertexBlend::copy) is the
case Component::remap_vertices states, and a component answering one answers the other alike.Source§fn restate(&self, _resolved: &Resolved<'_>) -> Restated<Self>
fn restate(&self, _resolved: &Resolved<'_>) -> Restated<Self>
resolve-state (crate::state::ResolveState) gave the axes in resolved their values: a
component that holds crate::state::Clauses of its own (a record of parts each present in some states) reduces
them as core.condition is reduced (crate::state::Resolved::reduce: a clause that fails is dropped, a clause
left with no literal holds whatever the other axes are). Restated::Absent says the entity is not present in
this state (every clause failed): it is despawned as one whose core.condition fails is. The default holds no
clause: Restated::Unchanged.