99 lines
2.8 KiB
Go
99 lines
2.8 KiB
Go
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] <dir>...")
|
|
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)
|
|
}
|