Skip to content

Decompile merged meshes without losing them; repair and compile refuse lost triangles - #109

Merged
plenarius merged 1 commit into
mainfrom
fix/merged-render-lists
Oct 21, 2026
Merged

plenarius merged 1 commit into
mainfrom
fix/merged-render-lists

Conversation

@plenarius

Copy link
Copy Markdown
Owner

Fixes the cause of layonara/nwn-module#476: walls lost their lower parts after cleanmodels repair (haks PR #23).

Cause. Some binaries draw meshes of one texture as one. The receiving mesh's render index list (MDL-BIN-049) holds its own faces' triangles plus copies of the others' (the donors). Each donor keeps its faces, but has render 0 and an empty index list. The game draws index lists, so the model looks whole. The decompiler read only faces, so the copies were lost and the donors were written invisible.

Fix.

  • The decompiler reads each mesh's index list (pkg/mdl/binary_merged.go). It writes every donor whose triangles are all among a receiver's copies with render 1, which draws the same triangles as a mesh of its own.
  • Triangles are matched by texture coordinates and side lengths (within 1 mm), so placement doesn't matter; untextured meshes match by shape alone.
  • Each receiver gets a note, and a donor that an animation moves gets one saying it now moves. That happens in 6 base-game dag_* placeables.
  • Triangles no donor accounts for get a warning, and repair, compile and check --fix refuse to write the model unless --force is given. decompile keeps its own --force. A test now checks that every subcommand's flags register.
  • Ported to python/.

Scale. 1,015 base-game binaries (tno01, tts02, ttf02 and tcn01 tiles first) and 342 in Layonara's haks hold merged meshes. All of them are put back fully, with no triangles lost.

Round trip (decompile, then compile) compared with the original, by the triangles drawn in world space:

v4.12.0 this PR
1,015 game binaries 47% of drawn triangles lost every triangle drawn, except degenerate ones
342 haks binaries 34% lost the same

Testing.

  • In game (Layonara shop PH_000195, the three tiles from #476): repaired with this build the way PR fix(compiler): don't split skin vertices at material boundaries #23 did it, the walls are whole.
  • Parity (parity_test.py on the game's 25,597 binaries) passes. Go and Python give the same warnings and notes on all of them, and the same ASCII, warnings and notes on the 342 haks models.
  • The conformance suite's results (46 compile, 46 decompile, 14 stock) are unchanged.
  • New tests cover matching, untextured donors, lost triangles, animated donors, the refusal, and flag registration.

Spec: plenarius/nwn-mdl-spec MDL-BIN-053 (separate PR).

…e lost triangles

Some binaries draw meshes of one texture as one: the receiving mesh's render
index list holds its own faces' triangles and copies of the others' (the
donors, render 0 with an empty list). The game draws index lists, so the
model looks whole; the decompiler read only faces, so the copies were lost
and the donors written invisible. Layonara's tin01 tiles lost their lower
walls after a repair that way (nwn-module#476).

The decompiler now reads each mesh's index list and writes every donor whose
triangles are all among a receiver's copies with render 1, which draws the
same triangles as a mesh of its own. Triangles are matched by texture
coordinates and side lengths (within 1 mm), so placement doesn't matter;
untextured meshes match by shape. Each receiver gets a note; a donor an
animation moves gets one saying it now moves; triangles no donor accounts
for get a warning, and repair, compile and check --fix refuse to write the
model unless --force is given (decompile keeps its own --force).

1,015 base-game binaries and 342 in Layonara's haks hold merged meshes; all
of them are put back fully. Round-tripped (decompile, compile), they draw
every triangle the originals draw except degenerate ones; with v4.12.0 the
same round trip lost 47% (game) and 34% (haks) of the drawn triangles.
Ported to python/; parity and Go-vs-Python warnings and notes pass on the
game's 25,597 binaries and the 342 haks models.
@plenarius
plenarius merged commit 7baffca into main Oct 21, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant