Warcraft III models

Aqua IV reads the models of Warcraft III (MDX version 800) and plays them in its own renderer. The goal is full coverage: every part of the format read, drawn or played the way the game does, and checked. This page is the honest scoreboard. It is regenerated from the project's coverage list, and it changes as work lands.

Reforged models (versions 900 and 1000) are out of scope.

Where we stand

There are 192 rows, one for each chunk, flag, track and rule. Each is judged three ways:

  • Read: the file is parsed into the model. 129 of 192 (67 per cent) are done; 60 more are not yet checked.
  • Drawn or played: the game shows or plays it. 78 of 192 (41 per cent) are done or need nothing drawn, and 12 more are partly done.
  • Checked: a test, a screenshot or a comparison with Warcraft III proves it. 51 of 192 (27 per cent).

The drawn and checked figures are the ones that matter. Reading a file completely is the easy half; the work is in playing what it holds. Rows that are research notes (rules to confirm against the game) count too, which is why the totals are modest while most day-to-day models already look right.

How to read the tables: Done means finished, Partly means some of it works, No means not yet, Not checked means nobody has confirmed the state yet, and Nothing to draw means the data has no visible form.

Research notes from OpenWCIII

39 rows, 6 drawn or played in full.

Feature Read Drawn Checked
Missing rule: Depth write only for filters None and Transparent; blending from filter ordinal 2; depth test off by flag Not checked No No
Missing rule: Alpha discard under 0.02 for Modulate and Modulate2x; discard needs vertex alpha 1 Not checked No No
Missing rule: Visibility tracks (KLAV, KATV, KPEV, KP2V, KRVS) are never interpolated Not checked No No
Missing rule: Colour tracks stored BGR (KLAC, KLBC, KGAC): channel order on load Not checked No No
Missing rule: Keys wrap from the last to the first of a sequence; global-sequence start key injection; constant-sequence shortcut Not checked No No
Missing rule: Sequence time in milliseconds; non-looping stops at end - 1; loop modes model (flags 0) and to-next; hide when done Done Partly Done
Missing rule: Fog rule: linear ramp, additive blends fade toward black, per-filter fog skips, unfogged flag Not checked No No
Missing rule: Layer colour: vertex colour times geoset colour, alpha = layer alpha Not checked No No
Missing rule: Texture animation order: translate, rotate about (0.5, 0.5), scale about (0.5, 0.5) Not checked No No
Missing rule: Opaque versus translucent geoset passes; geosets with alpha 0 not pickable Not checked No No
Missing rule: Attachment visibility threshold 0.1, restart at sequence 0 on reappearing, child hidden with the parent node, .mdl to .mdx path rule Not checked No No
Missing rule: Event object name parsing (3-character type, id from character 4), step trigger on key index change, reset on sequence change; SPL life Lifespan + Decay, UBR Birth + Pause + Decay; SPN plays sequence 0 Not checked No No
Missing rule: SND: volume / 127, pitch +- variance, random file pick, panner distances Not checked No No
Missing rule: Light formulas: omni distance /64 + 1 and inverse square, ambient window attenuation; unknown light type = directional Not checked No No
Missing rule: PRE2 gravity times node world scale Z; velocity scaled by node scale; half width and half length; velocity = unit Z through rotation about Z (90 degrees), Y, then X Not checked No No
Missing rule: PRE2 squirt starts with key -1 (first frame always a change); emission count ceil of the accumulator; sort key filter + 2 Not checked No No
Missing rule: PREM as model-instance particles: random Z rotation, sequence 0, no longitude Not checked No No
Missing rule: Ribbon emission cap of 1 per update; chain-factor UV rule; ribbons never lit; alpha cut 0.75 in the ribbon shader Not checked No No
Missing rule: Replaceable id table (11, 21, 31 to 37 paths) and the two-digit team id suffix; empty texture path = white texture Done Done Done
Missing rule: Node: parent id equal to own id = root; object id order; cameras without object id; billboard first matching flag only; camera-anchored is not billboarding Not checked No No
Missing rule: Sequence tag parsing stops at the first unknown token; rarity roll random(0..100) < 10 - rarity; tag rank constants (200000, 10) Done Partly Done
Rule differs: Additive versus AddAlpha: both src alpha x one in OpenWCIII; ours one Blend::Add; confirm what it multiplies by Not checked No No
Rule differs: Ribbon gravity: position offset gravity * dt^2 (OpenWCIII) versus sink speed gravity * scale * dt (ours); compare on a ribbon model Not checked No No
Rule differs: PRE2 accumulator emptied above MAX_PARTICLES (ours) versus no cap; squirt with no key emits nothing (ours) Not checked No No
Rule differs: Key before the first key and wrap case in anim.rs sample: check a track whose last key is before the sequence end Not checked No No
Rule differs: Non-looping end: clamp at end - 1 versus our "last pose" (row 5): check the off-by-one Done Done Done
Rule differs: Sequence blending with blendTime: ratio blendTimeRemaining / blendTime, only when the previous sequence is not -1 (row 3) Done Done Done
Rule differs: Billboard lock: first matching flag only, in the order 0x8, 0x10, 0x20, 0x40; ours (pose_facing) may apply several Not checked No No
Verify in WC3: Death and Decay hold the last frame (OpenWCIII has no such rule; the unit layer decides) Done Done Partly
Verify in WC3: Walk speed scaling by unit speed (OpenWCIII only returns the move speed) Done Done Partly
Verify in WC3: Alternate and Morph sequences beyond the tag lists; Attack and Decay selection Done Partly Partly
Verify in WC3: CLID cylinder and plane shapes (OpenWCIII does not implement them) Not checked No No
Verify in WC3: Camera behaviour for portraits (OpenWCIII stores the fields and tracks only) Not checked No No
Verify in WC3: PRE2 longitude (no field in the OpenWCIII loader) and PREM beyond sequence 0 Not checked No No
Verify in WC3: Sphere environment map (flag 0x2): view-space normals, not seen in OpenWCIII shaders Not checked No No
Verify in WC3: Sort primitives far Z, constant colour, full resolution; priority plane as a sort key Not checked No No
Verify in WC3: Per-sequence extents for culling; GEOA use-colour and drop-shadow flags Not checked No No
Verify in WC3: Ubersplat terrain placement for UBR event objects Not checked No No
Do not copy: OpenWCIII bugs: PRE2 width and length fall back to each other (swapped); ribbon kill clears first and last wrongly; splat normals as signed bytes; EventObjectSpn throws with no sequences; Attachment.update has no null check; an empty reforged texture path throws Nothing to draw Nothing to draw No

