Math Types
Implementation status: the math library is one of CNA's most complete areas. Matrix includes decomposition, billboard, shadow and reflection operations; Curve::Evaluate handles the XNA loop types; and Color exposes the named constants. The known BoundingFrustum::Intersects(Ray) boundary is documented below. Unless noted otherwise, every member lives in the Microsoft::Xna::Framework namespace. All documented math members are represented in CNA's XNA census (see XNA Compatibility); behaviour is checked against the real XNA runtime for a subset described in the numerical-behaviour section below.
Overview
CNA provides the complete XNA 4.0 math library as a C++23 implementation. It lives in the math module (CNA::Math), which is a compiled library — modules/math/src/*.cpp — with public headers, not a header-only one, and it links only that module and Sharp Runtime, so it can be used with no renderer. Types are value types (structs) and support the same member functions, static helpers, and operator overloads as their XNA counterparts. Floating-point arithmetic follows XNA semantics: row-major matrices, right-handed coordinate system for CreateLookAt and view-space conventions, and clockwise winding by default.
Two spelling rules apply throughout, because the C++ API mirrors the C# one: the vector, quaternion, plane, ray, point and matrix element components are plain public fields (v.X, m.M11, box.Min), while everything that is a property in C# is an accessor pair — getXProperty() / setXProperty(value) — for example Color::getRProperty(), Rectangle::getCenterProperty() and Matrix::getIdentityProperty(). Tables below name the accessor where one exists.
The library is organized into three groups: core types (vectors, matrix, quaternion, color, and helpers), bounding types (collision and visibility volumes), and curve types (animation splines). A separate PackedVector sub-namespace in Microsoft::Xna::Framework::Graphics::PackedVector provides GPU-format value types documented separately.
Core types
Vector2
A 2D vector with float components X and Y. Supports arithmetic with other vectors and scalars, and provides the most common geometric operations.
| Member | Description |
|---|---|
X, Y | Float components |
operator + - * / | Component-wise vector arithmetic and scalar multiply/divide |
Dot(a, b) | Dot product of two vectors |
Length() | Euclidean length (there is no 2D Cross: XNA has none; use a.X * b.Y − a.Y * b.X) |
LengthSquared() | Squared length (avoids square root) |
Normalize(v) | Returns a unit-length copy; instance Normalize() normalizes in place |
Distance(a, b) | Distance between two points |
DistanceSquared(a, b) | Squared distance |
Lerp(a, b, t) | Linear interpolation |
operator += -= *= /= | Compound assignment: a CNAEXT convenience (XNA declares none); write a = a + b for strict XNA source |
Equals(...), GetHashCode(), ToString() | XNA's value semantics, including Equals(std::any) for XNA's Equals(object) |
Reflect(v, normal) | Reflects a vector about a surface normal |
Transform(v, matrix) | Transforms by a Matrix (position transform) |
TransformNormal(v, matrix) | Transforms by a matrix, ignoring translation |
Min(a, b) / Max(a, b) | Component-wise minimum / maximum |
Clamp(v, min, max) | Component-wise clamp |
Negate(v) | Returns the additive inverse |
Zero | Static: (0, 0) |
One | Static: (1, 1) |
UnitX | Static: (1, 0) |
UnitY | Static: (0, 1) |
Vector3
A 3D vector with float components X, Y, Z. Used for positions, directions, normals, and colors throughout the 3D API.
| Member | Description |
|---|---|
X, Y, Z | Float components |
operator + - * / | Component-wise arithmetic and scalar operations |
Dot(a, b) | Dot product |
Cross(a, b) | 3D cross product, returning a perpendicular Vector3 |
Length() / LengthSquared() | Euclidean length and squared length. Length(), Distance and DistanceSquared sum their squares in float; the wider-than-float accumulation that reproduces XNA's 32-bit x87 arithmetic is used by Vector3::Transform / TransformNormal, matrix products and BoundingSphere's internal helpers instead |
Normalize(v) | Unit-length copy or in-place normalization |
Distance(a, b) / DistanceSquared(a, b) | Point-to-point distance |
Lerp(a, b, t) | Linear interpolation |
SmoothStep(a, b, t) | Smooth Hermite interpolation (cubic) |
Reflect(v, normal) | Reflects about a surface normal |
Transform(v, matrix) | Transforms by a Matrix (applies translation) |
Transform(v, quaternion) | Rotates by a Quaternion |
TransformNormal(v, matrix) | Transforms ignoring translation (for normals) |
Min / Max / Clamp | Component-wise operations |
Hermite(v1, t1, v2, t2, a) | Hermite spline interpolation |
Barycentric(v1, v2, v3, b2, b3) | Point in barycentric coordinates |
CatmullRom(v1, v2, v3, v4, a) | Catmull-Rom spline interpolation |
Zero / One | Static: (0,0,0) and (1,1,1) |
UnitX / UnitY / UnitZ | Axis unit vectors |
Forward | Static: (0, 0, −1) |
Backward | Static: (0, 0, +1) |
Up | Static: (0, +1, 0) |
Down | Static: (0, −1, 0) |
Left | Static: (−1, 0, 0) |
Right | Static: (+1, 0, 0) |
Vector4
A 4D vector with float components X, Y, Z, W. Used for homogeneous coordinates, RGBA colors, and as shader parameter types.
| Member | Description |
|---|---|
X, Y, Z, W | Float components |
operator + - * / | Component-wise arithmetic and scalar operations |
Dot(a, b) | 4D dot product |
Length() / LengthSquared() | 4D Euclidean length |
Normalize(v) | Unit-length copy or in-place normalization |
Distance(a, b) / DistanceSquared(a, b) | 4D distance |
Lerp(a, b, t) | Linear interpolation |
SmoothStep(a, b, t) | Smooth Hermite interpolation |
Transform(v, matrix) | Transforms by a 4×4 Matrix |
Min / Max / Clamp | Component-wise operations |
Hermite / Barycentric / CatmullRom | Spline and interpolation helpers |
Zero / One | Static: (0,0,0,0) and (1,1,1,1) |
UnitX / UnitY / UnitZ / UnitW | Axis unit vectors |
Matrix
A 4×4 row-major floating-point matrix. Elements are named M11–M44 (row, column). Used for world/view/projection transforms and general linear algebra. Multiplication is left-to-right (row-vector convention), matching XNA 4.0 exactly.
| Member | Description |
|---|---|
M11…M44 | Individual float elements (row-major); public fields |
getTranslationProperty() / setTranslationProperty(v) | The translation row (M41, M42, M43) as a Vector3; likewise getUpProperty(), getDownProperty(), getLeftProperty(), getRightProperty(), getForwardProperty() and getBackwardProperty() |
operator * | Matrix multiplication. Products reproduce XNA's x87 accumulation order and rounding |
operator + - | Component-wise addition / subtraction |
operator * (float), operator * (float, Matrix) | Scalar multiply on either side (the scalar-left form was added in this snapshot, as XNA has it) |
Transpose(m) | Returns the transpose |
Invert(m) | Returns the inverse; Invert(const Matrix&, Matrix& result) writes it to an output parameter instead |
Determinant() | Returns the scalar determinant |
Decompose(scale, rotation, translation) | Decomposes into TRS components; returns false if a scale is (nearly) zero. It follows FNA's algorithm, not XNA 4.0's, so a mirrored (negative-determinant) matrix gives positive scales and a quaternion that is not a unit rotation, and a sheared matrix reports success (CNA-BUG-259) |
CreateTranslation(x, y, z) | Translation matrix |
CreateScale(x, y, z) | Non-uniform scale matrix |
CreateRotationX/Y/Z(radians) | Axis-aligned rotation matrices |
CreateFromAxisAngle(axis, angle) | Arbitrary axis rotation |
CreateFromQuaternion(q) | Rotation matrix from a Quaternion |
CreateFromYawPitchRoll(yaw, pitch, roll) | Euler-angle rotation matrix |
CreateLookAt(eye, target, up) | View matrix (right-handed) |
CreatePerspectiveFieldOfView(fov, aspect, near, far) | Perspective projection matrix |
CreatePerspective(w, h, near, far) | Perspective from width and height |
CreatePerspectiveOffCenter(...) | Off-center perspective frustum |
CreateOrthographic(w, h, near, far) | Orthographic projection matrix |
CreateOrthographicOffCenter(...) | Off-center orthographic projection |
CreateBillboard(...) | Camera-facing billboard matrix |
CreateConstrainedBillboard(...) | Axis-constrained billboard |
CreateShadow(light, plane) | Planar shadow projection |
CreateReflection(plane) | Reflection matrix about a plane |
CreateWorld(pos, forward, up) | Full world matrix from TBN vectors |
Lerp(a, b, t) | Component-wise linear interpolation |
Matrix::getIdentityProperty() | Static accessor: the 4×4 identity matrix (the C# Matrix.Identity) |
ToString() | XNA's exact text format |
Quaternion
A unit quaternion representing a 3D rotation, stored as X, Y, Z (imaginary) and W (real) float components. Quaternions avoid gimbal lock and are the preferred rotation representation for animation and interpolation.
| Member | Description |
|---|---|
X, Y, Z, W | Float components |
operator * (Quaternion) | Quaternion concatenation (rotation composition) |
operator + - * | Component-wise arithmetic |
Length() / LengthSquared() | Quaternion magnitude |
Normalize(q) | Returns or applies unit normalization |
Conjugate(q) | Conjugate (negates X, Y, Z; equivalent to inverse for unit quaternions) |
Inverse(q) | Multiplicative inverse |
Dot(a, b) | 4D dot product |
Concatenate(a, b) | Applies rotation a then b |
Slerp(a, b, t) | Spherical linear interpolation |
Lerp(a, b, t) | Normalized linear interpolation (faster, less accurate than Slerp) |
CreateFromAxisAngle(axis, angle) | Constructs from axis and angle in radians |
CreateFromYawPitchRoll(yaw, pitch, roll) | Constructs from Euler angles |
CreateFromRotationMatrix(m) | Extracts rotation from a Matrix |
Identity | Static: (0, 0, 0, 1) — no rotation |
Color
An RGBA color stored as four byte (uint8) components, packed into a 32-bit integer. Over 140 named static colors are provided as static fields, matching the XNA Color class exactly (including CornflowerBlue, the classic XNA clear color).
| Member | Description |
|---|---|
getRProperty(), getGProperty(), getBProperty(), getAProperty() (and set…) | Byte (0–255) RGBA components |
getPackedValueProperty() / setPackedValueProperty(v) | The packed 32-bit word, numerically AABBGGRR (R in bits 0–7, A in bits 24–31); on a little-endian machine its bytes lie in memory as R, G, B, A. See Rectangle, Point and Color. |
Color() | Default construction gives transparent black (0, 0, 0, 0), as the XNA value type does (this changed in this snapshot), so set colours explicitly |
ToVector4() | Converts to a Vector4 in [0, 1] range |
ToVector3() | Converts RGB to a Vector3 in [0, 1] range |
Lerp(a, b, t) | Component-wise linear interpolation between two colors (truncating, as XNA does) |
Multiply(c, scale) | Scales all channels by a float in [0, 1] (truncating, as XNA does) |
Color(float r, float g, float b, float a), Color(Vector4) | Float construction saturates to [0, 1], rounds ties to even and packs NaN as 0 — see PackedVector Types |
operator == != | Equality comparison by packed value |
CornflowerBlue | Static: #6495ED — the iconic XNA clear color |
Red, Green, Blue | Static primary colors |
White, Black, Transparent | Static utility colors |
| 140+ named statics | Full set matching XNA: AliceBlue through YellowGreen |
Rectangle
An axis-aligned integer rectangle defined by its top-left corner (X, Y) and its dimensions (Width, Height). Used for screen regions, texture source rectangles, and 2D collision detection.
| Member | Description |
|---|---|
X, Y | Integer coordinates of the top-left corner |
Width, Height | Integer dimensions |
getLeftProperty(), getRightProperty() | Computed X and X+Width |
getTopProperty(), getBottomProperty() | Computed Y and Y+Height |
getCenterProperty() | Point at the geometric center |
getLocationProperty() / setLocationProperty(p) | Top-left corner as a Point (there is no Size property: XNA's Rectangle has none, so use Width/Height) |
getIsEmptyProperty() | True if the rectangle is the empty rectangle (all four fields zero) |
Contains(x, y) | Point-in-rectangle test (integer coordinates only; other overloads take a Point or a Rectangle) |
Contains(Point) | Point containment |
Contains(Rectangle) | Rectangle fully contained |
Intersects(Rectangle) | Overlap test |
Intersect(a, b) | Returns the overlapping rectangle |
Union(a, b) | Returns the bounding rectangle of both inputs |
Inflate(h, v) | Expands (or contracts) by horizontal and vertical amounts |
Offset(x, y) | Translates the rectangle by (x, y) |
Rectangle::Empty | Static: Rectangle(0, 0, 0, 0) |
Point
A pair of integer values X and Y. Used for screen coordinates, texture offsets, and as the return type of several Rectangle properties.
| Member | Description |
|---|---|
X, Y | Integer components |
operator + - * / | Component-wise arithmetic, carried over from FNA: XNA 4.0's Point has no arithmetic operators, and these carry no CNAEXT marker, so a strict-XNA build does not flag them |
operator == != | Equality comparison |
Point::Zero | Static: (0, 0) (also Point::getZeroProperty()) |
Conversion to Vector2 | There is no ToVector2() (XNA has none); write Vector2((float)p.X, (float)p.Y) |
MathHelper
A static utility class with common scalar math functions and constants. Mirrors Microsoft.Xna.Framework.MathHelper, and additionally exposes four FNA-internal helpers publicly (WithinEpsilon, MachineEpsilonFloat, an integer Clamp and ClosestMSAAPower); those four are not XNA API.
| Member | Description |
|---|---|
Pi | Static constant π (3.14159…) |
TwoPi | Static constant 2π |
PiOver2 | Static constant π/2 |
PiOver4 | Static constant π/4 |
E | Static constant e (2.71828…) |
Clamp(v, min, max) | Clamps a float to [min, max] |
Lerp(a, b, t) | Linear interpolation: a + (b−a) * t |
SmoothStep(a, b, t) | Smooth cubic interpolation using 3t²−2t³ |
ToDegrees(radians) | Converts radians to degrees |
ToRadians(degrees) | Converts degrees to radians |
WrapAngle(angle) | Wraps an angle to (−π, π] |
Distance(a, b) | Absolute difference between two floats |
Min(a, b) / Max(a, b) | Scalar min and max |
Barycentric / CatmullRom / Hermite | Scalar spline helpers |
WithinEpsilon(a, b), MachineEpsilonFloat, Log2E / Log10E | Epsilon comparison (FNA-internal, not XNA API) and the remaining XNA constants (Log2E, Log10E) |
Bounding types
Bounding volume types live in Microsoft::Xna::Framework alongside the core math types. They are used for frustum culling, collision detection, and ray casting. Contains returns a ContainmentType enum value (Disjoint, Contains, or Intersects). Intersects returns bool except for ray tests which return std::optional<float> (the hit distance along the ray).
BoundingBox
An axis-aligned bounding box (AABB) defined by its minimum and maximum corner points as Vector3 values.
| Member | Description |
|---|---|
Min, Max | Vector3 corners of the AABB |
Contains(Vector3) | Point containment test |
Contains(BoundingSphere) | Sphere containment test |
Contains(BoundingBox) | AABB containment test |
Intersects(BoundingBox) | AABB overlap test |
Intersects(BoundingSphere) | Sphere overlap test |
Intersects(BoundingFrustum) | Frustum overlap test |
Intersects(Ray) | Ray cast; returns optional hit distance |
GetCorners() | Returns the 8 corner points as a std::vector<Vector3> (an overload fills an existing vector) |
CreateFromPoints(points) | Static: AABB enclosing a span of points |
CreateFromSphere(sphere) | Static: Smallest AABB enclosing a sphere |
CreateMerged(a, b) | Static: AABB enclosing both input AABBs |
BoundingSphere
A bounding sphere defined by a center Vector3 and a float radius.
| Member | Description |
|---|---|
Center | Vector3 center of the sphere |
Radius | Float radius |
Contains(Vector3) | Point containment test |
Contains(BoundingBox) | AABB containment test |
Contains(BoundingSphere) | Sphere containment test |
Contains(BoundingFrustum) | Frustum containment test |
Intersects(BoundingBox) | AABB overlap test |
Intersects(BoundingSphere) | Sphere overlap test |
Intersects(BoundingFrustum) | Frustum overlap test |
Intersects(Ray) | Ray cast; returns optional hit distance |
Intersects(Plane) | Plane classification (front, back, or intersecting) |
Transform(matrix) | Transforms center and scales radius |
CreateFromBoundingBox(box) | Static: Sphere enclosing an AABB |
CreateFromPoints(points) | Static: Minimum enclosing sphere for a span of points |
CreateMerged(a, b) | Static: Sphere enclosing both input spheres |
BoundingFrustum
A view frustum defined by a combined view-projection matrix. Computes the six clip planes automatically from the matrix and exposes them as Plane objects. Typically used for frustum culling.
| Member | Description |
|---|---|
getMatrixProperty() / setMatrixProperty(m) | The combined view-projection Matrix; setting this recomputes all planes |
getNearProperty(), getFarProperty() | Near and far clip planes as Plane |
getLeftProperty(), getRightProperty() | Left and right clip planes |
getTopProperty(), getBottomProperty() | Top and bottom clip planes |
GetCorners() | Returns the 8 frustum corner vertices as a std::vector<Vector3> |
Contains(Vector3) | Point containment test |
Contains(BoundingBox) | AABB containment test |
Contains(BoundingSphere) | Sphere containment test |
Contains(BoundingFrustum) | Frustum-in-frustum test |
Intersects(BoundingBox) | AABB overlap test |
Intersects(BoundingSphere) | Sphere overlap test |
Intersects(BoundingFrustum) | Frustum overlap test |
Intersects(Ray) | Partial Returns an empty result when the ray origin is outside the frustum and 0 when it is inside; throws NotImplementedException only when the origin lies on the frustum boundary — see below |
BoundingFrustum::Intersects(Ray) is only partly implemented. It answers “no hit” for a ray origin outside the frustum and a distance of 0 for an origin inside, but for an origin exactly on the boundary it throws System::NotImplementedException; a real entry distance is never computed. It is not the only functional gap in the core math suite: BoundingSphere::Contains(BoundingFrustum) and BoundingBox::Contains(BoundingFrustum) never answer Disjoint (see Known Issues). XNA 4.0's own implementation computes the entry distance fully (checked in the XNA 4.0 assembly's IL), so this is a CNA gap, not XNA parity. Use Ray::Intersects(BoundingBox) or Ray::Intersects(BoundingSphere) against a proxy volume if you need a real ray/frustum entry distance.
Plane
A half-space plane defined by a Normal (Vector3) and a scalar distance D, satisfying the equation Normal·X + D = 0.
| Member | Description |
|---|---|
Normal | Vector3 normal of the plane; unit length only if you normalise it (the three-point constructor and Normalize() do, the other constructors store what they are given) |
D | Float with Normal·X + D = 0 on the plane: the negated distance of the plane from the origin along the normal (the plane y = 1 has D = −1) |
plane.Dot(v4) | Dot product with a Vector4 |
plane.DotCoordinate(v3) | Signed distance from a point to the plane |
plane.DotNormal(v3) | Dot product of the plane normal with a Vector3 |
Normalize(plane) / plane.Normalize() | Returns a unit-normal copy of the plane, or normalizes in place |
Transform(plane, matrix) | Transforms the plane by a matrix. Defective at this snapshot unless the matrix's inverse is symmetric (identity, axis-aligned scale): a translation or most rotations give a wrong plane (CNA-BUG-001; workaround on Planes, rays and bounding volumes) |
Transform(plane, quaternion) | Rotates the plane by a quaternion |
Plane(a, b, c) | Constructor: builds a plane from three points (also Plane(normal, d), Plane(a, b, c, d), Plane(Vector4)) |
Intersects(BoundingBox) | Box classification |
Intersects(BoundingSphere) | Sphere classification |
Ray
A ray defined by an origin (Position) and a unit direction (Direction), both Vector3. The primary use is ray casting against bounding volumes and planes.
| Member | Description |
|---|---|
Position | Vector3 ray origin |
Direction | Vector3 unit direction |
Intersects(BoundingBox) | Returns std::optional<float> hit distance, or empty if no intersection |
Intersects(BoundingSphere) | Returns optional hit distance |
Intersects(BoundingFrustum) | Returns optional hit distance |
Intersects(Plane) | Returns optional hit distance along the ray to the plane |
operator == != | Equality comparison |
Curve types
The curve types provide 1D floating-point animation splines. They are used by the content pipeline and by AnimationPlayer implementations to drive scalar properties over time.
Curve
A piecewise Hermite spline that maps a float position (typically time) to a float value. The spline is defined by a sorted collection of CurveKey control points and loop types that govern behaviour outside the key range.
| Member | Description |
|---|---|
getKeysProperty() | CurveKeyCollection — the sorted set of control points |
getPreLoopProperty() / setPreLoopProperty(t) | CurveLoopType controlling extrapolation before the first key |
getPostLoopProperty() / setPostLoopProperty(t) | CurveLoopType controlling extrapolation after the last key |
getIsConstantProperty() | True if the curve has fewer than two keys |
Evaluate(position) | Evaluates the spline at the given position and returns the interpolated float value |
ComputeTangents(type) | Recomputes all tangents using the specified CurveTangent type (Flat / Linear / Smooth) |
Clone() | Returns a deep copy |
The CurveLoopType enum controls what happens outside the key range:
| Value | Behaviour |
|---|---|
Constant | Clamps to the value of the nearest key (default) |
Cycle | Repeats the curve from the start |
CycleOffset | Repeats and offsets by the value difference between endpoints |
Oscillate | Ping-pongs back and forth (reverse on alternate cycles) |
Linear | Extrapolates linearly from the endpoint tangent |
CurveKey
A single control point on a Curve. Stores the position, value, and in/out tangents that define the Hermite segment connecting adjacent keys.
| Member | Description |
|---|---|
getPositionProperty() | The x-axis value (typically time) of this key |
getValueProperty() | The y-axis value (the output) at this key |
getTangentInProperty() | The incoming tangent (controls the slope arriving at this key) |
getTangentOutProperty() | The outgoing tangent (controls the slope leaving this key) |
getContinuityProperty() | CurveContinuity enum: Smooth (connected) or Step (discrete jump) |
Clone() | Returns a copy of this key |
PackedVector types
The Microsoft::Xna::Framework::Graphics::PackedVector namespace provides 17 GPU-oriented packed value types such as HalfVector2, HalfVector4, NormalizedByte4, Rgba1010102, and others. These types implement the IPackedVector interface and are used as vertex element formats. All 17 are real, including a correct IEEE-754 half-float codec that handles subnormals, infinities and NaN in both directions. Float construction of the 14 integer-packed types saturates, rounds ties-to-even and packs NaN as 0, as measured on the genuine XNA 4.0 runtime (the three half-float types use the IEEE half codec instead), and all 17 implement ToString(), GetHashCode() and Equals (alpha.1 lacked these).
See the dedicated PackedVector Types reference for the full per-type breakdown. These values are broadly usable as vertex data. Texture-format admission is narrower and renderer-qualified: the default Reach profile refuses the wider formats (Rgba1010102, Rg32, Rgba64, Alpha8, Single, Vector2, Vector4, the half-float formats and HdrBlendable) unless HiDef is requested, and on top of that only eight renderer families promote the broader formats for a public Texture2D (DirectX 11, the EasyGL identities, SDL_GPU, WebGPU, Vulkan, Metal, FNA3D and Software), while the other four identities (SDL_RENDERER, DIRECTX9, HEADLESS and STUB) accept only SurfaceFormat::Color.
Code examples
The snippets below compile against the CNA headers at this snapshot (syntax-checked with the same include set as the tutorials); they assume using namespace Microsoft::Xna::Framework; and, for the graphics types, Microsoft::Xna::Framework::Graphics.
Vector3 math — normalize and dot product
// Compute the angle between two directions using dot product
Vector3 toEnemy = enemy.Position - player.Position;
float distance = toEnemy.Length();
Vector3 dir = Vector3::Normalize(toEnemy); // unit direction
Vector3 facing = Vector3::Normalize(player.Forward);
float cosAngle = Vector3::Dot(facing, dir); // in [-1, 1]
float angleDeg = MathHelper::ToDegrees(std::acos(cosAngle));
if (angleDeg < 45.0f)
DrawAimingReticle();
Matrix camera setup — LookAt and PerspectiveFieldOfView
// Build a standard view-projection matrix pair (inside a Game subclass)
Matrix view = Matrix::CreateLookAt(
Vector3(0.0f, 5.0f, 10.0f), // eye position
Vector3::Zero, // look-at target
Vector3::Up // world up
);
Matrix projection = Matrix::CreatePerspectiveFieldOfView(
MathHelper::ToRadians(60.0f), // vertical FOV
getGraphicsDeviceProperty().getViewportProperty().getAspectRatioProperty(),
0.1f, // near plane
1000.0f // far plane
);
// Pass to a BasicEffect
effect->setViewProperty(view);
effect->setProjectionProperty(projection);
Quaternion rotation interpolation — Slerp
// Smoothly rotate an object from startRotation to endRotation over 2 seconds
Quaternion startRotation = Quaternion::CreateFromYawPitchRoll(0.0f, 0.0f, 0.0f);
Quaternion endRotation = Quaternion::CreateFromAxisAngle(Vector3::Up,
MathHelper::ToRadians(180.0f));
float elapsed = 0.0f; // a member of your Game
const float duration = 2.0f;
// Inside Update(GameTime& gameTime):
elapsed += (float)gameTime.getElapsedGameTimeProperty().getTotalSecondsProperty();
float t = MathHelper::Clamp(elapsed / duration, 0.0f, 1.0f);
Quaternion current = Quaternion::Slerp(startRotation, endRotation, t);
Matrix world = Matrix::CreateFromQuaternion(current);
effect->setWorldProperty(world);
BoundingSphere intersection test
// Simple frustum-culling check before submitting a draw call
BoundingSphere sphere(center, radius);
BoundingFrustum frustum(view * projection);
if (frustum.Contains(sphere) != ContainmentType::Disjoint)
{
// Sphere is at least partially visible — draw it
DrawMesh(mesh);
}
// Ray-cast from the cursor to pick an object: Viewport::Unproject returns a
// world-space Vector3, so unproject the near and far plane points and build the Ray
Vector3 nearPoint = viewport.Unproject(Vector3(cursorPos.X, cursorPos.Y, 0.0f),
projection, view, Matrix::getIdentityProperty());
Vector3 farPoint = viewport.Unproject(Vector3(cursorPos.X, cursorPos.Y, 1.0f),
projection, view, Matrix::getIdentityProperty());
Ray pickRay(nearPoint, Vector3::Normalize(farPoint - nearPoint));
std::optional<float> hitDistance = sphere.Intersects(pickRay);
if (hitDistance.has_value())
SelectObject(object, hitDistance.value());
MathHelper.Lerp for smooth transitions
// Smoothly fade a value (e.g. music volume) toward a target each frame
float currentVolume = 0.0f;
float targetVolume = 1.0f;
const float speed = 2.0f; // units per second
// Inside Update(GameTime& gameTime):
float dt = (float)gameTime.getElapsedGameTimeProperty().getTotalSecondsProperty();
currentVolume = MathHelper::Lerp(currentVolume, targetVolume,
MathHelper::Clamp(speed * dt, 0.0f, 1.0f));
MediaPlayer::setVolumeProperty(currentVolume);
Numerical behaviour: what matches the XNA runtime
Because CNA reproduces XNA's numerical behaviour rather than merely its API, a few results can differ in the last bits from alpha.1 and from a plain float reimplementation. The evidence is limited to the measured subsets below; it is not a claim that every math member is bit-identical.
| Behaviour | Detail |
|---|---|
| x87-width accumulation | Vector3::Transform, Vector3::TransformNormal, matrix products (Matrix::Multiply, Matrix::Invert) and BoundingSphere::CreateFromPoints (through private helpers) accumulate at wider-than-float precision and narrow once, reproducing the 32-bit x87 code path of the XNA runtime. The public Vector3::Length, LengthSquared, Distance and DistanceSquared sum their squares in float. Recorded oracles: bounding-sphere and matrix measurements under tests/reference/xna40/framework/. |
| Widest-axis tie-break | BoundingSphere::CreateFromPoints uses XNA's rule that the last axis wins a tie. |
| Packing | Float-to-packed conversion of the 14 integer-packed types (and of Color) saturates, rounds ties-to-even and maps NaN to 0 (68 measurements from the genuine XNA 4.0 runtime); the half-float types keep the IEEE half codec; Color::Lerp/Multiply still truncate, as XNA does. |
| Text formats | Matrix::ToString() uses XNA's exact format; the value types gained Equals(std::any), GetHashCode() and ToString(). |
| XML and text conversion | Opt-in XmlSerializationEXT.hpp adds XmlSerializer support for the math value types, and the opt-in Framework.Design converters parse and format them as text. |
Deep dives on this topic
Long-form pages that explain the exact semantics, invariants and evidence behind this subject.
- Coordinate and composition conventions: handedness, row vectors, depth and clip space — CNA's right-handed basis, row-vector matrices applied in reading order, quaternion products that run the other way, the [0,1] depth range derived three times, clip-space W and the ToColumnMajor bridge.
- Core framework and graphics API map — An orientation map of CNA's core framework and graphics API: owning headers, public shape, the boundary that trips ports, and where each behaviour is explained, for math, framework, content, resources, effects and device state.
- Curve evaluation: keys, tangents, loop types and the XNA reference — How CNA's Curve evaluates: sorted keys, the per-segment Hermite basis, Step continuity, the five loop types, smooth tangents and degenerate curves, each compared with the XNA 4.0 algorithm.
- Math value types in C++: object layout, equality, hashing and API shape — Which CNA math types carry a vtable, why Color is 24 bytes on 64-bit hosts, the internal vertex stream structs, output-reference aliasing, exact equality, hash and ToString differences, and the split argument exceptions.
- Planes, rays and bounding volumes: exact containment and intersection semantics — Half-space conventions, plane transforms, ray tolerances, box corner order, sphere and frustum containment rules in CNA, compared function by function with XNA 4.0, with workarounds for every mismatch.
- Rectangle, Point and Color: integer geometry and packed colour semantics — Rectangle's half-open edges, touching and empty rules, Point's missing Vector2 bridge and rounding, Color's AABBGGRR word, the 141/140/139 named-colour counts, construction rounding and premultiplied alpha.
- Vector, Matrix and MathHelper numerics: interpolation, clamping and degenerate inputs — What CNA's vector, matrix and MathHelper functions return for out-of-range amounts, inverted clamps, NaN, zero vectors, singular matrices and bad camera input, compared with XNA 4.0, plus the precision and test evidence.
Known issues in this area
Current defects, gaps and limitations at this snapshot that touch this subject.
- CNA-BUG-001: Plane::Transform(plane, matrix) transposes the inverse in place through a non-aliasing-safe Matrix::Transpose — Plane::Transform with a Matrix passes one object as both source and destination of Matrix::Transpose, which is not aliasing-safe, so any transform whose inverse is not symmetric (a translation, most rotations) yields a w
- CNA-BUG-002: BoundingSphere::Contains(const BoundingFrustum&) never returns Disjoint — When any frustum corner lies outside the sphere, BoundingSphere::Contains(frustum) always answers Intersects, because its distance test compares a constant zero, so a frustum nowhere near the sphere is reported as overla
- CNA-BUG-003: BoundingBox::Contains(const BoundingFrustum&) never returns Disjoint and answers Contains when only the first frustum corner is outside — BoundingBox::Contains(frustum) classifies the frustum from its corners only, so a frustum wholly separate from the box is reported as Intersects, and one whose first corner alone lies outside is reported as Contains.
- CNA-BUG-004: BoundingFrustum::Intersects(Ray) never computes an entry distance: rays starting outside always miss, and an origin on a plane throws — BoundingFrustum::Intersects(Ray) and Ray::Intersects(BoundingFrustum) report no hit for every ray whose origin is outside the frustum, whatever its direction, return 0 for an origin inside, and throw NotImplementedExcept
- CNA-BUG-025: PlaneIntersectionType's Doxygen swaps the meaning of Front and Back — PlaneIntersectionType.hpp documents Front as the negative half-space and Back as the positive one, the opposite of what every CNA classification returns and of XNA's meaning.
- CNA-BUG-026: Matrix::CreatePerspectiveFieldOfView accepts a field of view of exactly MathHelper::Pi — The upper guard compares against the literal 3.141593f, which rounds to the float one step above MathHelper::Pi, so a field of view of exactly Pi passes validation and builds a degenerate projection instead of throwing a
- CNA-BUG-027: Vector Clamp, Min and Max resolve inverted ranges and NaN operands differently from XNA — Vector2/3/4::Clamp use std::min(std::max(v, min), max), so max wins when min > max, whereas XNA's vector Clamp and CNA's MathHelper::Clamp let min win; vector and scalar Min/Max also return a different operand from XNA f
- CNA-BUG-028: Curve::ComputeTangent Smooth tangents test the key spacing against two different epsilons, where XNA tests the value difference against one — For CurveTangent::Smooth, ComputeTangent zeroes the in tangent when the neighbour span is below 2^-24 but the out tangent only below the smallest denormal, while XNA zeroes both when the neighbours' value difference is b
- CNA-BUG-063: Vector3::Length, LengthSquared, Distance and DistanceSquared accumulate in float, not at the width CNA measured XNA to use — CNA's own measurement of the XNA 4.0 runtime found Vector3.Distance summed at extended precision (a float sum matched none of 200 pairs), and BoundingSphere.cpp follows that rule, but the public Vector3 length and distan
- CNA-BUG-064: Curve::Evaluate reads the wrong key for Step continuity away from position 1 and for a Linear post-loop — A Step segment returns the next key's value whenever the evaluated position is at least 1.0 (an absolute constant) instead of at the segment's end, and a Linear post-loop extrapolates with the first key's TangentOut inst
- CNA-BUG-065: Curve::Evaluate divides by zero for coincident key positions, returning NaN and converting infinity to int in the cyclic loop modes — GetNumberOfCycle and GetCurvePosition divide by the key span and the segment width without a guard, so curves with coincident keys yield NaN or undefined behaviour where XNA returns the first key's value.
- CNA-BUG-066: BoundingFrustum::Contains(Vector3) answers Intersects for a point exactly on a plane and skips the remaining planes — BoundingFrustum::Contains(point) returns Disjoint for any positive plane distance and, for a distance of exactly zero, Intersects without testing the remaining planes; XNA never answers Intersects for a point and uses a
- CNA-BUG-251: BoundingSphere(Vector3 center, float radius) accepts a negative radius, where XNA 4.0 throws ArgumentException — CNA's BoundingSphere(Vector3, float) constructor stores any radius, while XNA 4.0's throws ArgumentException for radius < 0, so a negative radius is silently accepted.
- CNA-BUG-252: Vector3, Vector4, Quaternion and Matrix GetHashCode add raw int bit patterns with signed arithmetic, which overflows (undefined behaviour) for ordinary values — The four GetHashCode functions sum FloatHash results as int with plain +; three 1.0f components already exceed INT_MAX, so the sum is signed-overflow undefined behaviour, while Vector2::GetHashCode already sums as unsign
- CNA-BUG-259: Matrix::Decompose follows FNA's algorithm, not XNA 4.0's: a mirrored matrix decomposes to positive scales and a non-unit quaternion, and a sheared matrix reports success — Matrix::Decompose never checks the determinant: a mirrored matrix returns positive scales, a non-unit quaternion and true where XNA 4.0 negates the largest scale, and a sheared matrix returns true where XNA returns false