Prepared Model Draw Protocol
This is the renderer-facing frame protocol for all models. The exact layouts
live in model_draw.hpp; this document defines their meaning, ownership, and
failure behavior.
Batch Transform
ModelInstanceHandle span
-> PreparedModelDrawList
-> PreparedModelDrawRangeList
-> PreparedModelSurfaceDrawList
-> sorted surface span
-> PreparedRenderModelSkinTable
-> source-indexed runs and validated packets
-> ModelRenderContext submission
PreparedModelDrawList owns a flat draw array and an offset table with one
entry per input handle plus a terminal entry. Hidden, stale, missing, or
non-emitting inputs repeat the prior offset. This preserves input ordering
without dummy draws.
PreparedModelDrawRangeList emits one range for each non-empty handle. Every
draw in a range must share the instance handle and source model index. Invalid
offsets and mixed ranges are dropped and counted.
PreparedModelSurfaceDrawList flattens valid ranges. Each surface carries:
- instance, range, draw, source model, primitive, material, skin, and override indices
- material mode and payload class
- skinned and shadow flags
- world and normal transforms
- world-space bounds
- a frame-local skin-table index when assigned
Records contain indices and value data, never pointers into source models.
Sorting And Passes
sort_prepared_model_surface_draws_by_pass sorts the flat array by material
pass, skinned state, source model, material, override, skin, range, primitive,
and handle index.
Pass helpers return borrowed spans into that one sorted array:
- opaque and cutout:
[0, 2) - water:
[2, 3) - transparent:
[3, 4) - all: the full span
The caller must retain the surface list while any pass span is used.
Skin Tables And Submission
collect_prepared_render_model_skin_tables scans the surface batch and writes
one contiguous matrix array plus indexed ranges. Surfaces that are unskinned,
stale, invalid, over the joint bound, or intentionally using bind pose retain
kInvalidPreparedModelDrawIndex; each case is counted.
collect_prepared_render_model_surface_runs groups adjacent surfaces by
instance_source_index. Packet collection validates the referenced
RenderModel primitive, material, skin, override, and payload before common
PBR or shadow submission.
Error Policy
Every invalid boundary is drop-and-count. Counted cases include:
- stale or hidden instances and missing source models
- invalid offsets, mixed ranges, and invalid source indices
- primitive, material, skin, override, or matrix-range mismatches
- material payload or shadow-state mismatches
- unsupported material modes
No pass infers behavior from model, texture, or node names. Source-format policy must already have been lowered into common fields before this protocol.
Ownership, Cost, And Constraints
PreviewScene owns source models, instances, and material overrides.
PreviewPreparedModelDraws owns draw and range arrays.
PreparedModelSurfaceDrawList owns surfaces and the skin table. Packet and
run spans borrow these arrays. ModelRenderContext owns GPU submission state,
not scene or frame records.
Collection, range validation, skin assignment, and run construction are linear
in their input counts. Sorting is O(surface_count log surface_count). Memory
is linear in visible draws, surfaces, and referenced skin matrices. These are
algorithmic costs; runtime performance has not been measured here.