revectored app entrypoint
This commit is contained in:
211
internal/app/app.go
Normal file
211
internal/app/app.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"bspviz/internal/bsp"
|
||||
"bspviz/internal/geom"
|
||||
"bspviz/internal/mapfmt"
|
||||
"bspviz/internal/viz"
|
||||
"bspviz/internal/wad"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
WadPath string
|
||||
MapMarker string
|
||||
ListOnly bool
|
||||
Info bool
|
||||
Extract []string
|
||||
OutDir string
|
||||
GeomTest bool
|
||||
BuildBSP bool
|
||||
Alpha float64
|
||||
Beta float64
|
||||
Eps float64
|
||||
LeafMax int
|
||||
MaxDepth int
|
||||
Cands int
|
||||
Seed int64
|
||||
DotOut string
|
||||
TreePNG string
|
||||
Overlay string
|
||||
}
|
||||
|
||||
func Run(opts Options) error {
|
||||
if strings.TrimSpace(opts.WadPath) == "" {
|
||||
return fmt.Errorf("wad path required")
|
||||
}
|
||||
|
||||
w, err := wad.Open(opts.WadPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open wad: %w", err)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
if opts.ListOnly {
|
||||
fmt.Printf("WAD: %s\n", opts.WadPath)
|
||||
for i, d := range w.Dir() {
|
||||
fmt.Printf("%3d: %-8s size=%-7d pos=%-8d\n", i, d.Name(), d.Size, d.FilePos)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
start, end, err := w.FindMap(opts.MapMarker)
|
||||
if err != nil {
|
||||
return fmt.Errorf("find map: %w", err)
|
||||
}
|
||||
fmt.Printf("Map %s: Directory [%d, %d)\n", strings.ToUpper(opts.MapMarker), start, end)
|
||||
|
||||
if opts.Info {
|
||||
lumps, err := w.LoadMapLumps(opts.MapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
return fmt.Errorf("load map lumps: %w", err)
|
||||
}
|
||||
vb := lumps["VERTEXES"]
|
||||
lb := lumps["LINEDEFS"]
|
||||
m, err := mapfmt.LoadMap(lumps)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
verts := len(vb) / 4
|
||||
lines := len(lb) / 14
|
||||
fmt.Printf("VERTEXES: bytes=%d count=%d\n", len(vb), verts)
|
||||
fmt.Printf("LINEDEFS: bytes=%d count=%d\n", len(lb), lines)
|
||||
|
||||
fmt.Printf("Map has %d vertices and %d linedefs\n", len(m.Vertices), len(m.Linedefs))
|
||||
fmt.Printf("First vertex: %+v\n", m.Vertices[0])
|
||||
fmt.Printf("First linedef: %+v\n", m.Linedefs[0])
|
||||
|
||||
if len(vb)%4 != 0 {
|
||||
fmt.Println("WARN: VERTEXES size ist kein Vielfaches von 4 → Format prüfen")
|
||||
}
|
||||
if len(lb)%14 != 0 {
|
||||
fmt.Println("WARN: LINEDEFS size ist kein Vielfaches von 14 → Format prüfen")
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.Extract) > 0 {
|
||||
lumps, err := w.LoadMapLumps(opts.MapMarker, opts.Extract...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("extract: %w", err)
|
||||
}
|
||||
if err := os.MkdirAll(opts.OutDir, 0o755); err != nil {
|
||||
return fmt.Errorf("mkdir %s: %w", opts.OutDir, err)
|
||||
}
|
||||
for name, data := range lumps {
|
||||
dst := filepath.Join(opts.OutDir, fmt.Sprintf("%s.lmp", name))
|
||||
if err := os.WriteFile(dst, data, 0o644); err != nil {
|
||||
return fmt.Errorf("write %s: %w", dst, err)
|
||||
}
|
||||
fmt.Printf("wrote %s (%d bytes)\n", dst, len(data))
|
||||
}
|
||||
}
|
||||
|
||||
if opts.GeomTest {
|
||||
raw, err := w.LoadMapLumps(opts.MapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
return fmt.Errorf("load map lumps: %w", err)
|
||||
}
|
||||
m, err := mapfmt.LoadMap(raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse map: %w", err)
|
||||
}
|
||||
|
||||
segs := mapfmt.LinedefsToSegs(m.Vertices, m.Linedefs)
|
||||
fmt.Printf("GEOM: vertices=%d linedefs=%d segs=%d\n", len(m.Vertices), len(m.Linedefs), len(segs))
|
||||
if len(segs) == 0 {
|
||||
fmt.Println("GEOM: keine Segmente gefunden – prüfe LINEDEFS/VERTEXES")
|
||||
return nil
|
||||
}
|
||||
|
||||
pts := make([]geom.Vec, 0, len(m.Vertices))
|
||||
for _, v := range m.Vertices {
|
||||
pts = append(pts, geom.V(float64(v.X), float64(v.Y)))
|
||||
}
|
||||
bb := geom.Bounds(pts)
|
||||
w := bb.Max.X - bb.Min.X
|
||||
h := bb.Max.Y - bb.Min.Y
|
||||
fmt.Printf("AABB: min=(%.1f,%.1f) max=(%.1f,%.1f) size=(%.1f×%.1f)\n",
|
||||
bb.Min.X, bb.Min.Y, bb.Max.X, bb.Max.Y, w, h)
|
||||
|
||||
O := segs[0].A
|
||||
D := geom.Sub(segs[0].B, segs[0].A)
|
||||
if geom.Len(D) < 1e-9 && len(segs) > 1 {
|
||||
O = segs[1].A
|
||||
D = geom.Sub(segs[1].B, segs[1].A)
|
||||
}
|
||||
var left, right, splits, degens int
|
||||
for _, s := range segs {
|
||||
f, b := geom.SplitSeg(s, O, D)
|
||||
if len(f) == 0 && len(b) == 0 {
|
||||
degens++
|
||||
continue
|
||||
}
|
||||
left += len(f)
|
||||
right += len(b)
|
||||
if len(f) > 0 && len(b) > 0 {
|
||||
splits++
|
||||
}
|
||||
}
|
||||
fmt.Printf("PROBE-SPLIT: O=(%.1f,%.1f) D=(%.1f,%.1f)\n", O.X, O.Y, D.X, D.Y)
|
||||
fmt.Printf("PROBE-SPLIT: left=%d right=%d splits=%d degens=%d (EPS=%.1e)\n",
|
||||
left, right, splits, degens, geom.EPS)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
if opts.BuildBSP {
|
||||
raw, err := w.LoadMapLumps(opts.MapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
return fmt.Errorf("load map lumps: %w", err)
|
||||
}
|
||||
m, err := mapfmt.LoadMap(raw)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse map: %w", err)
|
||||
}
|
||||
|
||||
segs := mapfmt.LinedefsToSegs(m.Vertices, m.Linedefs)
|
||||
p := bsp.Params{
|
||||
Alpha: opts.Alpha, Beta: opts.Beta, Eps: opts.Eps,
|
||||
MaxDepth: opts.MaxDepth, LeafMax: opts.LeafMax, Cands: opts.Cands, Seed: opts.Seed,
|
||||
}
|
||||
root := bsp.Build(segs, p)
|
||||
st := bsp.Measure(root)
|
||||
|
||||
fmt.Printf("BSP built.\n")
|
||||
fmt.Printf(" nodes=%d leaves=%d maxDepth=%d totalLeafSegs=%d\n",
|
||||
st.Nodes, st.Leaves, st.MaxDepth, st.TotalSegs)
|
||||
fmt.Printf(" params: alpha=%.2f beta=%.2f eps=%.1e leafMax=%d maxDepth=%d cands=%d seed=%d\n",
|
||||
p.Alpha, p.Beta, p.Eps, p.LeafMax, p.MaxDepth, p.Cands, p.Seed)
|
||||
|
||||
if opts.DotOut != "" {
|
||||
if err := viz.EmitDOT(root, opts.DotOut); err != nil {
|
||||
return fmt.Errorf("write DOT: %w", err)
|
||||
}
|
||||
fmt.Printf("DOT export geschrieben: %s\n", opts.DotOut)
|
||||
|
||||
if opts.TreePNG != "" {
|
||||
if err := viz.RunGraphviz(opts.DotOut, opts.TreePNG); err != nil {
|
||||
log.Printf("Graphviz fehlgeschlagen: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Graphviz PNG gebaut: %s\n", opts.TreePNG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Overlay != "" {
|
||||
if err := viz.RenderPNG(m, root, opts.Overlay); err != nil {
|
||||
return fmt.Errorf("write overlay PNG: %w", err)
|
||||
}
|
||||
fmt.Printf("Overlay PNG geschrieben: %s\n", opts.Overlay)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
201
main.go
201
main.go
@@ -1,16 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bspviz/internal/bsp"
|
||||
"bspviz/internal/app"
|
||||
"bspviz/internal/geom"
|
||||
"bspviz/internal/mapfmt"
|
||||
"bspviz/internal/viz"
|
||||
"bspviz/internal/wad"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -49,178 +45,41 @@ func main() {
|
||||
usageAndExit("Flag -wad fehlt. Bitte Pfad zu einer Doom-kompatiblen WAD-Datei angeben.", 2)
|
||||
}
|
||||
|
||||
w, err := wad.Open(*wadPath)
|
||||
if err != nil {
|
||||
log.Fatalf("open wad: %v", err)
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
if *listOnly {
|
||||
fmt.Printf("WAD: %s\n", *wadPath)
|
||||
for i, d := range w.Dir() {
|
||||
fmt.Printf("%3d: %-8s size=%-7d pos=%-8d\n", i, d.Name(), d.Size, d.FilePos)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
start, end, err := w.FindMap(*mapMarker)
|
||||
if err != nil {
|
||||
log.Fatalf("find map: %v", err)
|
||||
}
|
||||
fmt.Printf("Map %s: Directory [%d, %d)\n", strings.ToUpper(*mapMarker), start, end)
|
||||
|
||||
//info über die daten in WAD
|
||||
if *info {
|
||||
lumps, err := w.LoadMapLumps(*mapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
log.Fatalf("load map lumps: %v", err)
|
||||
}
|
||||
vb := lumps["VERTEXES"]
|
||||
lb := lumps["LINEDEFS"]
|
||||
m, err := mapfmt.LoadMap(lumps)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
verts := len(vb) / 4
|
||||
lines := len(lb) / 14
|
||||
fmt.Printf("VERTEXES: bytes=%d count=%d\n", len(vb), verts)
|
||||
fmt.Printf("LINEDEFS: bytes=%d count=%d\n", len(lb), lines)
|
||||
|
||||
fmt.Printf("Map has %d vertices and %d linedefs\n", len(m.Vertices), len(m.Linedefs))
|
||||
fmt.Printf("First vertex: %+v\n", m.Vertices[0])
|
||||
fmt.Printf("First linedef: %+v\n", m.Linedefs[0])
|
||||
|
||||
if len(vb)%4 != 0 {
|
||||
fmt.Println("WARN: VERTEXES size ist kein Vielfaches von 4 → Format prüfen")
|
||||
}
|
||||
if len(lb)%14 != 0 {
|
||||
fmt.Println("WARN: LINEDEFS size ist kein Vielfaches von 14 → Format prüfen")
|
||||
}
|
||||
}
|
||||
|
||||
// Generiert einzelne Lump Dateien zum Debugen
|
||||
if *extract != "" {
|
||||
var extractLumps []string
|
||||
if strings.TrimSpace(*extract) != "" {
|
||||
want := strings.Split(*extract, ",")
|
||||
for i := range want {
|
||||
want[i] = strings.ToUpper(strings.TrimSpace(want[i]))
|
||||
}
|
||||
lumps, err := w.LoadMapLumps(*mapMarker, want...)
|
||||
if err != nil {
|
||||
log.Fatalf("extract: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(*outdir, 0o755); err != nil {
|
||||
log.Fatalf("mkdir %s: %v", *outdir, err)
|
||||
}
|
||||
for name, data := range lumps {
|
||||
dst := filepath.Join(*outdir, fmt.Sprintf("%s.lmp", name))
|
||||
if err := os.WriteFile(dst, data, 0o644); err != nil {
|
||||
log.Fatalf("write %s: %v", dst, err)
|
||||
}
|
||||
fmt.Printf("wrote %s (%d bytes)\n", dst, len(data))
|
||||
}
|
||||
}
|
||||
|
||||
// Zum debug test der geo functions
|
||||
if *geomtest {
|
||||
raw, err := w.LoadMapLumps(*mapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
log.Fatalf("load map lumps: %v", err)
|
||||
}
|
||||
m, err := mapfmt.LoadMap(raw)
|
||||
if err != nil {
|
||||
log.Fatalf("parse map: %v", err)
|
||||
}
|
||||
|
||||
segs := mapfmt.LinedefsToSegs(m.Vertices, m.Linedefs)
|
||||
fmt.Printf("GEOM: vertices=%d linedefs=%d segs=%d\n", len(m.Vertices), len(m.Linedefs), len(segs))
|
||||
if len(segs) == 0 {
|
||||
fmt.Println("GEOM: keine Segmente gefunden – prüfe LINEDEFS/VERTEXES")
|
||||
return
|
||||
}
|
||||
|
||||
pts := make([]geom.Vec, 0, len(m.Vertices))
|
||||
for _, v := range m.Vertices {
|
||||
pts = append(pts, geom.V(float64(v.X), float64(v.Y)))
|
||||
}
|
||||
bb := geom.Bounds(pts)
|
||||
w := bb.Max.X - bb.Min.X
|
||||
h := bb.Max.Y - bb.Min.Y
|
||||
fmt.Printf("AABB: min=(%.1f,%.1f) max=(%.1f,%.1f) size=(%.1f×%.1f)\n",
|
||||
bb.Min.X, bb.Min.Y, bb.Max.X, bb.Max.Y, w, h)
|
||||
|
||||
O := segs[0].A
|
||||
D := geom.Sub(segs[0].B, segs[0].A)
|
||||
if geom.Len(D) < 1e-9 && len(segs) > 1 {
|
||||
O = segs[1].A
|
||||
D = geom.Sub(segs[1].B, segs[1].A)
|
||||
}
|
||||
var left, right, splits, degens int
|
||||
for _, s := range segs {
|
||||
f, b := geom.SplitSeg(s, O, D)
|
||||
if len(f) == 0 && len(b) == 0 {
|
||||
degens++
|
||||
extractLumps = make([]string, 0, len(want))
|
||||
for _, name := range want {
|
||||
n := strings.ToUpper(strings.TrimSpace(name))
|
||||
if n == "" {
|
||||
continue
|
||||
}
|
||||
left += len(f)
|
||||
right += len(b)
|
||||
if len(f) > 0 && len(b) > 0 {
|
||||
splits++
|
||||
}
|
||||
extractLumps = append(extractLumps, n)
|
||||
}
|
||||
fmt.Printf("PROBE-SPLIT: O=(%.1f,%.1f) D=(%.1f,%.1f)\n", O.X, O.Y, D.X, D.Y)
|
||||
fmt.Printf("PROBE-SPLIT: left=%d right=%d splits=%d degens=%d (EPS=%.1e)\n",
|
||||
left, right, splits, degens, geom.EPS)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if *buildbsp {
|
||||
raw, err := w.LoadMapLumps(*mapMarker, "VERTEXES", "LINEDEFS")
|
||||
if err != nil {
|
||||
log.Fatalf("load map lumps: %v", err)
|
||||
}
|
||||
m, err := mapfmt.LoadMap(raw)
|
||||
if err != nil {
|
||||
log.Fatalf("parse map: %v", err)
|
||||
}
|
||||
|
||||
segs := mapfmt.LinedefsToSegs(m.Vertices, m.Linedefs)
|
||||
p := bsp.Params{
|
||||
Alpha: *alpha, Beta: *beta, Eps: *eps,
|
||||
MaxDepth: *depth, LeafMax: *leaf, Cands: *cands, Seed: *seed,
|
||||
}
|
||||
root := bsp.Build(segs, p)
|
||||
st := bsp.Measure(root)
|
||||
|
||||
fmt.Printf("BSP built.\n")
|
||||
fmt.Printf(" nodes=%d leaves=%d maxDepth=%d totalLeafSegs=%d\n",
|
||||
st.Nodes, st.Leaves, st.MaxDepth, st.TotalSegs)
|
||||
fmt.Printf(" params: alpha=%.2f beta=%.2f eps=%.1e leafMax=%d maxDepth=%d cands=%d seed=%d\n",
|
||||
p.Alpha, p.Beta, p.Eps, p.LeafMax, p.MaxDepth, p.Cands, p.Seed)
|
||||
|
||||
if *dotOut != "" {
|
||||
if err := viz.EmitDOT(root, *dotOut); err != nil {
|
||||
log.Fatalf("write DOT: %v", err)
|
||||
}
|
||||
fmt.Printf("DOT export geschrieben: %s\n", *dotOut)
|
||||
|
||||
if *treePNG != "" {
|
||||
if err := viz.RunGraphviz(*dotOut, *treePNG); err != nil {
|
||||
log.Printf("Graphviz fehlgeschlagen: %v", err)
|
||||
} else {
|
||||
fmt.Printf("Graphviz PNG gebaut: %s\n", *treePNG)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if *overlay != "" {
|
||||
if err := viz.RenderPNG(m, root, *overlay); err != nil {
|
||||
log.Fatalf("write overlay PNG: %v", err)
|
||||
}
|
||||
fmt.Printf("Overlay PNG geschrieben: %s\n", *overlay)
|
||||
}
|
||||
return
|
||||
opts := app.Options{
|
||||
WadPath: *wadPath,
|
||||
MapMarker: *mapMarker,
|
||||
ListOnly: *listOnly,
|
||||
Info: *info,
|
||||
Extract: extractLumps,
|
||||
OutDir: *outdir,
|
||||
GeomTest: *geomtest,
|
||||
BuildBSP: *buildbsp,
|
||||
Alpha: *alpha,
|
||||
Beta: *beta,
|
||||
Eps: *eps,
|
||||
LeafMax: *leaf,
|
||||
MaxDepth: *depth,
|
||||
Cands: *cands,
|
||||
Seed: *seed,
|
||||
DotOut: *dotOut,
|
||||
TreePNG: *treePNG,
|
||||
Overlay: *overlay,
|
||||
}
|
||||
|
||||
if err := app.Run(opts); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user