Files and the whole corpus

10 rows, 9 drawn or played in full.

Feature Read Drawn Checked
VERS (800) Done Nothing to draw Done
MODL name, bounds Done Done Done
MODL blend time (blending between sequences) Done Done Done
.mdl text read and write Done Nothing to draw Done
All 3,209 archive models parse Done Nothing to draw Done
All 3,209 play every sequence without panic or NaN Nothing to draw Done Done
MODL animation-file name (260 bytes, skipped) Not checked Nothing to draw No
MODL bounds radius separate from min and max Not checked No No
Unknown top-level chunks kept by name and ignored; fix stale comment at crates/aqua4-mdx/src/lib.rs:7-8 Not checked Nothing to draw No
v900 chunks (TANG, SKIN) refused cleanly (out of scope) Not checked Nothing to draw No

Sequences and animation

23 rows, 11 drawn or played in full.

Feature Read Drawn Checked
SEQS start, end Done Done Done
SEQS non-looping Done Done Done
SEQS rarity (which variant plays) Done Done Done
SEQS move speed (walk animation speed from unit speed) Done Done Done
SEQS bounds Done Done Done
GLBS global sequences Done Done Done
Interpolation none / linear Done Done Done
Interpolation hermite / bezier Done Done Done
Spherical rotation blending Done Done Done
SEQS animation tag lookup by name and subname (Stand, Stand Ready, Walk Fast, Attack, Death, Decay, Dissipate, Morph, Birth, Spell) Done Partly Done
SEQS end rules: Death and Decay hold the last frame Done Done Done
SEQS walk speed scaling by unit speed Done Done Done
SEQS alternate Stand chosen by rarity; Morph and Alternate sequences Done Partly Done
global_sequence honoured for layer alpha tracks Not checked No No
global_sequence honoured for texture animation tracks Not checked No No
global_sequence honoured for geoset animation tracks Not checked No No
global_sequence honoured for light tracks Not checked No No
global_sequence honoured for PRE2 and ribbon tracks Not checked No No
global_sequence honoured for camera tracks Not checked No No
Quaternion hermite and bezier with slerp fallback Not checked No No
Integer tracks (KMTF, KRTX) held with no interpolation Not checked No No
Keys outside the sequence range (first key or default) Not checked No No
Absent tracks: identity rotation, scale 1 Not checked No No

