package assets import ( "flag" "fmt" "io" "os" "path/filepath" "strconv" "strings" ) var upscaleBackends = []string{"upscayl-bin", "upscayl", "realesrgan-ncnn-vulkan", "waifu2x-ncnn-vulkan"} // runUpscale upscales textures in place through an installed ncnn-vulkan // backend. DDS inputs are bridged through PNG so the NWN flip stays correct. func runUpscale(args []string, stdout, stderr io.Writer) int { fs := flag.NewFlagSet("upscale", flag.ContinueOnError) fs.SetOutput(stderr) scale := fs.Int("scale", 4, "upscale factor") backend := fs.String("backend", "", "override the upscaler binary") nonRecursive := fs.Bool("non-recursive", false, "do not descend into subdirectories") if err := fs.Parse(args); err != nil { return exitUsage } dirs := fs.Args() if len(dirs) == 0 { fmt.Fprintln(stderr, "assets upscale: usage: upscale [--scale N] ...") return exitUsage } candidates := upscaleBackends if *backend != "" { candidates = []string{*backend} } tool := look(candidates...) if tool == "" { fmt.Fprintf(stderr, "assets upscale: no upscaler found — install one of: %s\n", strings.Join(upscaleBackends, ", ")) return exitTool } files, err := walk(dirs, textureExts, !*nonRecursive) if err != nil { fmt.Fprintln(stderr, "assets upscale:", err) return exitUsage } // magick is only needed if a .dds input is present; resolve lazily. magick := "" failed := false for _, src := range files { var upErr error if strings.EqualFold(filepath.Ext(src), ".dds") { if magick == "" { if magick = look("magick"); magick == "" { fmt.Fprintln(stderr, "assets upscale: .dds input needs ImageMagick (magick) for the png bridge") return exitTool } } upErr = upscaleDDS(tool, magick, src, *scale) } else { upErr = upscaleImage(tool, src, src, *scale) } if upErr != nil { fmt.Fprintf(stderr, "assets upscale: %s: %v\n", src, upErr) failed = true } } if failed { return exitFail } return exitOK } // upscaleImage runs the ncnn-vulkan backend to upscale src into dst (may be the // same path). func upscaleImage(tool, src, dst string, scale int) error { tmp := dst + ".upscaled.png" out, err := runner("", nil, tool, "-i", src, "-o", tmp, "-s", strconv.Itoa(scale)) if err != nil { return fmt.Errorf("%s: %v: %s", filepath.Base(tool), err, strings.TrimSpace(string(out))) } return os.Rename(tmp, dst) } // upscaleDDS bridges a DDS through PNG: dds->png (flip), upscale, png->dds // (flip back), yielding a correctly-flipped upscaled DDS. func upscaleDDS(tool, magick, src string, scale int) error { tmpPNG := src + ".bridge.png" if err := ddsToPNG(magick, src, tmpPNG); err != nil { return err } defer os.Remove(tmpPNG) if err := upscaleImage(tool, tmpPNG, tmpPNG, scale); err != nil { return err } return pngToDDS(magick, tmpPNG, src) }