translated the remaining german notes, python comments, help and messages to english (in-game strings, parsed report lines and cli values stay german)
This commit is contained in:
1 parent
86fe26d786
commit
526f6072f6
36 files changed
+1553
-1544
No files matched your search
+79
-77
@@ -1,26 +1,28 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Debug-Visualisierung fuer Level-WADs von "Ein Koenigreich fuer ein Lama".
|
||||
"""Debug visualisation for level WADs of "Ein Koenigreich fuer ein Lama".
|
||||
|
||||
Macht Kollisionsgeometrie (auch unsichtbare Waende/Boeden) und unsichtbare Logik-Objekte
|
||||
(Kameras, Trigger, Ausgaenge, Checkpoints, Kraftzonen ...) im Spiel sichtbar.
|
||||
Makes collision geometry (including invisible walls/floors) and invisible logic objects
|
||||
(cameras, triggers, exits, checkpoints, force zones ...) visible in the game.
|
||||
|
||||
debugviz.py IN.wad OUT.wad [Optionen] ein Level
|
||||
debugviz.py --all OUTDIR [--src CD-wads-Ordner] alle Level-WADs (t1l*, t6l*)
|
||||
debugviz.py IN.wad OUT.wad [options] one level
|
||||
debugviz.py --all OUTDIR [--src CD-wads-folder] all level WADs (t1l*, t6l*)
|
||||
|
||||
Optionen: --no-coll --no-markers --no-fill (nur Kanten) --opaque (Fuellung deckend)
|
||||
--width 0.03 (Kantenbreite) --offset 0.012 (Abstand entlang der Normale)
|
||||
--report datei.json
|
||||
Options: --no-coll --no-markers --no-fill (edges only) --opaque (opaque fill)
|
||||
--width 0.03 (edge width) --offset 0.012 (offset along the normal)
|
||||
--report file.json
|
||||
|
||||
Prinzip (Details: notes/debugviz.md):
|
||||
* Kollision: an jedes TRAK-Modell werden Render-Dreiecke angehaengt (Rahmen entlang der
|
||||
Kanten jedes Kollisionspolygons, leicht entlang der Normale versetzt; bei unsichtbarer
|
||||
Kollision zusaetzlich halbtransparente Fuellung). Damit stimmen Kachel-Transformation,
|
||||
Zonen/Sichtbarkeit und Kachel-Wechsel automatisch. Kollisionspolygone werden NICHT
|
||||
veraendert/ergaenzt. Vertexfarben-Block in MAP waechst je Kachel und Farbsatz mit.
|
||||
* Objekte: Marker (Wuerfel, Linien, Boxen) als neue Kacheln ohne Kollision, je Rasterzelle
|
||||
eine Kachel (also in der richtigen Zone). Strats bleiben unveraendert.
|
||||
* Farben: angehaengte Flachfarb-Texturen (Flags 0x105 deckend, 0x1105 = Blendmodus 1
|
||||
Alpha-Blending, Alpha im 4. Byte).
|
||||
Principle (details: notes/debugviz.md):
|
||||
* Collision: render triangles are appended to every TRAK model (a frame along the
|
||||
edges of each collision polygon, offset slightly along the normal; invisible
|
||||
collision additionally gets a semi-transparent fill). This way tile transforms,
|
||||
zones/visibility and tile swaps are automatically correct. Collision polygons are NOT
|
||||
changed/added. The vertex colour block in MAP grows accordingly per tile and colour set.
|
||||
* Objects: markers (cubes, lines, boxes) as new tiles without collision, one tile per
|
||||
grid cell (so in the right zone). Strats stay unchanged.
|
||||
* Colours: appended flat colour textures (flags 0x105 opaque, 0x1105 = blend mode 1
|
||||
alpha blending, alpha in the 4th byte).
|
||||
Report/JSON keys and category names (boden, wand, ausgang, koll_polys, ...) are German
|
||||
identifiers and kept as they are.
|
||||
"""
|
||||
import argparse
|
||||
import collections
|
||||
@@ -40,24 +42,24 @@ import strats as S # noqa: E402
|
||||
|
||||
CD_WADS = os.path.expanduser('~/.wine-lama/iso-dk/Setup/Eng/Cd/wads')
|
||||
|
||||
# ------------------------------------------------------------------ Farben
|
||||
# ------------------------------------------------------------------ colours
|
||||
KIND_COL = {
|
||||
'boden': (40, 255, 40), # begehbar (Normale steil nach oben)
|
||||
'schraege': (200, 255, 0), # schraeg
|
||||
'wand': (0, 150, 255), # Wand
|
||||
'decke': (255, 130, 0), # Decke / Ueberhang
|
||||
'boden': (40, 255, 40), # walkable (normal steeply upwards)
|
||||
'schraege': (200, 255, 0), # slope
|
||||
'wand': (0, 150, 255), # wall
|
||||
'decke': (255, 130, 0), # ceiling / overhang
|
||||
}
|
||||
INVIS_FILL = (255, 0, 0) # unsichtbare Kollision (keine Render-Flaeche)
|
||||
INVIS_FILL = (255, 0, 0) # invisible collision (no render surface)
|
||||
FILL_ALPHA = 96
|
||||
|
||||
# Material -> (Name, Farbe). Unbekannte Materialien bekommen Farben aus PALETTE.
|
||||
# material -> (name, colour). Unknown materials get colours from PALETTE.
|
||||
MAT_INFO = {
|
||||
16: ('Ausgang (LevelDoor-Boden)', (190, 60, 255)),
|
||||
17: ('selektiv 0x11 (nur Objekte mit Flag 0x8000000)', (255, 255, 0)),
|
||||
18: ('selektiv 0x12 (nicht fuer Objekte mit Flag 0x8000000)', (255, 200, 120)),
|
||||
30: ('kein Boden / Fall-/Todesebene (0x1e)', (255, 0, 255)),
|
||||
16: ('exit (LevelDoor floor)', (190, 60, 255)),
|
||||
17: ('selective 0x11 (only objects with flag 0x8000000)', (255, 255, 0)),
|
||||
18: ('selective 0x12 (not for objects with flag 0x8000000)', (255, 200, 120)),
|
||||
30: ('no floor / fall/death plane (0x1e)', (255, 0, 255)),
|
||||
}
|
||||
# feste Farben fuer die uebrigen Materialien (Bedeutung im Code nicht geklaert, siehe notes/debugviz.md)
|
||||
# fixed colours for the remaining materials (meaning in the code not yet known, see notes/debugviz.md)
|
||||
MAT_FIXED = {
|
||||
1: (0, 200, 200), 2: (255, 255, 255), 3: (255, 120, 170), 5: (120, 255, 200), 6: (160, 120, 255),
|
||||
7: (255, 170, 80), 8: (0, 130, 60), 9: (150, 200, 255), 10: (150, 150, 0), 11: (150, 90, 40),
|
||||
@@ -79,8 +81,8 @@ MARK_COL = {
|
||||
'objekt': (90, 90, 90),
|
||||
}
|
||||
|
||||
MARK_H = 0.35 # Markerwuerfel ueber dem Strat-Ursprung
|
||||
MARK_SIZE = 0.05 # halbe Kantenlaenge
|
||||
MARK_H = 0.35 # marker cube above the strat origin
|
||||
MARK_SIZE = 0.05 # half edge length
|
||||
START_T = {'Llama', 'KuscoAndPachaTogetherOnATree', 'RollerCoaster', 'LlamaChase'}
|
||||
EXIT_T = {'LevelDoor', 'VillageEndDoor', 'EndGameDoor', 'TeleportDoor'}
|
||||
FORCE_T = {'FallOffNoHurt', 'ObjectDontDropInBox', 'RiverCurrentBox', 'RiverRebound',
|
||||
@@ -117,10 +119,10 @@ def mark_cat(name):
|
||||
return None
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ TEXT: Flachfarben anhaengen
|
||||
# ------------------------------------------------------------------ TEXT: append flat colours
|
||||
|
||||
def text_append_flats(d, entries):
|
||||
"""entries: Liste (r,g,b,alpha|None). Liefert (neues TEXT, erster neuer Index)."""
|
||||
"""entries: list of (r,g,b,alpha|None). Returns (new TEXT, first new index)."""
|
||||
o = 0
|
||||
npal = struct.unpack_from('<I', d, o)[0]; o += 4
|
||||
for _ in range(npal):
|
||||
@@ -139,7 +141,7 @@ def text_append_flats(d, entries):
|
||||
for r, g, b, a in entries:
|
||||
if a is None:
|
||||
add += struct.pack('<HbbBBBB', 0x105, -1, -1, r, g, b, 0)
|
||||
else: # Blendmodus 1 (Bits 12-14) = SRCALPHA/INVSRCALPHA, Alpha = 4. Byte
|
||||
else: # blend mode 1 (bits 12-14) = SRCALPHA/INVSRCALPHA, alpha = 4th byte
|
||||
add += struct.pack('<HbbBBBB', 0x1105, -1, -1, r, g, b, a)
|
||||
e = o + 4 + 8 * nt
|
||||
return d[:o] + struct.pack('<I', nt + len(entries)) + d[o + 4:e] + add + d[e:], nt
|
||||
@@ -156,10 +158,10 @@ class Palette:
|
||||
if k not in self.idx:
|
||||
self.idx[k] = len(self.entries)
|
||||
self.entries.append((*rgb, alpha))
|
||||
return self.idx[k] # relativ; + base beim Schreiben
|
||||
return self.idx[k] # relative; + base when writing
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Geometrie-Helfer
|
||||
# ------------------------------------------------------------------ geometry helpers
|
||||
|
||||
def norm(v):
|
||||
n = np.linalg.norm(v)
|
||||
@@ -167,7 +169,7 @@ def norm(v):
|
||||
|
||||
|
||||
class Mesh:
|
||||
"""Dreiecksliste mit Paletten-Index; Verts (pos, normal)."""
|
||||
"""Triangle list with palette index; verts (pos, normal)."""
|
||||
|
||||
def __init__(self):
|
||||
self.verts = []
|
||||
@@ -178,13 +180,13 @@ class Mesh:
|
||||
return len(self.verts) - 1
|
||||
|
||||
def quad(self, p, n, col):
|
||||
"""4 Punkte (Ring), eine Normale."""
|
||||
"""4 points (ring), one normal."""
|
||||
ids = [self.v(q, n) for q in p]
|
||||
self.tris.append((ids[0], ids[1], ids[2], col))
|
||||
self.tris.append((ids[0], ids[2], ids[3], col))
|
||||
|
||||
def beam(self, a, b, w, col):
|
||||
"""Linie a->b als Kreuz aus zwei doppelseitigen Streifen."""
|
||||
"""Line a->b as a cross of two double-sided strips."""
|
||||
a = np.asarray(a, float); b = np.asarray(b, float)
|
||||
d = b - a
|
||||
L = np.linalg.norm(d)
|
||||
@@ -215,7 +217,7 @@ def seg_split(a, b, maxlen=1.0):
|
||||
return [(a + (b - a) * k / n, a + (b - a) * (k + 1) / n) for k in range(n)]
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Kollision klassifizieren
|
||||
# ------------------------------------------------------------------ classify collision
|
||||
|
||||
def kind_of(ny):
|
||||
if ny >= 0.7:
|
||||
@@ -236,7 +238,7 @@ def decode_model_coll(m):
|
||||
ok = len(pts) >= 3 and all(abs(x) < 12 for p in pts for x in p)
|
||||
P = np.array(pts, float) if ok else None
|
||||
if ok:
|
||||
# Flaeche pruefen
|
||||
# check the surface
|
||||
ar = 0.0
|
||||
for k in range(1, len(P) - 1):
|
||||
ar += np.linalg.norm(np.cross(P[k] - P[0], P[k + 1] - P[0])) / 2
|
||||
@@ -249,7 +251,7 @@ def decode_model_coll(m):
|
||||
|
||||
|
||||
class RenderIndex:
|
||||
"""Render-Dreiecke der Welt (Exportraum), nach Rasterzellen gebuckelt."""
|
||||
"""Render triangles of the world (export space), bucketed by grid cell."""
|
||||
|
||||
def __init__(self, trak, mp):
|
||||
cells = collections.defaultdict(list)
|
||||
@@ -280,7 +282,7 @@ class RenderIndex:
|
||||
self.cells = {k: np.array(v) for k, v in cells.items()}
|
||||
|
||||
def covered(self, p, n, dist=0.5, cosmin=0.4, tol=0.02):
|
||||
"""Trifft der Strahl p + t*n (|t| <= dist) ein Render-Dreieck (Neigung zur Normale < ~66 Grad)?"""
|
||||
"""Does the ray p + t*n (|t| <= dist) hit a render triangle (angle to the normal < ~66 degrees)?"""
|
||||
ids = set()
|
||||
for q in (p, p + n * dist, p - n * dist):
|
||||
k = (int(math.floor(q[0])), int(math.floor(q[2])))
|
||||
@@ -316,9 +318,9 @@ class RenderIndex:
|
||||
|
||||
|
||||
def classify(trak, mp, decoded):
|
||||
"""Setzt pro Polygon 'invis' (True = keine Render-Flaeche deckt es)."""
|
||||
"""Sets 'invis' per polygon (True = no render surface covers it)."""
|
||||
ri = RenderIndex(trak, mp)
|
||||
votes = collections.defaultdict(lambda: [0, 0]) # (model, k) -> [sichtbar, unsichtbar]
|
||||
votes = collections.defaultdict(lambda: [0, 0]) # (model, k) -> [visible, invisible]
|
||||
inst = collections.defaultdict(list)
|
||||
altmap = dict(zip([i for i in range(mp['N']) if mp['A'][i][5]], mp['anim']))
|
||||
for i in range(mp['N']):
|
||||
@@ -326,7 +328,7 @@ def classify(trak, mp, decoded):
|
||||
if i in altmap:
|
||||
inst[altmap[i][4]].append(i)
|
||||
for mi, polys in enumerate(decoded):
|
||||
tiles = inst.get(mi, [])[:6] # wenige Instanzen reichen
|
||||
tiles = inst.get(mi, [])[:6] # a few instances are enough
|
||||
for k, pl in enumerate(polys):
|
||||
if pl['pts'] is None:
|
||||
continue
|
||||
@@ -334,7 +336,7 @@ def classify(trak, mp, decoded):
|
||||
cen = P.mean(axis=0)
|
||||
samples = [cen] + [cen + (q - cen) * 0.7 for q in P]
|
||||
if not tiles:
|
||||
votes[(mi, k)][1] += 1 # nie platziert: ohne Weltbezug -> als unsichtbar werten
|
||||
votes[(mi, k)][1] += 1 # never placed: no world reference -> count as invisible
|
||||
continue
|
||||
for ti in tiles:
|
||||
x, y, z, rot, _, _ = mp['A'][ti]
|
||||
@@ -348,7 +350,7 @@ def classify(trak, mp, decoded):
|
||||
pl['invis'] = vs[1] > vs[0]
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Overlay je Modell
|
||||
# ------------------------------------------------------------------ overlay per model
|
||||
|
||||
def mat_color(mat, matcols):
|
||||
if mat in MAT_INFO:
|
||||
@@ -367,7 +369,7 @@ def poly_overlay(mesh, pl, pal, opt, matcols):
|
||||
ecol = KIND_COL[pl['kind']] if mat == 0 else mat_color(mat, matcols)
|
||||
off = n * opt.offset
|
||||
cen = P.mean(axis=0)
|
||||
# Inkreis-Abschaetzung: kleinster Abstand Mittelpunkt -> Kante
|
||||
# incircle estimate: smallest distance centre -> edge
|
||||
rmin = 1e9
|
||||
for k in range(len(P)):
|
||||
a, b = P[k], P[(k + 1) % len(P)]
|
||||
@@ -377,7 +379,7 @@ def poly_overlay(mesh, pl, pal, opt, matcols):
|
||||
continue
|
||||
rmin = min(rmin, np.linalg.norm(np.cross(e, cen - a)) / L)
|
||||
w = min(opt.width, 0.4 * rmin)
|
||||
# innere Ecken: Kantengeraden um w nach innen verschoben, mit Flaechenebene schneiden
|
||||
# inner corners: edge lines shifted inwards by w, intersected with the surface plane
|
||||
E = c['edges']
|
||||
m = len(E)
|
||||
ok = True
|
||||
@@ -395,7 +397,7 @@ def poly_overlay(mesh, pl, pal, opt, matcols):
|
||||
inner = pts2
|
||||
else:
|
||||
inner = [cen + (q - cen) * 0.85 for q in P]
|
||||
O = [mesh.v(q + off, n) for q in P] # Ecken einmal anlegen (Rahmen + Fuellung teilen sie)
|
||||
O = [mesh.v(q + off, n) for q in P] # create corners once (frame + fill share them)
|
||||
I = [mesh.v(q + off, n) for q in inner]
|
||||
ec = pal(ecol)
|
||||
for k in range(len(P)):
|
||||
@@ -416,7 +418,7 @@ def poly_overlay(mesh, pl, pal, opt, matcols):
|
||||
|
||||
|
||||
def append_mesh(model, mesh, pal_base, limit=7900):
|
||||
"""Haengt Mesh an Modell an (Batch-Flag 0x8 bei Texturwechsel / alle 256 Faces)."""
|
||||
"""Appends a mesh to a model (batch flag 0x8 on texture change / every 256 faces)."""
|
||||
nv0 = len(model.verts)
|
||||
if nv0 + len(mesh.verts) > limit:
|
||||
return 0
|
||||
@@ -437,7 +439,7 @@ def append_mesh(model, mesh, pal_base, limit=7900):
|
||||
return len(mesh.verts)
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Marker fuer Objekte
|
||||
# ------------------------------------------------------------------ markers for objects
|
||||
|
||||
def fx(v):
|
||||
v = v - (1 << 32) if v >= 1 << 31 else v
|
||||
@@ -445,15 +447,15 @@ def fx(v):
|
||||
|
||||
|
||||
def strat_markers(ch, wf, pal, stats):
|
||||
"""Liefert Liste (welt-Mesh-Teile) als dict cell -> Mesh in Weltkoordinaten (Exportraum)."""
|
||||
"""Returns the world mesh parts as dict cell -> Mesh in world coordinates (export space)."""
|
||||
mm = mapchunk.parse(G.wad_get(ch, 'MAP'), wf, mapchunk.trak_vertcounts(G.wad_get(ch, 'TRAK')))
|
||||
st = G.wad_get(ch, 'STPC')
|
||||
import stpcwalk
|
||||
lo = stpcwalk.walk(st, wf)['code']
|
||||
nodes = mm['nodes']
|
||||
segs = [] # (a, b, breite, farbe) Weltraum Spielkoordinaten (z positiv)
|
||||
cubes = [] # (c, h, farbe)
|
||||
quads = [] # (4 Punkte, farbe, alpha)
|
||||
segs = [] # (a, b, width, colour) world space, game coordinates (z positive)
|
||||
cubes = [] # (c, h, colour)
|
||||
quads = [] # (4 points, colour, alpha)
|
||||
per_cat = collections.Counter()
|
||||
per_type = collections.Counter()
|
||||
|
||||
@@ -478,7 +480,7 @@ def strat_markers(ch, wf, pal, stats):
|
||||
name = S.strat_name(st, s[6], lo) or '?'
|
||||
cat = mark_cat(name)
|
||||
if cat is None:
|
||||
# alle uebrigen Objekte: kleiner dunkler Punkt am Ursprung (nichts geht verloren)
|
||||
# all other objects: small dark dot at the origin (nothing gets lost)
|
||||
per_cat['objekt'] += 1
|
||||
cubes.append((np.array([fx(s[3]), fx(s[4]), fx(s[5])]) + [0, 0.06, 0], 0.03, MARK_COL['objekt']))
|
||||
continue
|
||||
@@ -487,11 +489,11 @@ def strat_markers(ch, wf, pal, stats):
|
||||
col = MARK_COL[cat]
|
||||
p = np.array([fx(s[3]), fx(s[4]), fx(s[5])])
|
||||
rot = s[1] / 4096 * 2 * math.pi
|
||||
# Marker: Wuerfel + Pfahl
|
||||
# marker: cube + post
|
||||
top = p + [0, MARK_H, 0]
|
||||
if cat == 'start':
|
||||
# Pfeil flach auf dem Boden (blockiert die Startkamera nicht)
|
||||
d = np.array([math.sin(rot), 0, math.cos(rot)]) # 0 = +z, 90 Grad = +x
|
||||
# arrow flat on the ground (doesn't block the start camera)
|
||||
d = np.array([math.sin(rot), 0, math.cos(rot)]) # 0 = +z, 90 degrees = +x
|
||||
q = np.array([d[2], 0, -d[0]])
|
||||
g = p + [0, 0.03, 0]
|
||||
segs.append((g - d * 0.3, g + d * 0.4, 0.025, col))
|
||||
@@ -530,16 +532,16 @@ def strat_markers(ch, wf, pal, stats):
|
||||
prev = q
|
||||
stats['pfadpunkte'] += len(ch_)
|
||||
|
||||
# Umgebungszonen (MAP-Block 4, 90 Byte: Zelle x/y/z, Nebel, Musik ...) -> Drahtwuerfel je Zelle
|
||||
# environment zones (MAP block 4, 90 bytes: cell x/y/z, fog, music ...) -> wire cube per cell
|
||||
col = MARK_COL['umgebung']
|
||||
for L in mm['lights']:
|
||||
cx, cy, cz = L[0], L[1], L[2]
|
||||
if L[3:6] == (1, 1, 1):
|
||||
continue # Vorgabe-Eintrag (ganzes Level)
|
||||
continue # default entry (whole level)
|
||||
box((cx + 0.04, cy, cz + 0.04), (cx + 0.96, cy + 0.92, cz + 0.96), col, 0.02)
|
||||
per_cat['umgebung'] += 1
|
||||
|
||||
# alles in Zellen buckeln (Exportraum: z negieren)
|
||||
# bucket everything into cells (export space: negate z)
|
||||
cells = collections.defaultdict(Mesh)
|
||||
|
||||
def cell_of(q):
|
||||
@@ -554,7 +556,7 @@ def strat_markers(ch, wf, pal, stats):
|
||||
for c, h, col in cubes:
|
||||
cells[cell_of(c)].cube(ex(c), h, pal(col))
|
||||
for pts, col in quads:
|
||||
# in <=1x1-Stuecke zerlegen
|
||||
# split into <=1x1 pieces
|
||||
(x0, y, z0), _, (x1, _, z1), _ = pts
|
||||
xs = np.arange(math.floor(x0), math.ceil(x1))
|
||||
zs = np.arange(math.floor(z0), math.ceil(z1))
|
||||
@@ -575,7 +577,7 @@ def strat_markers(ch, wf, pal, stats):
|
||||
return cells
|
||||
|
||||
|
||||
# ------------------------------------------------------------------ Hauptablauf
|
||||
# ------------------------------------------------------------------ main flow
|
||||
|
||||
def process(src, dst, opt):
|
||||
ch = G.wad_read(src)
|
||||
@@ -592,7 +594,7 @@ def process(src, dst, opt):
|
||||
if not opt.no_coll:
|
||||
decoded = [decode_model_coll(m) for m in trak]
|
||||
classify(trak, mp, decoded)
|
||||
# Statistik je Kachelinstanz
|
||||
# statistics per tile instance
|
||||
inst = collections.Counter(mp['midx'])
|
||||
for mi, polys in enumerate(decoded):
|
||||
for pl in polys:
|
||||
@@ -610,11 +612,11 @@ def process(src, dst, opt):
|
||||
add_v[mi] = len(mesh.verts)
|
||||
mesh_store = mesh
|
||||
trak[mi]._ov = mesh_store
|
||||
# Marker
|
||||
# markers
|
||||
cells = {}
|
||||
if not opt.no_markers:
|
||||
cells = strat_markers(ch, wf, pal, stats)
|
||||
# TEXT erweitern
|
||||
# extend TEXT
|
||||
text, base = text_append_flats(G.wad_get(ch, 'TEXT'), pal.entries)
|
||||
G.wad_set(ch, 'TEXT', text)
|
||||
for mi, m in enumerate(trak):
|
||||
@@ -624,7 +626,7 @@ def process(src, dst, opt):
|
||||
if got == 0:
|
||||
stats['modelle_zu_gross'] += 1
|
||||
add_v[mi] = 0
|
||||
# neue Marker-Kacheln
|
||||
# new marker tiles
|
||||
W, H = mp['W'], mp['H']
|
||||
new_tiles = []
|
||||
for (cx, cz), mesh in sorted(cells.items()):
|
||||
@@ -640,7 +642,7 @@ def process(src, dst, opt):
|
||||
loc = Mesh()
|
||||
loc.verts = [(v[0] - ox, v[1] - oy, v[2] - oz, v[3], v[4], v[5]) for v in mesh.verts]
|
||||
loc.tris = mesh.tris
|
||||
# zu grosse Zellen aufteilen
|
||||
# split cells that are too large
|
||||
if len(loc.verts) > 7900:
|
||||
stats['marker_gekuerzt'] += 1
|
||||
keep = [t for t in loc.tris if max(t[:3]) < 7900]
|
||||
@@ -651,7 +653,7 @@ def process(src, dst, opt):
|
||||
new_tiles.append(dict(x=ox, y=oy, z=oz, rot=0, model=len(trak) - 1,
|
||||
cols=[[0x00808080] * len(mdl.verts)]))
|
||||
stats['marker_kacheln'] = len(new_tiles)
|
||||
# MAP neu
|
||||
# rebuild MAP
|
||||
altmap = dict(zip([i for i in range(mp['N']) if mp['A'][i][5]], mp['anim']))
|
||||
tiles = []
|
||||
for i in range(mp['N']):
|
||||
@@ -666,7 +668,7 @@ def process(src, dst, opt):
|
||||
newmap = G.build_map_tiles(G.wad_get(ch, 'MAP'), wf, old_vc, tiles, zones='keep', anim=mp['anim'])
|
||||
G.wad_set(ch, 'TRAK', G.build_trak(trak))
|
||||
G.wad_set(ch, 'MAP', newmap)
|
||||
# Gegenprobe: MAP vollstaendig parsen, Strats unveraendert
|
||||
# cross-check: MAP parses completely, strats unchanged
|
||||
vc = [len(m.verts) for m in trak]
|
||||
a = mapchunk.parse(newmap, wf, vc)
|
||||
b = mapchunk.parse(G.wad_get(G.wad_read(src), 'MAP'), wf, old_vc)
|
||||
@@ -693,7 +695,7 @@ def main():
|
||||
ap.add_argument('out', nargs='?')
|
||||
ap.add_argument('--all', metavar='OUTDIR')
|
||||
ap.add_argument('--src', default=CD_WADS)
|
||||
ap.add_argument('--only', help='Kommagetrennte Levelnamen (mit --all)')
|
||||
ap.add_argument('--only', help='comma-separated level names (with --all)')
|
||||
ap.add_argument('--no-coll', action='store_true')
|
||||
ap.add_argument('--no-markers', action='store_true')
|
||||
ap.add_argument('--no-fill', action='store_true')
|
||||
@@ -712,12 +714,12 @@ def main():
|
||||
for f in files:
|
||||
info = process(f, os.path.join(opt.all, os.path.basename(f)), opt)
|
||||
infos.append(info)
|
||||
print('%-13s %5d KB -> %5d KB Koll %5d (unsichtbar %4d) Marker-Kacheln %3d maxV %4d' % (
|
||||
print('%-13s %5d KB -> %5d KB coll %5d (invisible %4d) marker tiles %3d maxV %4d' % (
|
||||
info['level'], info['groesse_alt'] // 1024, info['groesse_neu'] // 1024, info.get('koll_polys', 0),
|
||||
info.get('koll_unsichtbar', 0), info.get('marker_kacheln', 0), info['max_verts_modell']), flush=True)
|
||||
else:
|
||||
if not (opt.inp and opt.out):
|
||||
ap.error('IN.wad OUT.wad oder --all OUTDIR')
|
||||
ap.error('IN.wad OUT.wad or --all OUTDIR')
|
||||
info = process(opt.inp, opt.out, opt)
|
||||
infos.append(info)
|
||||
print(json.dumps(info, indent=1, ensure_ascii=False))
|
||||
|
||||
Reference in new issue
Block a user