Textures, materials and layers

35 rows, 18 drawn or played in full.

Feature Read Drawn Checked
TEXS path, wrap width and height Done Done Done
TEXS replaceable 1 (team colour) Done Done Done
TEXS replaceable 2 (team glow) Done Done Done
TEXS replaceable 11, 21, 31 to 37 (cliff, trees) Done Done Done
MTLS layer filter None Done Done Done
MTLS layer filter Transparent (alpha test) Done Done No
MTLS layer filter Blend Done Done No
MTLS layer filter Additive Done Done No
MTLS layer filter AddAlpha Done Partly No
MTLS layer filter Modulate / Modulate2x Done Done No
Layer flag unshaded Done Done No
Layer flag two sided Done Done No
Layer flag sphere environment map Done No No
Layer flag unfogged Done No No
Layer flag no depth test Done Done No
Layer flag no depth set Done Done No
Layer alpha (fixed) Done Done Partly
Layer alpha track (KMTA) Done Done Partly
Layer texture id track (KMTF) Done No No
Layer texture animation (TXAN translation, rotation, scale: waterfalls, flames) Done No No
Layer coord id (second UV set) Done No No
Material priority plane (draw order) Done No No
Material flags (constant colour, sort primitives far Z, full resolution) Done No No
MTLS constant colour flag (0x1) Not checked No No
MTLS sort primitives far Z (0x8) Not checked No No
MTLS full resolution (0x10) Not checked No No
Layer shading flag bits above 0x80 Not checked No No
Unknown filter mode falls back to opaque Not checked No No
AddAlpha rule (src = alpha * colour, additive); alpha key threshold 0.75 not scaled by layer alpha Not checked No No
TXAN rotation (angle about Z versus quaternion) checked against WC3 Not checked No No
Sphere environment map uses view-space normals Not checked No No
Team colour: replaceable 1 (colour) and 2 (glow) pictures as the game has them Done Done Done
Per-player colour table (24 colours, per instance in the shader) Done Done Done
Replaceable ids 8 to 10 and unknown ids Done Done Done
Texture path rules: .tga and .blp, case, backslashes, missing file fallback Not checked No No

Geometry and geoset animation

16 rows, 12 drawn or played in full.

Feature Read Drawn Checked
GEOS positions, normals, triangles Done Done Done
GEOS skinning (vertex groups, bone matrices) Done Done Done
GEOS UV set 0 Done Done Done
GEOS selection group and flags Done Nothing to draw No
GEOA static alpha (hides a geoset) Done Done Partly
GEOA alpha track (KGAO: fades, appearing parts) Done Done Partly
GEOA colour and colour track (KGAC) Done Done Partly
GEOS per-geoset bounds Not checked No No
GEOS per-sequence extents (28 bytes each, skipped; per-sequence culling) Done No No
GEOS primitive types other than triangles (refused: UnsupportedPrimitive) and PCNT Done Done Done
GEOS more than 4 bones per vertex (cap and weights) Not checked No No
GEOS index validation Done Done Done
GEOS UV sets beyond the first (UVBS) Not checked No No
GEOA drop-shadow flag Done Nothing to draw Done
GEOA use-colour flag Done Done Done
GEOA NO_ID geoset = all geosets Done Done Partly

Skeleton and nodes

10 rows, 6 drawn or played in full.

Feature Read Drawn Checked
BONE: translation, rotation, scale tracks Done Done Done
BONE geoset id and geoset anim id Done Partly No
HELP Done Done Done
Node flags: don't inherit translation / rotation / scaling Done Done Done
Node flags: billboarded, lock X / Y / Z Done No No
Node flag camera anchored Done No No
PIVT pivot points Done Done Done
BONE with geoset anim id takes alpha from that GEOA Not checked No No
Node parent_id NO_ID = root; parent before child; cycle and forward-reference test Done Done Done
Node name table; node flag bits above 0x80 Done Done Done

Particles and ribbons

32 rows, 13 drawn or played in full.

