--- id: bgf-format title: "BGF Model Format (DIV-BIZ2 geometry) + the render gotchas" status: established source_sections: "docs/BGF_FORMAT.md (full spec); CLAUDE.md §5, §10 render-fidelity notes" related_topics: [asset-formats, rendering, decomp-reference] key_terms: [BGF, DIV-BIZ2, PMESH, CONN, PCONN, LOD, material-ramp, SV_SPECIAL] open_questions: - "Replacement-LOD selection for NON-additive multi-LOD models (hot-spot/reference semantics)" --- # BGF Model Format `.BGF` = **`DIV-BIZ2`** little-endian nested Tag-Length-Value geometry. Full byte-level parsing spec (verified against all 1275 content `.BGF` files) lives in **`docs/BGF_FORMAT.md`** — this topic captures the structure + the hard-won gotchas that cost real debugging. Loader of record: `engine/MUNGA_L4/bgfload.cpp` (game-callable via `LoadBgfFile`); standalone reference reader `DivLoader/VGCDivLoader.cpp`. Tag names: `dsys/PFBIZTAG.H`. ## Structure `OBJECT → LOD → PATCH (geogroup) → PMESH`. Interleaved float32 verts; **QUAD faces (must triangulate `[a b c][a c d]`)**; materials referenced by `library:material` name (resolved against the map's `.BMF` libs). Damage/articulation are **name-driven via `SV_SPECIAL` (0x2037) `dz_*` tokens**, not stored geometry. [T1] ## Indices — the CONN/PCONN story (two corrections) A PMESH carries faces in `CONNECTION_LIST` (0x0047) and/or `PCONN_LIST`: - `CONNECTION_LIST` is a **FLAT TRIANGLE LIST** (3 indices/face) — NOT "one polygon, fan-triangulate" (the original doc was wrong; fan-triangulating turned buttec's 115 tris into 341 fan-garbage). Corpus-verified: ALL 3488 CONN chunks have n%3==0. [T2] - **CONN and PCONN COEXIST** — a pmesh can carry quads/hexes in PCONN PLUS loose triangles in CONN. **370 of 841 GEO models** had mixed pmeshes silently dropping their CONN triangles until both were processed always (the "turret base missing panels" bug). `ppf=6` hexagons exist. [T2] ## LODs — the √3 decode Each LOD chunk carries a `0x2046` header = **[near..far) viewing band**. The board selected the LOD whose band contains the camera distance. - **√3 range decode:** every stored band value is the authored euclidean distance ÷ √3 (92% of the corpus is exactly nice-number/√3; hand-conversion typos prove it). Multiply parsed bands by `√3` (`kLodRangeScale=1.7320508`). [T2] - **Metric = the instance-transformed OBJECT ORIGIN distance**, ONE shared `d` for all LODs of an object (a bounding-sphere-SURFACE metric desyncs sibling bands — wrong). [T2] - **ADDITIVE_LODS** (object-level `SV_SPECIAL` token, 135 pod BGFs — all arena structures): at eye distance d, EVERY LOD with `d < OutDist` draws (near detail ADDS onto coarser massing). Non-additive keep first-LOD-only (the 2007 engine's own behavior). [T2] - **PUNCH** (patch-level `SV_SPECIAL`, `dpl_Punchize` = FUN_00490308 → VPX board cmd `0x20`, tokens `{0x80000003,0x80000017,0x80000004}` — a CONSTANT geogroup-modifier opcode, no color key; the sibling `dpl_Damagize` FUN_004902b0 uses the same cmd with a different triple). Two cases: [T1] - **Textured** punch (arena walls/catwalks): black texels = HOLES (alpha-test in the opaque pass). Coplanar shells inside one LOD z-fight → depth-bias by submission ordinal. [T2] - **Texture-less** punch (the `*_cop` cockpit canopies: blakskn + `softer` ramp, NO texture tag in the BMF — byte-verified, 238-byte BLXSKIN.BMF): the frame/window split is the GEOMETRY — every `_cop` is an open strut lattice (38-59% boundary edges, all 12 mechs); rendered single-sided with per-face INWARD winding orientation (the l/r torso patches are MIRRORED, so no single global winding works) the struts are the dark frame and the openings show the world. The old "canopy windows are punch texels" claim was WRONG — there is no texel to key. See [[cockpit-view]]. [T2 render-verified in-game on Madcat vs gameplay footage] ## Shading model (from libDPL DPLTYPES.H) Shading is selected PER-GEOMETRY by vertex type: - **No-normal geometry** (XYZ_UV / XYZ_RGBA_UV: mesas/ground/sky/buildings/mech, WHITE baked verts) is UNLIT, colorized by the material's 2-endpoint **RAMP** (see [[material-ramp]]). - **Normal-bearing geometry** (XYZ_N_UV: ~150 vehicle/missile files) is LIT by the map light. - **Applying the ramp to lit geometry = the "dusty white blobs" bug** — gate on `hasNormals`. [T2] ## Skeleton assembly A mech is not one BGF — it's a `.SKL` skeleton (a DCS tree of joints) whose each joint's `Object=part.bgf` is loaded + posed, then animated by `.ANI` clips. See [[asset-formats]] / [[locomotion]] for skeleton + animation. [T1] ## Key Relationships - Detailed spec: `docs/BGF_FORMAT.md`. - Consumed by: [[rendering]] (the D3D9 draw path), [[locomotion]] (skeleton parts). - Related: [[asset-formats]] (BMF/BSL/SKL/ANI), [[decomp-reference]].