cinder.core
cinder.core #
Source: cinder/core/__init__.mojo
Core: math, logging, assertions, allocators, containers, handles, time, file system. No I/O to GPU, audio or window systems lives here.
cinder.core.arena #
Source: cinder/core/arena.mojo
LinearArena: a bump allocator for per-frame scratch memory. One block is allocated up front; alloc_bytes hands out aligned sub-ranges in O(1) and reset returns everything at once. There is no per-allocation free. After warm-up the engine's frame loop allocates only from arenas and pools, which is what makes the zero-allocation steady-state test possible.
struct LinearArena #
struct LinearArena(Movable)Bump allocator over one fixed block. Every address returned is aligned as requested.
Fields:
__init____init__(out self, capacity: Int) raises
Allocatescapacitybytes once. Raises on a non-positive capacity.capacitycapacity(self) -> Int
Usable bytes requested at construction; the 64-byte alignment slack is not counted.usedused(self) -> Int
Bytes handed out since the last reset, including alignment padding.high_waterhigh_water(self) -> Int
Largestused()ever observed; the number to size the arena by.alloc_bytesalloc_bytes( mut self, size: Int, alignment: Int = 16 ) raises -> Pointer[UInt8, MutUntrackedOrigin]
Returnssizebytes aligned toalignment(a power of two <= 64). Raises when exhausted.allocalloc[ T: AnyType ](mut self, count: Int = 1) raises -> Pointer[T, MutUntrackedOrigin]
Uninitialised storage forcountvalues ofT, aligned forT. The caller initialises it.resetreset(mut self)
Makes the whole block available again. Previously returned pointers become dangling.
cinder.core.assertions #
Source: cinder/core/assertions.mojo
Engine assertions: broken invariants abort with an explicit message. cinder_assert is compiled in unless the build defines CINDER_ASSERTS=0 (mojo build -D CINDER_ASSERTS=0), which release builds of the shipped game set and nothing else does. cinder_check is never compiled out and is used where the cost is negligible and the invariant guards memory safety (handle validation, FFI preconditions). Both abort rather than raise: an invariant violation is a bug, not a recoverable condition (section 4 of the brief).
comptime ASSERTS_ENABLED: Bool = get_defined_bool["CINDER_ASSERTS", True]()— Whethercinder_assertis compiled in. Read from -D CINDER_ASSERTS at build time.
def cinder_assert #
def cinder_assert(condition: Bool, message: StaticString)Aborts with message when condition is false, unless asserts are compiled out.
def cinder_check #
def cinder_check(condition: Bool, message: StaticString)Aborts with message when condition is false, in every build.
cinder.core.base64 #
Source: cinder/core/base64.mojo
Base64 decoding (RFC 4648, with or without padding) for data URIs in glTF files.
def decode_base64 #
def decode_base64(text: StringSpan) raises -> List[UInt8]Decodes base64 text; whitespace is skipped and '=' padding is optional.
cinder.core.boxed #
Source: cinder/core/boxed.mojo
Boxed: a value at a stable heap address. Subsystems that hand out Pointers to themselves (Gfx, Resources, Renderer, JobSystem, ...) must never move once those pointers exist. Boxed[T] owns one T on the heap so the owner can move freely while the pointee stays put.
struct Boxed #
struct Boxed[T: Deinitable & Movable](Movable)Owns one T on the heap so pointers to it stay valid while the box itself moves. The value is moved in at construction and destroyed, then freed, when the box is destroyed. ptr() and [] give untracked mutable access; neither may outlive the box.
Fields:
__init____init__(out self, var value: Self.T)ptrptr(self) -> Pointer[Self.T, MutUntrackedOrigin]
A raw pointer valid for the box's lifetime.__getitem____getitem__(ref self) -> ref[MutUntrackedOrigin] Self.T
cinder.core.bytes #
Source: cinder/core/bytes.mojo
Little-endian byte packing for GPU uploads (std140/std430-style layouts are the caller's job).
struct ByteWriter #
struct ByteWriter(Movable, Sized)Appends plain values to a byte buffer. pad_to aligns the length for struct rules.
Fields:
-
bytes: List[UInt8] -
__init____init__(out self, capacity: Int = 256) -
__len____len__(self) -> Int -
clearclear(mut self)
Empties the buffer, keeping its capacity (same asreset). -
u8u8(mut self, v: UInt8)
Appends one byte. -
u32u32(mut self, v: UInt32)
Appendsvas four bytes, little-endian. -
i32i32(mut self, v: Int32)
Appendsvas four bytes, little-endian two's complement. -
f32f32(mut self, v: Float32)
Appends the IEEE-754 bits ofvas four bytes, little-endian. -
vec2vec2(mut self, v: Vec2)
Appends x then y as twof32(8 bytes, no padding). -
vec3vec3(mut self, v: Vec3)
Three floats, no padding (callers addf32orpad_to(16)for vec4 alignment). -
vec3_paddedvec3_padded(mut self, v: Vec3, w: Float32 = 0.0)
Appends x, y, z, thenw(default 0) as fourf32: a vec3 in a 16-byte vec4 slot. -
vec4vec4(mut self, v: Vec4)
Appends x, y, z, w as fourf32(16 bytes). -
mat4mat4(mut self, m: Mat4)
Column-major, matching WGSLmat4x4<f32>. -
pad_topad_to(mut self, alignment: Int)
Zero-fills to the next multiple ofalignment; no-op when already aligned.alignmentmust be positive: 0 or a negative value is a bug andcinder_assertaborts. With assertions compiled out it leaves the bytes unchanged. -
spanspan(self) -> Span[UInt8, origin_of(self.bytes)]
A view of the bytes written so far, borrowed from the writer; invalid after it changes. -
resetreset(mut self)
Empties the writer, keeping its capacity (frame scratch buffers). -
taketake(deinit self) -> List[UInt8]
Consumes the writer and returns its bytes.
cinder.core.cstring #
Source: cinder/core/cstring.mojo
C strings to Mojo Strings, decoding the bytes as UTF-8. C APIs (SDL, the shim, stb) hand back NUL-terminated UTF-8. Converting byte by byte with chr treats every byte as a code point and double-encodes anything outside ASCII, so every conversion goes through string_from_c instead.
def string_from_c #
def string_from_c( p: Optional[Pointer[c_char, MutUntrackedOrigin]], max_len: Int = -1 ) -> StringThe UTF-8 text at p up to its NUL terminator, or up to max_len bytes when max_len is not negative (fixed-size C buffers). A null pointer gives the empty string. Invalid UTF-8 sequences become U+FFFD instead of failing: C text is diagnostic data here and must never make the caller raise. The caller guarantees p points at a terminated string or at least max_len readable bytes.
cinder.core.fs #
Source: cinder/core/fs.mojo
Filesystem helpers with typed errors. Thin on purpose: the asset database layers on top.
struct FileError #
struct FileError(Copyable, Movable, Writable)A failed file operation, with the path and the underlying message.
Fields:
-
path: String -
message: String -
write_towrite_to(self, mut writer: Some[Writer])
def file_exists #
def file_exists(path: String) -> BoolTrue when something exists at path (a file or a directory). Never raises.
def read_bytes #
def read_bytes(path: String) raises FileError -> List[UInt8]Reads a whole file into memory.
def read_text #
def read_text(path: String) raises FileError -> StringReads a whole UTF-8 text file.
def write_bytes #
def write_bytes(path: String, data: Span[UInt8, _]) raises FileErrorWrites (truncating) data to path.
def write_text #
def write_text(path: String, text: String) raises FileErrorWrites (truncating) text to path. Raises FileError carrying the path on failure.
cinder.core.handles #
Source: cinder/core/handles.mojo
Generational handles and the slot pool that issues them. A Handle[Tag] names a slot in a Pool[T, Tag]. The generation counter makes a stale handle (one whose slot was freed and reused) fail validation instead of aliasing a new object. Tag is a phantom type so that, for example, a texture handle cannot be passed where a buffer handle is expected.
struct Handle #
struct Handle[Tag: AnyType]( Boolable, Equatable, Hashable, ImplicitlyCopyable, RegisterPassable, Writable, )A 64-bit generational handle: 32-bit slot index, 32-bit generation. Zero is the null handle.
Fields:
-
index: UInt32 -
generation: UInt32 -
nullnull() -> Handle[Self.Tag]
The null handle (index 0, generation 0); never valid in anyPool. -
is_nullis_null(self) -> Bool
True when the generation is 0, whatever the index; pools never issue generation 0. -
packedpacked(self) -> UInt64
The handle as one integer, for serialization and GPU-side ids. -
from_packedfrom_packed(v: UInt64) -> Handle[Self.Tag]
Inverse ofpacked(): low 32 bits are the index, high 32 bits the generation. -
write_towrite_to(self, mut writer: Some[Writer])
struct Pool #
struct Pool[T: Copyable & Deinitable, Tag: AnyType](Movable)A slot map: O(1) insert, remove and lookup by Handle[Self.Tag], with generation checking. Slots are never reallocated once created, so a Pool holds at most capacity live values; insert raises when full, which keeps steady-state frames free of allocation (section 4 of the brief). Freed slots are recycled through an intrusive free list. Generations start at 1 and skip 0 so the zero handle is never valid.
Fields:
__init____init__(out self, capacity: Int) raises
Creates a pool with room forcapacityvalues (1 <= capacity < 2^32).capacitycapacity(self) -> Int
Number of slots, fixed at construction; the pool never grows past it.livelive(self) -> Int
Number of values currently stored.insertinsert(mut self, var value: Self.T) raises -> Handle[Self.Tag]
Storesvalueand returns its handle. Raises when the pool is full.is_validis_valid(self, h: Handle[Self.Tag]) -> Bool
True whenhnames a live value (right slot, current generation).getget(self, h: Handle[Self.Tag]) raises -> Self.T
A copy of the value behindh; raises on a null, stale or foreign handle. Pooled values are small records (handles, descriptors), so copying is the intended access pattern;updatewrites a value back.updateupdate(mut self, h: Handle[Self.Tag], var value: Self.T) raises
Replaces the value behindh; raises on an invalid handle.removeremove(mut self, h: Handle[Self.Tag]) raises -> Self.T
Removes and returns the value behindh, retiring the handle's generation.handleshandles(self) -> List[Handle[Self.Tag]]
Handles of every live value, in slot order (allocates; for tools and tests).
cinder.core.hash #
Source: cinder/core/hash.mojo
Content hashing: 64-bit FNV-1a over bytes and strings (stable across runs and platforms).
comptime FNV_OFFSET: UInt64 = 14695981039346656037— FNV-1a 64-bit offset basis; also the hash of empty input.comptime FNV_PRIME: UInt64 = 1099511628211— FNV-1a 64-bit prime.
def fnv1a64 #
def fnv1a64(data: Span[UInt8, _]) -> UInt6464-bit FNV-1a of data. Stable across runs and platforms, which is why the asset cooker uses it as a content hash. Not cryptographic: do not use it where collisions could be engineered.
def fnv1a64_string #
def fnv1a64_string(text: String) -> UInt64fnv1a64 of the string's UTF-8 bytes, without a terminator.
def hex64 #
def hex64(v: UInt64) -> StringSixteen lowercase hex digits.
cinder.core.image #
Source: cinder/core/image.mojo
CPU images: RGBA8 load/decode/save through the shim (stb) and perceptual comparison (SSIM). Image owns its pixels in a List[UInt8] (tightly packed RGBA8). ssim is the structural similarity index on luma with an 8x8 box window; golden-image tests compare against it.
struct Image #
struct Image(Copyable, Movable)A tightly packed RGBA8 image.
Fields:
-
width: Int -
height: Int -
pixels: List[UInt8] -
__init____init__(out self, width: Int, height: Int) -
__init____init__( out self, width: Int, height: Int, var pixels: List[UInt8] ) raises -
from_rowsfrom_rows( width: Int, height: Int, rows: List[UInt8], stride: Int ) raises -> Image
Repacks rows ofstridebytes (GPU readback with 256-byte alignment) into a tight image. -
pixelpixel(self, x: Int, y: Int) -> SIMD[DType.uint8, 4]
The RGBA8 value at columnx, rowy; (0, 0) is the first pixel in memory.xmust be in [0, width) andyin [0, height). Anything else is a bug and aborts throughcinder_checkin every build (an unchecked index would read outside the pixel list, or silently wrap into the next row). -
set_pixelset_pixel(mut self, x: Int, y: Int, value: SIMD[DType.uint8, 4])
Writes RGBA8valueat columnx, rowy; addressed and range-checked likepixel. -
swap_rbswap_rb(mut self)
BGRA <-> RGBA in place (swapchain readbacks are BGRA). -
lumaluma(self, x: Int, y: Int) -> Float64
Rec. 709 luma of the pixel at (x,y) in [0, 255], from the stored (gamma-encoded) values; alpha is ignored.comparecomputes SSIM on this value.
def load_image #
def load_image(lib: NativePtr, path: String) raises -> ImageLoads the image file at path through the shim's stb_image and returns it as RGBA8. Any channel count in the file is expanded to four. lib must point at the loaded native shim. Raises with stb's failure reason when the file cannot be read or decoded. The stb buffer is copied into the Image and freed before returning.
def decode_image #
def decode_image(lib: NativePtr, bytes: Span[UInt8, _]) raises -> ImageDecodes an encoded image held in memory (stb_image) to RGBA8. Raises with stb's failure reason on undecodable data; the shim also rejects inputs larger than 2^31 - 1 bytes. The stb buffer is copied into the Image and freed before returning.
def save_png #
def save_png(lib: NativePtr, path: String, img: Image) raisesWrites img to path as an RGBA8 PNG through the shim's stb_image_write. Raises when the file cannot be written; the shim also refuses an image with zero width or height.
struct ImageDiff #
struct ImageDiff(ImplicitlyCopyable, Movable, Writable)Result of compare: SSIM on luma, plus the raw pixel statistics tests may also bound.
Fields:
-
ssim: Float64 -
max_channel_delta: Int -
differing_pixels: Int — Pixels where any channel differs by more thantolerancepassed tocompare. -
write_towrite_to(self, mut w: Some[Writer])
def compare #
def compare( a: Image, b: Image, tolerance: Int = 2, window: Int = 8 ) raises -> ImageDiffSSIM (luma, non-overlapping window boxes, K1 = 0.01, K2 = 0.03, L = 255) and pixel deltas.
cinder.core.jobs #
Source: cinder/core/jobs.mojo
The job system: a work-stealing thread pool with dependency counters. Design (ADR-0008, docs/THREADING.md): - One worker per logical core minus one (the main thread is the remaining core), each with a fixed-capacity Chase-Lev deque of job indices. A worker pushes and pops at the bottom of its own deque; idle workers steal from the top of others'. - Jobs are JobFn thin function pointers plus an untyped data pointer; the caller owns the data for the job's lifetime. Each job decrements a Counter when it finishes; wait on a counter helps run jobs until it reaches zero, so waiting never idles a core. - OS threads and semaphores come from the native shim (cn_thread_*, cn_semaphore_*); worker entry points are Mojo abi("C") functions (verified by spike 4). Everything else is Mojo with Atomic operations. - No allocation after construction: the job table, deques and counters are fixed-capacity. submit returns False when the system is saturated; callers then run the job inline.
comptime JobFn = def(Pointer[NoneType, MutUntrackedOrigin]) thin -> None— Signature of a job: receives the untyped data pointer it was submitted with.comptime INVALID_JOB: Int32 = -1— Job index meaning "no job":Deque.popandDeque.stealreturn it when nothing was taken.comptime MAX_WORKERS = 64— Largestworker_countthatJobSystemaccepts.
struct Counter #
struct Counter(Movable)Completion counter: incremented per submitted job, decremented when each finishes.
Fields:
-
remaining: Atomic[Int32] -
__init____init__(out self) -
loadload(self) -> Int32
Jobs still outstanding on this counter (acquire load); 0 when all have finished.
struct Job #
struct Job(ImplicitlyCopyable, Movable)One unit of work in the job table.
Fields:
-
run: JobFn -
data: Pointer[NoneType, MutUntrackedOrigin] -
counter: Optional[Pointer[Counter, MutUntrackedOrigin]] -
__init____init__( out self, run: JobFn, data: Pointer[NoneType, MutUntrackedOrigin], counter: Optional[Pointer[Counter, MutUntrackedOrigin]], )
struct Deque #
struct Deque(Movable)Chase-Lev work-stealing deque of job indices with a fixed power-of-two capacity. The owner thread calls push and pop; any thread calls steal. Indices wrap through the mask; push fails when the deque is full instead of growing.
Fields:
__init____init__(out self, capacity: Int)pushpush(mut self, job: Int32) -> Bool
Owner only. Returns False when full.poppop(mut self) -> Int32
Owner only. Returns INVALID_JOB when empty.stealsteal(mut self) -> Int32
Any thread. Returns INVALID_JOB when empty or when it lost a race (caller retries elsewhere).
struct Shared #
struct Shared(Movable)State shared by all workers; lives at a stable heap address for the system's lifetime.
Fields:
-
jobs: Allocation[Job] -
job_capacity: Int -
next_job: Atomic[Int64] -
deques: List[Deque] -
worker_count: Int -
stop: Atomic[Int32] -
idle: Atomic[Int32] -
semaphore: Optional[Pointer[CnSemaphore, MutUntrackedOrigin]] -
executed: Atomic[Int64] -
lib: Pointer[CinderNative, MutUntrackedOrigin]
struct WorkerContext #
struct WorkerContext(Movable)Passed to each worker thread entry: which deque is mine and where the shared state lives.
Fields:
-
shared: Pointer[Shared, MutUntrackedOrigin] -
index: Int -
__init____init__( out self, shared: Pointer[Shared, MutUntrackedOrigin], index: Int )
struct JobSystem #
struct JobSystem(Movable)Owns the worker threads, the shared state and the job table. Deque 0 belongs to the main thread. Hold one instance for the life of the program (section 4: the job system runs everything that is not SDL or presentation). __deinit__ stops and joins every worker.
Fields:
__init____init__( out self, lib: Pointer[CinderNative, MutUntrackedOrigin], worker_count: Int, job_capacity: Int = 1 << 14, ) raises
Startsworker_countworkers (0 runs everything on the calling thread).job_capacitymust be a power of two; it bounds the number of jobs in flight betweenresetcalls.worker_countworker_count(self) -> Int
Number of worker threads started, not counting the main thread (which owns deque 0).executedexecuted(self) -> Int
Jobs completed since construction (diagnostics).submitsubmit( mut self, run: JobFn, data: Pointer[NoneType, MutUntrackedOrigin], counter: Optional[Pointer[Counter, MutUntrackedOrigin]], ) -> Bool
Queues a job from the main thread. Incrementscounterbefore the job can run. Returns False when the job table or the main deque is full; the caller must then run it inline.waitwait(mut self, counter: Pointer[Counter, MutUntrackedOrigin])
Runs jobs on the calling thread untilcounterreaches zero.resetreset(mut self)
Recycles the job table. Only valid when no job is queued or running (e.g. at frame start).
cinder.core.log #
Source: cinder/core/log.mojo
Structured, levelled logging. A Logger owns a minimum level and a sink. Records carry a level, a category and a message plus optional key=value fields, and are formatted as one line: [LEVEL] category: message key=value .... Sinks are a trait so tests capture records in memory and the engine routes them to stderr, a file or the debug console. Logging never raises; a failing sink drops the record.
struct LogLevel #
struct LogLevel( Comparable, Equatable, ImplicitlyCopyable, RegisterPassable, Writable )Severity, ordered. Compare with the usual operators.
Fields:
-
value: UInt8 -
tracetrace() -> LogLevel
Severity 0, the lowest: a logger at this level passes everything. -
debugdebug() -> LogLevel
Severity 1, betweentraceandinfo. -
infoinfo() -> LogLevel
Severity 2; the defaultLoggerminimum level. -
warnwarn() -> LogLevel
Severity 3, betweeninfoanderror. -
errorerror() -> LogLevel
Severity 4, the highest named level. -
namename(self) -> StaticString
Label printed in records: TRACE, DEBUG, INFO, WARN, or ERROR for 4 and above. -
write_towrite_to(self, mut writer: Some[Writer])
struct LogField #
struct LogField(Copyable, Movable, Writable)One key=value pair attached to a record.
Fields:
-
key: String -
value: String -
write_towrite_to(self, mut writer: Some[Writer])
struct LogRecord #
struct LogRecord(Copyable, Movable, Writable)A formatted log entry.
Fields:
-
level: LogLevel -
category: String -
message: String -
fields: List[LogField] -
__init____init__( out self, level: LogLevel, category: String, message: String, var fields: List[LogField], ) -
write_towrite_to(self, mut writer: Some[Writer])
trait LogSink #
trait LogSinkReceives formatted records. Implementations must not raise.
emitemit(mut self, record: LogRecord)
Handles one record that passed the filter. Must not raise: drop the record instead.
struct PrintSink #
struct PrintSink(LogSink, Movable)Writes each record as one line to standard output.
Fields:
-
emitted: Int — Number of records written so far. -
__init____init__(out self) -
emitemit(mut self, record: LogRecord)
Prints the record as one line to standard output and incrementsemitted.
struct MemorySink #
struct MemorySink(LogSink, Movable)Keeps every record; used by tests and the in-engine console.
Fields:
-
records: List[LogRecord] -
__init____init__(out self) -
emitemit(mut self, record: LogRecord)
Appends a copy of the record torecords, which grows without bound.
struct Logger #
struct Logger[S: LogSink & Movable & Deinitable](Movable)Filters by minimum level and forwards to its sink.
Fields:
-
min_level: LogLevel -
sink: Self.S -
__init____init__( out self, var sink: Self.S, min_level: LogLevel = LogLevel.info() ) -
enabledenabled(self, level: LogLevel) -> Bool
True whenlevel>=min_level; check it before building costly messages. -
loglog( mut self, level: LogLevel, category: String, message: String, var fields: List[LogField], )
Emits a record whenlevelpasses the filter. Field lists are consumed. -
loglog(mut self, level: LogLevel, category: String, message: String)
Emits a record without fields whenlevelpasses the filter. -
tracetrace(mut self, category: String, message: String)
Logsmessageundercategoryat TRACE, subject tomin_level. -
debugdebug(mut self, category: String, message: String)
Logsmessageundercategoryat DEBUG, subject tomin_level. -
infoinfo(mut self, category: String, message: String)
Logsmessageundercategoryat INFO, subject tomin_level. -
warnwarn(mut self, category: String, message: String)
Logsmessageundercategoryat WARN, subject tomin_level. -
errorerror(mut self, category: String, message: String)
Logsmessageundercategoryat ERROR, subject tomin_level.
cinder.core.math #
Source: cinder/core/math/__init__.mojo
SIMD math for the engine. Conventions (docs/ARCHITECTURE.md, fixed): right-handed, Y up, -Z forward, metres, column-major matrices, reverse-Z depth with an infinite far plane. All types are plain 32-bit float values backed by SIMD[DType.float32, 4]; a Vec3 keeps its fourth lane at zero.
cinder.core.math.mat4 #
Source: cinder/core/math/mat4.mojo
Mat4: a column-major 4x4 float matrix, as WGSL and glTF store it.
struct Mat4 #
struct Mat4(Equatable, ImplicitlyCopyable, RegisterPassable, Writable)Column-major 4x4 matrix. c0..c3 are the columns; element (row r, column c) is cC[r].
Fields:
-
c0: F4 -
c1: F4 -
c2: F4 -
c3: F4 -
identityidentity() -> Mat4
The identity matrix. -
zerozero() -> Mat4
All sixteen elements zero; also whatinversereturns for a singular matrix. -
from_rowsfrom_rows(r0: Vec4, r1: Vec4, r2: Vec4, r3: Vec4) -> Mat4
Builds a matrix from its rows (handy for literals written the way maths books print them). -
translationtranslation(t: Vec3) -> Mat4
Translation byt(metres): the identity withtin the last column. -
scalingscaling(s: Vec3) -> Mat4
Scale bys.x(),s.y(),s.z()along the x, y and z axes. -
rotationrotation(q: Quat) -> Mat4
Rotation matrix of a unit quaternion. -
trstrs(t: Vec3, r: Quat, s: Vec3) -> Mat4
Translation * Rotation * Scale, the glTF node transform order. -
look_atlook_at(eye: Vec3, target: Vec3, up: Vec3) -> Mat4
Right-handed view matrix: the camera looks down -Z, with +Y up and +X right. -
perspective_reverse_z_infiniteperspective_reverse_z_infinite( fov_y: Float32, aspect: Float32, near: Float32 ) -> Mat4
Right-handed perspective projection, reverse-Z (near maps to 1) with an infinite far plane, clip depth in [0, 1] as wgpu expects. -
orthographic_reverse_zorthographic_reverse_z( left: Float32, right: Float32, bottom: Float32, top: Float32, near: Float32, far: Float32, ) -> Mat4
Right-handed orthographic projection with reverse-Z (near maps to 1, far to 0). -
columncolumn(self, c: Int) -> Vec4
Columnc(0 to 3) as a Vec4. Any other index is a bug:cinder_assertaborts. With assertions compiled out (-D CINDER_ASSERTS=0) the index wraps toc & 3. -
__getitem____getitem__(self, row: Int, col: Int) -> Float32
Element (row,col); both indices are checked likerowandcolumn. -
rowrow(self, r: Int) -> Vec4
Rowr(0 to 3), gathered from the four columns. Any other index is a bug:cinder_assertaborts. With assertions compiled out the index wraps tor & 3. -
to_quatto_quat(self) -> Quat
Rotation of an orthonormal (possibly scaled) matrix's upper 3x3 (Shepperd's method, choosing the largest diagonal term for stability). Scale is removed first. -
transform_pointtransform_point(self, p: Vec3) -> Vec3
Applies the affine part to a point (w = 1), ignoring any projective row. -
transform_vectortransform_vector(self, v: Vec3) -> Vec3
Applies the linear part to a direction (w = 0). -
project_pointproject_point(self, p: Vec3) -> Vec3
Full projective transform with perspective divide. -
transposetranspose(self) -> Mat4
Rows and columns swapped; for a pure rotation this is also its inverse. -
determinantdeterminant(self) -> Float32
Determinant of the full 4x4 matrix, by expansion in 2x2 minors. Exactly 0 is what makesinversereturn the zero matrix; a negative value means the matrix mirrors space (Transform.from_mat4relies on this). -
inverseinverse(self) -> Mat4
General inverse by cofactors. A singular matrix returns the zero matrix; callers that need to detect that checkdeterminant()first. -
approx_equalapprox_equal(self, o: Mat4, eps: Float32 = EPSILON) -> Bool
True when every element matches withinepsunderapprox_eq. -
write_towrite_to(self, mut writer: Some[Writer])
cinder.core.math.quat #
Source: cinder/core/math/quat.mojo
Quat: a unit quaternion (x, y, z, w) representing a rotation.
struct Quat #
struct Quat(Equatable, ImplicitlyCopyable, RegisterPassable, Writable)Rotation quaternion. Lanes are (x, y, z, w); w is the scalar part.
Fields:
-
data: F4 -
__init____init__(out self, x: Float32, y: Float32, z: Float32, w: Float32) -
identityidentity() -> Quat
The no-rotation quaternion (0, 0, 0, 1). -
from_axis_anglefrom_axis_angle(axis: Vec3, angle: Float32) -> Quat
Rotation ofangleradians about the unit vectoraxis(right-handed). -
from_eulerfrom_euler(yaw: Float32, pitch: Float32, roll: Float32) -> Quat
Yaw about +Y, then pitch about +X, then roll about +Z (applied in that order to a body). -
xx(self) -> Float32
Lane 0, the x term of the vector part. -
yy(self) -> Float32
Lane 1, the y term of the vector part. -
zz(self) -> Float32
Lane 2, the z term of the vector part. -
ww(self) -> Float32
Lane 3, the scalar part: cos(angle / 2) for a unit quaternion. -
vector_partvector_part(self) -> Vec3
(x, y, z) as a Vec3: the rotation axis times sin(angle / 2) for a unit quaternion. -
dotdot(self, o: Quat) -> Float32
4D dot product; negative when the two are on opposite hemispheres (seeslerp). -
lengthlength(self) -> Float32
Euclidean norm over all four lanes; 1 for a unit quaternion. -
normalizednormalized(self) -> Quat
Unit quaternion; the zero quaternion becomes the identity. -
conjugateconjugate(self) -> Quat
The vector part negated; for a unit quaternion this is the inverse rotation. -
inverseinverse(self) -> Quat
Inverse for any non-zero quaternion (equals the conjugate for unit quaternions). The zero quaternion has no inverse and returns the zero quaternion, asMat4.inversereturns the zero matrix for a singular matrix. -
rotaterotate(self, v: Vec3) -> Vec3
Rotatesvby this unit quaternion: v' = v + 2w(u x v) + 2u x (u x v). -
nlerpnlerp(self, o: Quat, t: Float32) -> Quat
Normalised linear interpolation along the shorter arc. -
slerpslerp(self, o: Quat, t: Float32) -> Quat
Spherical interpolation along the shorter arc; falls back to nlerp when nearly parallel. -
approx_equalapprox_equal(self, o: Quat, eps: Float32 = EPSILON) -> Bool
True when both represent the same rotation (q and -q are equal rotations). -
write_towrite_to(self, mut writer: Some[Writer])
cinder.core.math.scalar #
Source: cinder/core/math/scalar.mojo
Scalar helpers shared by the vector, quaternion and matrix types.
comptime EPSILON: Float32 = 1e-6— Default tolerance for approximate comparisons of unit-scale quantities.
def radians #
def radians(deg: Float32) -> Float32Converts degrees to radians.
def degrees #
def degrees(rad: Float32) -> Float32Converts radians to degrees.
def clamp #
def clamp(x: Float32, lo: Float32, hi: Float32) -> Float32Clamps x to [lo, hi].
def saturate #
def saturate(x: Float32) -> Float32Clamps x to [0, 1].
def lerp #
def lerp(a: Float32, b: Float32, t: Float32) -> Float32Linear interpolation; exact at t = 0 and t = 1.
def approx_eq #
def approx_eq(a: Float32, b: Float32, eps: Float32 = EPSILON) -> BoolTrue when |a - b| <= eps * max(1, |a|, |b|): absolute near zero, relative elsewhere.
cinder.core.math.transform #
Source: cinder/core/math/transform.mojo
Transform: translation, rotation and scale as separate terms (poses, animation keys).
struct Transform #
struct Transform(Equatable, ImplicitlyCopyable, Movable, Writable)A TRS transform. Composition order is scale, then rotation, then translation.
Fields:
-
translation: Vec3 -
rotation: Quat -
scale: Vec3 -
identityidentity() -> Transform
Zero translation, identity rotation and unit scale. -
from_mat4from_mat4(m: Mat4) -> Transform
Decomposes a matrix without shear: translation from the last column, scale from the column lengths, rotation from the normalised columns. A mirrored matrix (negative determinant) has no proper rotation; the reflection is folded into a negative x scale and the rotation is taken from the matrix with its first column negated, soto_mat4()rebuilds the input. -
to_mat4to_mat4(self) -> Mat4
The equivalent matrix,Mat4.trs: scale, then rotation, then translation. -
lerplerp(self, o: Transform, t: Float32) -> Transform
Linear translation and scale, normalised-lerp rotation along the shorter arc. -
approx_equalapprox_equal(self, o: Transform, eps: Float32 = EPSILON) -> Bool
True when translation, rotation and scale match withineps(q and -q are equal). -
write_towrite_to(self, mut writer: Some[Writer])
cinder.core.math.vec #
Source: cinder/core/math/vec.mojo
Vec2, Vec3 and Vec4: 32-bit float vectors backed by SIMD registers.
comptime F2 = SIMD[DType.float32, 2]— Storage ofVec2: two float32 lanes.comptime F4 = SIMD[DType.float32, 4]— Storage ofVec3,Vec4,Quatand eachMat4column: four float32 lanes.
struct Vec2 #
struct Vec2(Equatable, ImplicitlyCopyable, RegisterPassable, Writable)A 2D vector.
Fields:
-
data: F2 -
__init____init__(out self, x: Float32, y: Float32) -
zerozero() -> Vec2
(0, 0). -
xx(self) -> Float32
Lane 0. -
yy(self) -> Float32
Lane 1. -
dotdot(self, o: Vec2) -> Float32
Sum of the component-wise products. -
length_squaredlength_squared(self) -> Float32
Squared Euclidean length; avoids the square root when only comparing lengths. -
lengthlength(self) -> Float32
Euclidean length. -
approx_equalapprox_equal(self, o: Vec2, eps: Float32 = EPSILON) -> Bool
True when x and y each match withinepsunderapprox_eq. -
write_towrite_to(self, mut writer: Some[Writer])
struct Vec3 #
struct Vec3(Equatable, ImplicitlyCopyable, RegisterPassable, Writable)A 3D vector. The fourth SIMD lane is always zero so 4-wide operations stay exact.
Fields:
-
data: F4 -
__init____init__(out self, x: Float32, y: Float32, z: Float32) -
zerozero() -> Vec3
(0, 0, 0). -
oneone() -> Vec3
(1, 1, 1), the unit scale. -
unit_xunit_x() -> Vec3
+X, the engine's right axis. -
unit_yunit_y() -> Vec3
+Y, the engine's up axis (right-handed, Y-up). -
unit_zunit_z() -> Vec3
+Z, pointing backwards: the engine's forward is -Z. -
forwardforward() -> Vec3
The engine's forward direction, -Z. -
splatsplat(v: Float32) -> Vec3
All three components set tov(the fourth lane stays zero). -
xx(self) -> Float32
Lane 0. -
yy(self) -> Float32
Lane 1. -
zz(self) -> Float32
Lane 2. -
__getitem____getitem__(self, i: Int) -> Float32 -
with_xwith_x(self, v: Float32) -> Vec3
A copy with x replaced byv. -
with_ywith_y(self, v: Float32) -> Vec3
A copy with y replaced byv. -
with_zwith_z(self, v: Float32) -> Vec3
A copy with z replaced byv. -
dotdot(self, o: Vec3) -> Float32
Sum of the component-wise products of x, y and z. -
crosscross(self, o: Vec3) -> Vec3
Right-handed cross productself x o(unit_x cross unit_y is unit_z). -
length_squaredlength_squared(self) -> Float32
Squared Euclidean length; avoids the square root when only comparing lengths. -
lengthlength(self) -> Float32
Euclidean length. -
distancedistance(self, o: Vec3) -> Float32
Euclidean distance too. -
normalizednormalized(self) -> Vec3
Unit vector in the same direction; zero stays zero. -
lerplerp(self, o: Vec3, t: Float32) -> Vec3
self + (o - self) * tper component;tis unclamped, so it extrapolates. -
minmin(self, o: Vec3) -> Vec3
Component-wise minimum. -
maxmax(self, o: Vec3) -> Vec3
Component-wise maximum. -
absabs(self) -> Vec3
Component-wise absolute value. -
max_componentmax_component(self) -> Float32
Largest of x, y and z by signed value (not by magnitude; useabs()first for that). -
approx_equalapprox_equal(self, o: Vec3, eps: Float32 = EPSILON) -> Bool
True when x, y and z each match withinepsunderapprox_eq. -
to_vec4to_vec4(self, w: Float32) -> Vec4
(x, y, z,w): pass 1 for a point and 0 for a direction. -
write_towrite_to(self, mut writer: Some[Writer])
struct Vec4 #
struct Vec4(Equatable, ImplicitlyCopyable, RegisterPassable, Writable)A 4D vector, also used for homogeneous points and colours.
Fields:
-
data: F4 -
__init____init__(out self, x: Float32, y: Float32, z: Float32, w: Float32) -
zerozero() -> Vec4
(0, 0, 0, 0). -
xx(self) -> Float32
Lane 0. -
yy(self) -> Float32
Lane 1. -
zz(self) -> Float32
Lane 2. -
ww(self) -> Float32
Lane 3: 1 for a point, 0 for a direction, alpha for a colour. -
__getitem____getitem__(self, i: Int) -> Float32 -
xyzxyz(self) -> Vec3
(x, y, z) as a Vec3, dropping w without a perspective divide. -
dotdot(self, o: Vec4) -> Float32
Sum of the component-wise products over all four lanes. -
lengthlength(self) -> Float32
Euclidean length over all four lanes. -
approx_equalapprox_equal(self, o: Vec4, eps: Float32 = EPSILON) -> Bool
True when all four components match withinepsunderapprox_eq. -
write_towrite_to(self, mut writer: Some[Writer])
cinder.core.profile #
Source: cinder/core/profile.mojo
Tracy profiling for the engine: zones, frame marks, plots and messages. Profiling is off until Profiler.start() (nothing listens on the network before that) and every call is a cheap no-op while it is off. Zone opens on construction and closes when it is destroyed. Mojo destroys a value right after its last use, so end the zone explicitly where it should close: var z = profiler.zone("render") ... # the instrumented work _ = z^ String lifetimes: Tracy copies zone names, zone text and messages during the call, but keys plots by the name pointer and reads it for the rest of the program. Profiler.plot therefore interns each plot name once in a table that is never freed (one small allocation per distinct name, the first time it is plotted while profiling runs).
comptime COLOR_RENDER: UInt32 = 0x3F7FBF— Zone colour (0xRRGGBB) for rendering.comptime COLOR_PHYSICS: UInt32 = 0xBF7F3F— Zone colour (0xRRGGBB) for physics and fixed steps.comptime COLOR_ANIM: UInt32 = 0x7FBF3F— Zone colour (0xRRGGBB) for animation.comptime COLOR_AUDIO: UInt32 = 0xBF3F7F— Zone colour (0xRRGGBB) for audio.comptime COLOR_ASSETS: UInt32 = 0x7F7F7F— Zone colour (0xRRGGBB) for asset loading.
struct Profiler #
struct Profiler(ImplicitlyCopyable, Movable)A handle to the shim's Tracy client; copies share the process-wide profiler and its plot name table.
Fields:
-
lib: NativePtr -
__init____init__(out self, lib: NativePtr) -
availableavailable(self) -> Bool
Whether the shim was built with Tracy. -
startstart(self) -> Bool
Starts the Tracy client (idempotent). Returns False when Tracy is not built in. -
stopstop(self)
Shuts the Tracy client down if it is running; a no-op otherwise or without Tracy. -
is_startedis_started(self) -> Bool
Whether the Tracy client is running (startwithoutstop). -
is_connectedis_connected(self) -> Bool
Whether a Tracy viewer is connected; always False while stopped or without Tracy. -
zonezone(self, name: String, color: UInt32 = 0) -> Zone
Opens a zone namednamethat ends when the returnedZoneis destroyed.coloris 0xRRGGBB (0 keeps Tracy's default; see theCOLOR_*constants). Mojo destroys a value after its last use, so end the zone explicitly with_ = z^where it should close. While profiling is off the zone is inert and itsidis 0. -
frame_markframe_mark(self)
Marks the end of a frame. -
plotplot(self, name: String, value: Float64)
Addsvalueto the Tracy plot calledname. Does nothing while profiling is off. Tracy keeps the name pointer for the program's life, so the name is interned (copied once into a never-freed table); later calls with the same name reuse that copy and do not allocate. -
plot_name_countplot_name_count(self) -> Int
How many distinct plot names have been interned (shared by every copy). -
messagemessage(self, text: String)
Sendstextto Tracy's message log (info severity); a no-op while profiling is off.
struct Zone #
struct Zone(Movable)An open profiling zone; ends when destroyed. id is 0 while profiling is off.
Fields:
-
lib: NativePtr -
id: UInt64 -
__init____init__(out self, lib: NativePtr, name: String, color: UInt32) -
texttext(self, note: String)
Attaches text to the open zone.
cinder.core.ring #
Source: cinder/core/ring.mojo
RingBuffer: a fixed-capacity FIFO queue with no allocation after construction.
struct RingBuffer #
struct RingBuffer[T: Copyable & Deinitable](Movable, Sized)Single-threaded bounded FIFO. push returns False when full; pop returns None when empty. Capacity must be a power of two so index wrapping is a mask. Cross-thread queues live in the native shim (CnEventQueue); this type is for in-engine command and event buffering.
Fields:
__init____init__(out self, capacity: Int) raisescapacitycapacity(self) -> Int
Number of slots, a power of two fixed at construction.__len____len__(self) -> Intis_emptyis_empty(self) -> Bool
True when nothing is queued (popwould return None).is_fullis_full(self) -> Bool
True when every slot is taken (pushwould return False).pushpush(mut self, var value: Self.T) -> Bool
Appendsvalue; returns False (and drops nothing already queued) when full.poppop(mut self) -> Optional[Self.T]
Removes and returns the oldest value, or None when empty.peekpeek(self) raises -> Self.T
A copy of the oldest value; raises when empty.clearclear(mut self)
Pops and destroys every queued value, oldest first.
cinder.core.time #
Source: cinder/core/time.mojo
Time: a monotonic clock and the fixed-timestep accumulator that drives the simulation. The frame loop (section 4 of the brief) simulates at a fixed 60 Hz and renders at whatever rate the display allows, interpolating between the last two simulation states with alpha.
comptime NS_PER_SECOND: Int = 1_000_000_000— Nanoseconds per second.
struct Clock #
struct Clock(Movable)Monotonic wall clock in nanoseconds, with per-frame deltas.
Fields:
__init____init__(out self)now_nsnow_ns(self) -> Int
Currentperf_counter_ns()reading. Monotonic, but its origin is arbitrary (not the clock's creation), so only differences between readings are meaningful.elapsed_secondselapsed_seconds(self) -> Float64
Seconds since the clock was created.ticktick(mut self) -> Float64
Seconds since the previoustick(or creation). Never negative.
struct FixedStep #
struct FixedStep(ImplicitlyCopyable, Movable)Fixed-timestep accumulator. Feed real frame times with advance; it returns how many simulation steps of step_seconds to run (capped at max_steps_per_frame to avoid the spiral of death) and leaves alpha() as the interpolation factor for rendering between the previous and current simulation state.
Fields:
-
step_seconds: Float64 -
max_steps_per_frame: Int -
__init____init__(out self, hz: Float64 = 60.0, max_steps_per_frame: Int = 8) -
advanceadvance(mut self, frame_seconds: Float64) -> Int
Accounts forframe_secondsof real time and returns the number of steps to simulate. -
alphaalpha(self) -> Float64
Fraction of a step accumulated but not yet simulated, in [0, 1). -
total_stepstotal_steps(self) -> Int
Sum of every step countadvancehas returned.