Cracks the DIV-BIZ2 binary format (BGF/BMF) using Division's own reader source (DPL3/BIZREAD.C) as reference: block stream, 14 vertex layouts, pmesh/strip connectivity, LOD nesting, embedded materials. Adds SVT raw-texture decoding, 1995-dialect VGF support (implicit CONNECTION_LIST, header SCALE), and a whole-drive scene audit. 108 of 241 scenes on the Glaze drive are recoverable; 26 are curated into restoration/vwe-archive.html, a self-contained WebGL gallery: Star Trek, Hull Pressure, BattleTech (incl. the polar-map mech lineup), Red Planet's Mars-canal raceway, and the Canyon demos. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
112 lines
5.6 KiB
Python
112 lines
5.6 KiB
Python
"""Build the gallery HTML: curated scenes from allscenes.json injected into
|
|
gallery_template.html."""
|
|
import json, os
|
|
|
|
CURATED = [
|
|
# (scene key, project, display name, blurb)
|
|
("STDAVE/TREK.SCN", "Star Trek", "Enterprise-D",
|
|
"The Enterprise-D at rest among three parallax layers of drifting stars."),
|
|
("STDAVE/KLNGVID.SCN", "Star Trek", "Klingon flyby",
|
|
"A Klingon cruiser at rest while two more drift past on spline paths."),
|
|
("STDAVE/TREKVID.SCN", "Star Trek", "Enterprise flyby",
|
|
"Camera-pass variant of the Enterprise scene, built for video capture."),
|
|
("HPDAVE/SDEMO.SCN", "Hull Pressure", "Sea demo",
|
|
"The big Hull Pressure demo: seafloor, wrecks, and marine life on spline paths."),
|
|
("HPDAVE/FISHSPLS.SCN", "Hull Pressure", "Fish schools",
|
|
"Schools of fish and sharks swimming spline circuits over the seabed."),
|
|
("HPDAVE/BDDEMO.SCN", "Hull Pressure", "Big demo",
|
|
"Full underwater environment demo for the unreleased submarine game."),
|
|
("HPDAVE/TMPRIGS.SCN", "Hull Pressure", "Temple rigs",
|
|
"Sunken temple environment with rig structures."),
|
|
("HPDAVE/DUANE.SCN", "Hull Pressure", "Duane's scene",
|
|
"An underwater scene named for one of the team."),
|
|
("HPDAVE/SANDTEST.SCN", "Hull Pressure", "Sand test",
|
|
"Seafloor sand and lighting test."),
|
|
("BTDAVE/MAPS/POLAR4.SCN", "BattleTech", "Polar map",
|
|
"The polar arena environment, assembled from 99 models."),
|
|
("BTRAVINE/RAVTEST.SCN", "BattleTech", "Ravine map",
|
|
"The Ravine arena in development — this environment shipped as RAV/RAV1."),
|
|
("BTRAVINE/DESTEST.SCN", "BattleTech", "Desert test",
|
|
"Desert environment test with full map furniture."),
|
|
("BTDAVE/MAPS/DTEST.SCN", "BattleTech", "Desert map test",
|
|
"A smaller desert map assembly test."),
|
|
("CONVERT/BTECH/STAD/STAD.SCN", "BattleTech", "Stadium",
|
|
"Arena stadium model in the art-conversion workspace."),
|
|
("DPL3RLS/SCENES/MISSILE.SCN", "BattleTech", "Missile test",
|
|
"Weapon-effects staging scene with arena props."),
|
|
("RPDAVE/SCENES/BLADE.SCN", "Red Planet", "Blade arena",
|
|
"The Blade racing arena — late Red Planet development work."),
|
|
("CONVERT/MILESTON/MILESTON.SCN", "Red Planet", "Milestone",
|
|
"The Red Planet milestone demo: Mars mining-canal raceway."),
|
|
("CONVERT/MILESTON/WELLENT.SCN", "Red Planet", "Well entrance",
|
|
"Raceway well-entrance sequence from the milestone build."),
|
|
("CONVERT/RD/CHOICE2.SCN", "Red Planet", "Choice point",
|
|
"A raceway fork (“choice”) section of the Mars canals."),
|
|
("RD/VTER.SCN", "Red Planet", "Terrain",
|
|
"Generated Mars terrain heightfield test."),
|
|
("CANYON/CANYON.SCN", "Canyon demo", "Canyon",
|
|
"River-canyon flythrough environment — Division demo work."),
|
|
("CANYON/CANABOVE.SCN", "Canyon demo", "Canyon from above",
|
|
"The canyon seen from altitude."),
|
|
("CANYON/TEMPLE.SCN", "Canyon demo", "Maya temple",
|
|
"Mayan temple set piece at the canyon rim."),
|
|
("ERIC/VANSMAK.SCN", "Misc", "Van's MAK",
|
|
"A 31-model scene from developer Eric's directory."),
|
|
("HPDAVE/BATEST.SCN", "Hull Pressure", "Bathysphere test",
|
|
"Single-model test of the submersible."),
|
|
("CONVERT/CALIB/DIVCAL.SCN", "Misc", "Division calibration",
|
|
"Display-calibration model used to align the pod projectors."),
|
|
]
|
|
|
|
# camera overrides for scenes whose START sits inside geometry (dev scenes);
|
|
# None = use the viewer's auto-framing instead
|
|
START_OVERRIDE = {
|
|
"BTRAVINE/RAVTEST.SCN": [280, 30, 160, -8, 25, 0],
|
|
"CANYON/CANYON.SCN": None,
|
|
"CANYON/CANABOVE.SCN": None,
|
|
"CANYON/TEMPLE.SCN": None,
|
|
"BTDAVE/MAPS/DTEST.SCN": None,
|
|
"CONVERT/CALIB/DIVCAL.SCN": None,
|
|
}
|
|
|
|
here = os.path.dirname(os.path.abspath(__file__))
|
|
data = json.load(open(os.path.join(here, "allscenes.json")))
|
|
|
|
out = {"models": {}, "images": {}, "scenes": {}, "catalog": []}
|
|
for key, project, name, blurb in CURATED:
|
|
sc = data["scenes"].get(key)
|
|
if not sc:
|
|
print("MISSING SCENE:", key)
|
|
continue
|
|
if key in START_OVERRIDE:
|
|
sc = dict(sc); sc["start"] = START_OVERRIDE[key]
|
|
if sc["start"] is None: del sc["start"]
|
|
out["scenes"][key] = sc
|
|
out["catalog"].append({"key": key, "project": project, "name": name, "blurb": blurb})
|
|
for mid in sc["modelmap"].values():
|
|
out["models"][mid] = data["models"][mid]
|
|
for mat in sc["materials"].values():
|
|
if mat and mat.get("img"):
|
|
out["images"][mat["img"]] = data["images"][mat["img"]]
|
|
|
|
# per-model bounding radius for auto-framing
|
|
for mid, groups in out["models"].items():
|
|
lo = [1e9] * 3; hi = [-1e9] * 3
|
|
for g in groups:
|
|
for v in g.get("v", g.get("points", [])):
|
|
for i in range(3):
|
|
lo[i] = min(lo[i], v[i]); hi[i] = max(hi[i], v[i])
|
|
if lo[0] > hi[0]: lo = hi = [0, 0, 0]
|
|
for g in groups: pass
|
|
c = [(lo[i] + hi[i]) / 2 for i in range(3)]
|
|
r = max(hi[i] - lo[i] for i in range(3)) / 2 or 1
|
|
out.setdefault("bounds", {})[mid] = {"c": [round(x, 2) for x in c], "r": round(r, 2)}
|
|
|
|
blob = json.dumps(out, separators=(",", ":"))
|
|
print("gallery data: %.1f MB, %d scenes, %d models, %d images"
|
|
% (len(blob) / 1e6, len(out["scenes"]), len(out["models"]), len(out["images"])))
|
|
tpl = open(os.path.join(here, "gallery_template.html"), encoding="utf-8").read()
|
|
open(os.path.join(here, "vwe-archive.html"), "w", encoding="utf-8").write(
|
|
tpl.replace("%%DATA%%", blob))
|
|
print("wrote vwe-archive.html", os.path.getsize(os.path.join(here, "vwe-archive.html")) / 1e6, "MB")
|