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:
MineTec committed 2026-11-07 10:51:14 +01:00
1 parent 86fe26d786
commit 526f6072f6
36 files changed
+1553 -1544

No files matched your search

+43 -43
View File
@@ -1,31 +1,31 @@
#!/usr/bin/env python3
"""OBJ -> neue Weltgeometrie (TRAK + Kachelteil von MAP) in einer Kopie eines Level-WADs.
"""OBJ -> new world geometry (TRAK + tile part of MAP) in a copy of a level WAD.
geom_import.py basis.wad mesh.obj neu.wad [--default-tex N] [--no-coll] [--mat N]
geom_import.py base.wad mesh.obj new.wad [--default-tex N] [--no-coll] [--mat N]
[--keep-tiles] [--band 6]
Eingabe-OBJ im Exportraum von geom_export.py (y oben, 1 Einheit = 1 Kachel, z < 0 liegt im
Raster; Rasterzelle (cx,cz) = (floor(x), floor(-z)), muss in 0..W-1 / 0..H-1 liegen).
Input OBJ in the export space of geom_export.py (y up, 1 unit = 1 tile, z < 0 lies in the
grid; grid cell (cx,cz) = (floor(x), floor(-z)), must be within 0..W-1 / 0..H-1).
Texturen: Die Engine kennt KEINE freien UVs. Jedes Dreieck zeigt eine Haelfte eines
Texturrechtecks (Eintrag der TEXT-Tabelle), die Ecken werden ueber Face-Flags gewaehlt.
usemtl page_NN -> Texturindex wird aus dem UV-Rechteck (Bounding-Box der Face-UVs)
auf Seite NN gesucht; UVs muessen auf Rechteck-Ecken liegen
(so wie geom_export sie schreibt).
usemtl tex_N -> Texturindex N; UVs (falls vorhanden) waehlen nur die Ecken-Belegung,
ohne UVs wird die Standardbelegung genommen.
usemtl flat_N -> Texturindex N (so exportiert geom_export Flachfarben)
sonst -> --default-tex
Vierecke werden als (0,1,2)+(2,3,0) zerlegt; mit Rechteck-UVs ergibt das genau die
Original-Belegung (Flags 0x800 / 0x810).
Vertexfarben: "v x y z r g b" (0..1, 1.0 = Originalhelligkeit 0x80); sonst 0x80.
Kollision: --coll-obj datei.obj (Polygone, Gruppen "matNN...") oder aus jedem Face ein konvexes Kollisionspolygon (Viereck wenn planar), eingetragen
in jede Rasterzelle, die das Polygon (xz-Bounding-Box) beruehrt. Material: Gruppe/Objekt
"..._matNN" bzw. --mat. (--no-coll: keine Kollision)
Textures: the engine has NO free UVs. Each triangle shows one half of a texture
rectangle (entry of the TEXT table); the corners are chosen via face flags.
usemtl page_NN -> texture index is looked up from the UV rectangle (bounding box of the
face UVs) on page NN; UVs must lie on rectangle corners
(the way geom_export writes them).
usemtl tex_N -> texture index N; UVs (if present) only choose the corner assignment,
without UVs the default assignment is used.
usemtl flat_N -> texture index N (this is how geom_export exports flat colours)
otherwise -> --default-tex
Quads are split as (0,1,2)+(2,3,0); with rectangle UVs this gives exactly the
original assignment (flags 0x800 / 0x810).
Vertex colours: "v x y z r g b" (0..1, 1.0 = original brightness 0x80); otherwise 0x80.
Collision: --coll-obj file.obj (polygons, groups "matNN...") or one convex collision polygon from each face (quad if planar), entered
into every grid cell the polygon (xz bounding box) touches. Material: group/object
"..._matNN" or --mat. (--no-coll: no collision)
Ausgabe: Ein Modell pro belegter (Zelle, Hoehenband). Alle vorhandenen Kacheln werden ersetzt
(ausser --keep-tiles: alte Kacheln + Modelle bleiben, neue kommen dazu).
Strats/Pfade/Zonen (Rest von MAP) und alle anderen Chunks bleiben unveraendert.
Output: one model per occupied (cell, height band). All existing tiles are replaced
(except with --keep-tiles: old tiles + models stay, new ones are added).
Strats/paths/zones (rest of MAP) and all other chunks stay unchanged.
"""
import argparse
import math
@@ -72,7 +72,7 @@ def read_obj(path):
def find_tex(texs, page, uvs):
"""Texturindex auf Seite 'page', dessen Rechteck am besten zu den UVs passt."""
"""Texture index on page 'page' whose rectangle best matches the UVs."""
us = [u * 256 for u, v in uvs]; vs = [v * 256 for u, v in uvs]
best, bd = None, 1e9
for i, t in enumerate(texs):
@@ -85,7 +85,7 @@ def find_tex(texs, page, uvs):
def match_pattern(uvs, rect):
"""Beste (Flags, Rotation) so dass face_uvs(flags) die gegebenen Ecken-UVs trifft."""
"""Best (flags, rotation) so that face_uvs(flags) hits the given corner UVs."""
best = (1e9, 0x800, 0)
for fl in PATTERNS:
ref = G.face_uvs(fl, rect)
@@ -108,14 +108,14 @@ def main():
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument('base'); ap.add_argument('obj'); ap.add_argument('out')
ap.add_argument('--default-tex', type=int, default=None)
ap.add_argument('--mat', type=int, default=0, help='Kollisionsmaterial (Standard 0)')
ap.add_argument('--mat', type=int, default=0, help='collision material (default 0)')
ap.add_argument('--no-coll', action='store_true')
ap.add_argument('--coll-obj', help='Kollision aus eigenem OBJ (z.B. collision.obj von geom_export) '
'statt aus den Render-Faces')
ap.add_argument('--coll-obj', help='collision from a separate OBJ (e.g. collision.obj from geom_export) '
'instead of the render faces')
ap.add_argument('--keep-tiles', action='store_true')
ap.add_argument('--zones', choices=['flat', 'keep'], default='flat',
help='flat: Zonen-Sichtbarkeit (PVS) abschalten, alles zeichnen; keep: Original')
ap.add_argument('--band', type=float, default=6.0, help='Hoehenband pro Kachel (Einheiten)')
help='flat: disable zone visibility (PVS), draw everything; keep: original')
ap.add_argument('--band', type=float, default=6.0, help='height band per tile (units)')
a = ap.parse_args()
ch, wf, trak, mp = G.load_level(a.base)
@@ -126,9 +126,9 @@ def main():
if deftex is None:
deftex = next(i for i, t in enumerate(texs) if not (t['flags'] & 1) and t['page'] >= 0)
# ---- Dreiecke mit Textur + Flags
# ---- triangles with texture + flags
tris = [] # (pos[3], col[3], tex, flags)
polys = [] # (pos list, mat) fuer Kollision
polys = [] # (pos list, mat) for collision
warn = defaultdict(int)
for vi, ti, mat, grp in faces:
pts = [V[i] for i in vi]; cols = [C[i] for i in vi]
@@ -140,7 +140,7 @@ def main():
if mm and mm.group(1) == 'page' and uvs:
tex, dist = find_tex(texs, int(mm.group(2)), uvs)
if tex is None or dist > 2:
warn['UV-Rechteck nicht gefunden'] += 1
warn['UV rectangle not found'] += 1
elif mm:
tex = int(mm.group(2))
if tex is None:
@@ -153,7 +153,7 @@ def main():
if uvs and not (t['flags'] & 1):
fl, rot, d = match_pattern([uvs[j] for j in idx], rect)
if d > 2.5 / 256:
warn['UVs nicht auf Rechteck-Ecken'] += 1
warn['UVs not on rectangle corners'] += 1
P = [P[(j + rot) % 3] for j in range(3)]; Cc = [Cc[(j + rot) % 3] for j in range(3)]
else:
fl = 0x800 if k % 2 else 0x810
@@ -166,7 +166,7 @@ def main():
m = re.search(r'mat(\d+)', grp or '')
polys.append(([cV[i] for i in vi], int(m.group(1)) if m else a.mat))
# ---- Zellen/Baender
# ---- cells/bands
def key_of(x, y, z):
cx, cz = math.floor(x), math.floor(-z)
return (cx, cz, math.floor(y / a.band))
@@ -184,7 +184,7 @@ def main():
for cz in range(math.floor(-P[:, 2].max()), math.floor(-P[:, 2].min() - 1e-6) + 1):
cells[(cx, cz, band)]['coll'].append((pts, mat))
# ---- Modelle bauen
# ---- build models
models, tiles = [], []
if a.keep_tiles:
models = list(trak)
@@ -194,7 +194,7 @@ def main():
altcols=mp['altcols'].get(i, [])))
for (cx, cz, band), cell in sorted(cells.items()):
if not (0 <= cx < W and 0 <= cz < H):
warn[f'ausserhalb des Rasters {W}x{H}'] += 1
warn[f'outside the {W}x{H} grid'] += 1
continue
allp = [p for t in cell['tris'] for p in t[0]] or [p for c in cell['coll'] for p in c[0]]
ty = float(round(np.median([p[1] for p in allp])))
@@ -218,8 +218,8 @@ def main():
for ids, tex, fl in facelist:
plane = G.face_plane(*[m.verts[i][:3] for i in ids])
st = (texs[tex]['page'], texs[tex]['flags'])
# Bit 0x8 = neuer Render-Batch (Zustand neu laden). Batch-Puffer 0x5d15f8 fasst ~4800
# Ausgabe-Vertices -> spaetestens alle 256 Faces neu starten.
# bit 0x8 = new render batch (reload state). Batch buffer 0x5d15f8 holds ~4800
# output vertices -> restart at least every 256 faces.
if st != prev or len(m.faces) % 256 == 0:
fl |= 0x8
prev = st
@@ -233,7 +233,7 @@ def main():
for pts, mat in cell['coll']:
loc = [(p[0] - ox, p[1] - ty, p[2] - oz) for p in pts]
if max(abs(c) for p in loc for c in p) > 7.9:
warn['Kollisionspolygon > 7.9 Einheiten vom Kachelzentrum (uebersprungen)'] += 1
warn['collision polygon > 7.9 units from tile centre (skipped)'] += 1
continue
recs = []
if len(loc) == 4:
@@ -252,12 +252,12 @@ def main():
r = bytes([r[0] | 4]) + r[1:]
m.coll[0].append(r)
if len(m.verts) > 8000 or len(m.faces) > 65535:
sys.exit('Kachel zu gross (Transformpuffer 0x58b0f0 fasst 8000 Vertices)')
sys.exit('tile too large (transform buffer 0x58b0f0 holds 8000 vertices)')
models.append(m)
tiles.append(dict(x=ox, y=ty, z=oz, rot=0, model=len(models) - 1, cols=[cols]))
if not models:
sys.exit('keine Geometrie')
sys.exit('no geometry')
newtrak = G.build_trak(models)
newmap = G.build_map_tiles(G.wad_get(ch, 'MAP'), wf, [len(m.verts) for m in trak], tiles, a.zones,
mp['anim'] if a.keep_tiles else ())
@@ -265,9 +265,9 @@ def main():
G.wad_set(ch, 'MAP', newmap)
G.wad_write(a.out, ch)
nf = sum(len(m.faces) for m in models); nc = sum(len(m.coll[0]) for m in models)
print(f'{a.out}: {len(models)} Modelle, {len(tiles)} Kacheln, {nf} Dreiecke, {nc} Kollisionspolygone')
print(f'{a.out}: {len(models)} models, {len(tiles)} tiles, {nf} triangles, {nc} collision polygons')
for k, v in warn.items():
print(f' WARNUNG: {k}: {v}x')
print(f' WARNING: {k}: {v}x')
if __name__ == '__main__':