basic tui implementation

This commit is contained in:
Doc
2025-09-28 13:48:56 +02:00
parent bfb1c7bef6
commit a5a28840b1
5 changed files with 520 additions and 24 deletions

View File

@@ -2,7 +2,7 @@ package app
import (
"fmt"
"log"
"io"
"os"
"path/filepath"
"strings"
@@ -33,9 +33,14 @@ type Options struct {
DotOut string
TreePNG string
Overlay string
Out io.Writer
}
func Run(opts Options) error {
if opts.Out == nil {
opts.Out = os.Stdout
}
if strings.TrimSpace(opts.WadPath) == "" {
return fmt.Errorf("wad path required")
}
@@ -47,9 +52,9 @@ func Run(opts Options) error {
defer w.Close()
if opts.ListOnly {
fmt.Printf("WAD: %s\n", opts.WadPath)
fmt.Fprintf(opts.Out, "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)
fmt.Fprintf(opts.Out, "%3d: %-8s size=%-7d pos=%-8d\n", i, d.Name(), d.Size, d.FilePos)
}
return nil
}
@@ -58,7 +63,7 @@ func Run(opts Options) error {
if err != nil {
return fmt.Errorf("find map: %w", err)
}
fmt.Printf("Map %s: Directory [%d, %d)\n", strings.ToUpper(opts.MapMarker), start, end)
fmt.Fprintf(opts.Out, "Map %s: Directory [%d, %d)\n", strings.ToUpper(opts.MapMarker), start, end)
if opts.Info {
lumps, err := w.LoadMapLumps(opts.MapMarker, "VERTEXES", "LINEDEFS")
@@ -74,18 +79,18 @@ func Run(opts Options) error {
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.Fprintf(opts.Out, "VERTEXES: bytes=%d count=%d\n", len(vb), verts)
fmt.Fprintf(opts.Out, "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])
fmt.Fprintf(opts.Out, "Map has %d vertices and %d linedefs\n", len(m.Vertices), len(m.Linedefs))
fmt.Fprintf(opts.Out, "First vertex: %+v\n", m.Vertices[0])
fmt.Fprintf(opts.Out, "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")
fmt.Fprintln(opts.Out, "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")
fmt.Fprintln(opts.Out, "WARN: LINEDEFS size ist kein Vielfaches von 14 → Format prüfen")
}
}
@@ -102,7 +107,7 @@ func Run(opts Options) error {
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))
fmt.Fprintf(opts.Out, "wrote %s (%d bytes)\n", dst, len(data))
}
}
@@ -117,9 +122,9 @@ func Run(opts Options) error {
}
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))
fmt.Fprintf(opts.Out, "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")
fmt.Fprintln(opts.Out, "GEOM: keine Segmente gefunden prüfe LINEDEFS/VERTEXES")
return nil
}
@@ -130,7 +135,7 @@ func Run(opts Options) error {
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",
fmt.Fprintf(opts.Out, "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
@@ -152,8 +157,8 @@ func Run(opts Options) error {
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",
fmt.Fprintf(opts.Out, "PROBE-SPLIT: O=(%.1f,%.1f) D=(%.1f,%.1f)\n", O.X, O.Y, D.X, D.Y)
fmt.Fprintf(opts.Out, "PROBE-SPLIT: left=%d right=%d splits=%d degens=%d (EPS=%.1e)\n",
left, right, splits, degens, geom.EPS)
return nil
@@ -177,23 +182,23 @@ func Run(opts Options) error {
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",
fmt.Fprintln(opts.Out, "BSP built.")
fmt.Fprintf(opts.Out, " 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",
fmt.Fprintf(opts.Out, " 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)
fmt.Fprintf(opts.Out, "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)
fmt.Fprintf(opts.Out, "Graphviz fehlgeschlagen: %v\n", err)
} else {
fmt.Printf("Graphviz PNG gebaut: %s\n", opts.TreePNG)
fmt.Fprintf(opts.Out, "Graphviz PNG gebaut: %s\n", opts.TreePNG)
}
}
}
@@ -202,7 +207,7 @@ func Run(opts Options) error {
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)
fmt.Fprintf(opts.Out, "Overlay PNG geschrieben: %s\n", opts.Overlay)
}
return nil
}