Modules
A window drawn by the graphics card from a scene described in Elixir.
A Quake alias model (a Cauldron3D.Mesh posed by keyframes, as read by
Cauldron3D.Formats.Mdl) uploaded for drawing: one mesh per keyframe pose, every one
with the same vertices in the same order and the same indices, so a
CauldronGPU.Pose blends between any two; each skin as a base texture and, when it
has palette colours 224 to 254, a glow texture holding only those. Skin textures have
no mipmaps: every skin is read at full size, as Quake reads it.
Flat pictures turned to face the camera — sprites, particles, beams seen side on — as one mesh, rebuilt each tick and put under the same mesh id.
A Cauldron3D.Bsp world uploaded for drawing: one mesh per brush model, a material per
texture and lightmap page, the world's lightmaps packed into atlas pages.
A BSP world's face lightmaps packed into pages of luxels, row by row, tallest first. A
face's place is page_size luxels wide per slot; a page holds slots slots side by
side (the most light styles any face has, at most four), slot k holding each face's
lightmap for its k-th style, so a page is page_size * slots luxels wide and as tall
as its rows need.
A BSP world's textures uploaded as RGBA: the base picture of each, and for a :quake
world a glow picture holding only its full-bright colours (palette 224 and up) when it
has any. Colour 255 of a :masked texture is see-through.
The eye: a position and a rotation (looking down its -Z with +Y up), a vertical field of
view in radians, and near and far distances. snap: true places it without
interpolating from where it was on the previous tick.
A picture the renderer draws into: width × height RGBA pixels kept on the card. A
canvas is a texture, so its handle can be drawn by sprites, warped by a column layer,
shown as the overlay or used by a material. It starts transparent.
A texture redrawn column by column into a target, one layer of a {:layers, [layer]}
change: a warp given as a table.
What surrounds the scene: a sky shaded from sky_top through sky_horizon to
sky_ground, ambient light at ambient_intensity for surfaces without a lightmap,
exponential fog of fog_color thickening at fog_density per unit, exposure
before tone mapping, and shadow_distance, the half width of the square around the
camera that the shadow-casting light covers, and reflections, how strongly surfaces
mirror the sky. With ray-traced ambient occlusion requested, ao_radius is how far
occluders are looked for and ao_strength how much they darken (0 to 1). With
upscaling requested, frames are drawn at render_scale of the window's size (0.25 to
A mesh, texture or material held by the renderer. Once the handle is garbage collected the renderer frees the object as soon as no scene entry uses it: a mesh or material when no instance names it, a texture when no material does. A material's handle keeps the texture handles it uses.
The renderer in its own OS process (priv/native/<system architecture>/cauldron_gpu_host),
so a crash in it leaves the VM running. The functions take the same arguments and
return the same values as CauldronGPU's; a caller switches by module.
The scene a host renderer holds, rebuilt from the changes sent to it: meshes, textures
and materials, instances with their latest transform and pose, lights, camera,
environment, effects, light styles, overlay, screen tint and 2D layers. replay/1 lists the changes that give a new renderer the same
scene.
A mesh placed in the scene with one material per mesh part (the last material serves
any further parts). hidden instances are kept but not drawn; shadows: false keeps
an instance out of the shadow map; snap: true places it without interpolating from
its previous tick.
A light in the scene. :directional lights shine along direction from everywhere;
:point lights shine from position out to range; :spot lights also narrow to a
cone around direction, full inside inner_cone radians and none past outer_cone.
intensity scales color. The first directional light with shadows: true casts
shadows.
How a surface reflects light, in glTF's metallic-roughness terms.
Triangles to upload: vertices, u32 indices and parts.
The compiled renderer: priv/native/<system architecture>/cauldron_gpu.so, loaded when
the module loads. Call through CauldronGPU; these functions take and return the raw
values the C++ side uses.
RGBA pixels as a PNG file, for saving what CauldronGPU.capture/2 returns.
Transforms standing a model made in map axes (x forward, y left, z up) at a point of a
map, in the renderer's frame, matching CauldronGPU.Bsp.transform/1 and
CauldronGPU.Bsp.point/2: map units times scale metres, +Z up turned to +Y up.
How an instance's mesh is bent this tick, applied on the graphics card before drawing, shadows and ray tracing.
Rotations as unit quaternions {x, y, z, w}, in the renderer's frame: right-handed,
+Y up, the camera looking down -Z.
A Cauldron2D.Sectors.Map uploaded for drawing: one mesh holding every floor,
ceiling and wall, a material per picture, and a sky cylinder.
Floors and ceilings of a sector map as CauldronGPU.Sectors.Surfaces surfaces.
Sector light levels as a lightmap: one 256×1 texture holding the brightness of every
light level 0..255, and the lightmap coordinates that read level n from it.
A Cauldron2D.Sectors.Map drawn while its sectors move: doors and lifts change
heights, lights flicker, switches and animated pictures change what sides and flats
show. Each sector is one mesh and one instance — its floors, ceilings and the walls
facing into it — and update/5 rebuilds only the sectors that changed and their
neighbours. Each sector's light level is held in a lightmap with a row per sector
(CauldronGPU.Sectors.Live.Lightmap), put again whenever a light changes, and turned
into light falling with distance by a light table
(CauldronGPU.Sectors.Live.LightTable) the caller puts in its environment with
light_space: :display
The surfaces of a sector map sector by sector, from its sectors and sides as they are
now: each sector's floors and ceilings over its subsectors' polygons
(CauldronGPU.Sectors.Flats.polygons/1), and the walls facing into it
(CauldronGPU.Sectors.Walls, with its pegging and sky rules). Floors and ceilings
whose picture marks a sky, and the upper walls left out between two sky ceilings
(from the lower ceiling up to the higher, facing into the higher sector), are sky
surfaces keyed :sky.
Sector light falling with distance, as an CauldronGPU.Environment light_table:
column n of 256 is light level n (as CauldronGPU.Sectors.Live.Lightmap writes
it), row r the distance r / (rows - 1) of the table's reach, and each texel the
share of a colour's display value left by the light table
Cauldron2D.Sectors.Light.table/3 picks for that level and distance, as
(maps - table) / maps. It is meant for light_space: :display.
Every sector's light level as a lightmap, for a CauldronGPU.Sectors.Live.LightTable
to turn into light: a texture three texels wide and one row per sector, the row's
texels the sector's light level with -16, 0 and 16 added (a wall's contrast),
each written as (level + 0.5) / 256 with the level clamped to 0..255, the column of
the light table that level reads.
CauldronGPU.Sectors.Live.Geometry surfaces gathered into one CauldronGPU.Mesh,
one part per picture, each corner's lightmap coordinates reading its sector's row of a
CauldronGPU.Sectors.Live.Lightmap of count sectors.
Pictures of a Cauldron2D.Sectors.Pictures set uploaded on first use, each through a
light table: table nil shows the palette's own colours, table n each colour index
first mapped through the set's table n (as a fixed light table draws it). Textures
and materials are kept by {picture, table} and made once.
A sky picture laid out as Doom draws its sky (CauldronGPU.Sectors.Sky: 1024 picture
columns to a full turn, one picture row per 1/160 of elevation's tangent, row 100 at
the horizon, the top and bottom rows carried on above and below), as the six faces of
an CauldronGPU.Environment {:box, faces} sky.
A sky picture wrapped round the inside of a cylinder, as
CauldronGPU.Sectors.Surfaces surfaces keyed :sky, laid out as Doom draws its sky:
1024 picture columns to a full turn, one picture row per 1/160 radian of elevation,
row 100 at the horizon. Above and below the picture the cylinder continues in its top
and bottom rows and is closed by caps.
Convex polygons gathered into one CauldronGPU.Mesh, one part per material key.
Pictures of a Cauldron2D.Sectors.Pictures set uploaded as RGBA textures through a
768-byte palette. Masked pixels (mask byte 0) are see-through.
The walls of a sector map as CauldronGPU.Sectors.Surfaces surfaces, one quad per
section of each side, keyed {:picture, id} and facing into the side's sector.
What building the renderer needs on this machine, and the build configuration
mix cauldron_gpu.setup writes.
Programs run by CauldronGPU.Setup's platforms.
Downloads for CauldronGPU.Setup: an archive fetched over HTTPS, with the server's
certificate checked against the operating system's certificate store, and unpacked into
a folder.
Building the renderer on Linux (CauldronGPU.Setup.Platform): a C++ compiler, make and
pkg-config, SDL3, Vulkan's headers, and a Vulkan driver to run it.
Building the renderer on macOS (CauldronGPU.Setup.Platform): Apple's command-line tools
for Swift and Metal, pkg-config and SDL3 from Homebrew, and, for the Vulkan backend
that runs through MoltenVK, Vulkan's loader and headers.
What a platform module of CauldronGPU.Setup provides.
Building the renderer on Windows (CauldronGPU.Setup.Platform): MSVC's C++ tools, SDL3's
development files, Vulkan's headers, and a Vulkan driver to run it.
A rectangle of a texture placed in a CauldronGPU.SpriteLayer.
Sprites drawn in order into a target, one layer of a {:layers, [layer]} change.
The binary change stream the renderer reads: a sequence of operations, each a one-byte
code and its fields, little-endian. encode/1 turns changes into it.
A Half-Life studio model (Cauldron3D.Formats.Studio) uploaded for drawing: one
skinned mesh in the model's rest pose, every vertex weighted wholly to its own bone,
one mesh part per skin reference, and its textures.
Anything a scene can be sent to: a CauldronGPU renderer in the VM, a
CauldronGPU.Host in its own process, or a browser scene (Cauldron3D.Net.Scene).
The converters (CauldronGPU.Bsp, CauldronGPU.AliasModel, CauldronGPU.StudioModel,
CauldronGPU.Sectors) upload through it, so they work with every one.
A picture to upload. pixels is width * height pixels, rows from the top: four bytes
RGBA for :srgb (colour pictures) and :linear (data such as roughness), eight bytes
(four little-endian half floats) for :rgba16f.
Where a scene entry stands: position, rotation (CauldronGPU.Quat) and scale, in the
renderer's frame (right-handed, +Y up, units are metres by convention).
Mix Tasks
Finds what building cauldron_gpu's renderer needs on this machine, installs what is
missing when you agree, builds the renderer, and checks that it opens.