The first-person cockpit now shows by default and matches gameplay footage (verified on the Madcat). Two decomp-verified reconstructions: EYEPOINT (FUN_004579a8 + caller part_014.c:5525, FUN_004c22c4): - eye offset = siteeyepoint GetBaseOffset (not GetSegmentToEntity, not the upright hack), parented on the PARENT segment DCS (btl4vid.cpp) - live view = affine INVERSE of the eye world matrix (L4VIDRND Execute) -- replaces the hand-rolled LookAtRH whose +Z-forward/+Y-up row guess aimed some mechs into the canopy; combine order fixed to baseOffset * R - chase camera basis + aim boresight re-expressed for the inverse convention (row2 = back); boresight now derives from the view matrix (the stale rows aimed the pick ray at the sky = no target, no discharge) CANOPY (*_COP.BGF, dpl_Punchize geogroups): - every shell is an open strut lattice (38-59% boundary edges, all 12 mechs); rendered single-sided with per-face INWARD winding (l/r torso patches are mirrored, so no global winding works) the struts are the dark frame and the openings show the world - frame colour = the 'softer' ramp near its dark end (texture-less unlit ramp; BLXSKIN.BMF has no texture -- the old "punch texels" theory was wrong) - scoped by filename (meshIsCop); wrong drop-punch + view-cut paths removed - BT_FORCE_MODEL=<name> forces the player mech for per-mech bring-up KB: new context/cockpit-view.md topic; punch split corrected in bgf-format; gotchas 14 (LookAt axis guess) + 15 (per-patch edge namespaces); env gates + eye/punch addresses in decomp-reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
75 lines
4.8 KiB
Markdown
75 lines
4.8 KiB
Markdown
---
|
|
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]].
|