Feature Read Drawn Checked
PREM (ParticleEmitter v1, model particles) Done No No
PRE2 speed, variation, latitude, gravity, life span, rate, width, length (+ tracks) Done Done Partly
PRE2 filter modes (blend, additive, modulate, modulate2x, alpha key) Done Done Partly
PRE2 rows, columns, head and tail frame intervals Done Done Done
PRE2 head / tail / both, tail length Done Done Done
PRE2 line emitter Done Done Done
PRE2 XYQuad (flat in the ground plane) Done Done Done
PRE2 squirt Done Done Partly
PRE2 model space (particles move with the emitter) Done Done Done
PRE2 unshaded, unfogged Done Partly No
PRE2 sort primitives far Z Done Done Done
PRE2 priority plane Done Done Partly
PRE2 team colour (replaceable id 1, 2) Done Done No
PRE2 visibility track Done Done No
RIBB ribbons (heights, alpha, colour, life, rate, rows, columns, slot, gravity) Done Done Partly
PRE2 KP2V visibility track Done No No
PRE2 KP2E emission rate track Done No No
PRE2 KP2W width track Done No No
PRE2 KP2N length track Done No No
PRE2 KP2S speed track Done No No
PRE2 KP2L latitude track Done No No
PRE2 KP2G gravity track Done No No
PRE2 KP2R variation track Done No No
PRE2 segment colours, alphas and scaling (head, mid, tail with the time split) Done No No
PRE2 head and tail intervals with repeat and the random frame choice Done No No
PRE2 texture id plus replaceable id when both are set Done No No
PRE2 emission accumulator, emitter life and gravity sign Not checked No No
PREM texture path flags (EMITTER_USES_MDL, EMITTER_USES_TGA) Done No No
PREM emission rate, gravity, longitude, latitude, life span, initial velocity and tracks KPEV, KPEE, KPEG, KPLN, KPLT, KPEL, KPES Done No No
RIBB KRVS visibility, KRHA and KRHB heights, KRAL alpha, KRCO colour, KRTX texture slot Done No No
RIBB material id (filter and layer flags matter), emission rate, gravity, rows and columns Done No No
RIBB trail ends when the emitter is hidden Not checked No No

Attachments, events, lights, cameras and collision

27 rows, 3 drawn or played in full.

Feature Read Drawn Checked
ATCH attachment points (weapon, overhead, origin ...) Done No No
ATCH visibility track Done No No
LITE lights (all kinds, colours, intensity, attenuation, tracks) Done No No
CAMS position, target, field of view (portraits) Done Partly No
CAMS translation, target and roll tracks Done Partly Partly
EVTS SND (sounds), FPT (footprints), SPN (spawned models), UBR (unit blood), SPL (splats) with their lookup tables Done Partly Partly
CLID collision shapes Done Nothing to draw No
Visibility tracks (emitters, lights, attachments) Done Partly No
ATCH attachment path (child model) and attachment_id Done No No
ATCH name to point lookup (Origin Ref, Overhead Ref, Chest Ref, Hand Left, Weapon ...) and child models loaded Not checked No No
EVTS SND (AnimSounds.slk) Done No No
EVTS FPT (footprints) Done No No
EVTS SPN (SpawnData) Done No No
EVTS UBR (unit blood) Done No No
EVTS SPL (SplatData.slk) Done No No
EVTS KEVT global_sequence; key times are sequence-relative Done No No
LITE kind (omni, directional, ambient), attenuation start and end Done No No
LITE colour, intensity, ambient colour and intensity Done No No
LITE seven tracks (KLAV, KLAC, KLAI, KLBC, KLBI, KLAS, KLAE) Done No No
CLID plane (kind 1) is approximated as a box (parser.rs:503) Partly Nothing to draw No
CLID sphere centre and radius, box min and max Done Nothing to draw No
CAMS name, near and far clip Done No No
CAMS tracks KCTR, KTTR, KCRL with roll; cameras beyond the first Done No No
Billboard flag: billboarded Done No No
Billboard flag: lock X Done No No
Billboard flag: lock Y Done No No
Billboard flag: lock Z Done No No

Where the detail lives

Each row has an owner, a test or a screenshot behind it, and notes in the repository's docs/MDX-COVERAGE.md. The Warcraft III behaviour is studied from the open OpenWCIII project for its rules and numbers; Aqua IV writes its own code. See also the look for how models are lit, and rendering.