diff --git a/.vscode/settings.json b/.vscode/settings.json index 248b3dd..b273e45 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,9 +14,11 @@ "gridify", "hacky", "hilbertify", + "Hitbox", "ipairs", "kbinani", "Lanczos", + "lann", "ldflags", "linearize", "lowram", @@ -25,7 +27,6 @@ "nfnt", "noita", "polymorphed", - "prerender", "promptui", "rasterizer", "savegames", diff --git a/bin/stitch/README.md b/bin/stitch/README.md index de003c3..3dd097e 100644 --- a/bin/stitch/README.md +++ b/bin/stitch/README.md @@ -46,8 +46,6 @@ example list of files: Lower bound of the output rectangle. This coordinate is not included in the output. - `ymin int` Upper bound of the output rectangle. This coordinate is included in the output. - - `prerender` - Pre renders the image in RAM before saving. Can speed things up if you have enough RAM. - `cleanup float` Enables cleanup mode with the given float as threshold. This will **DELETE** images from the input folder; no stitching will be done in this mode. A good value to start with is `0.999`, which deletes images where the sum of the min-max difference of each sub-pixel overlapping with other images is less than 99.9%% of the maximum possible sum of pixel differences. diff --git a/bin/stitch/entity.go b/bin/stitch/entity.go index fe137de..ec92e80 100644 --- a/bin/stitch/entity.go +++ b/bin/stitch/entity.go @@ -8,14 +8,13 @@ package main import ( "encoding/json" "image/color" - "log" "os" "github.com/tdewolff/canvas" ) -var entityDisplayFontFamily = canvas.NewFontFamily("times") -var entityDisplayFontFace *canvas.FontFace +//var entityDisplayFontFamily = canvas.NewFontFamily("times") +//var entityDisplayFontFace *canvas.FontFace var entityDisplayAreaDamageStyle = canvas.Style{ FillColor: color.RGBA{100, 0, 0, 100}, @@ -73,13 +72,13 @@ var entityDisplayCollisionTriggerStyle = canvas.Style{ } func init() { - fontName := "NimbusRoman-Regular" + //fontName := "NimbusRoman-Regular" - if err := entityDisplayFontFamily.LoadLocalFont(fontName, canvas.FontRegular); err != nil { - log.Printf("Couldn't load font %q: %v", fontName, err) - } + //if err := entityDisplayFontFamily.LoadLocalFont(fontName, canvas.FontRegular); err != nil { + // log.Printf("Couldn't load font %q: %v", fontName, err) + //} - entityDisplayFontFace = entityDisplayFontFamily.Face(48.0, canvas.White, canvas.FontRegular, canvas.FontNormal) + //entityDisplayFontFace = entityDisplayFontFamily.Face(48.0, canvas.White, canvas.FontRegular, canvas.FontNormal) } type Entity struct { @@ -146,6 +145,7 @@ func (e Entity) Draw(c *canvas.Context) { if member, ok := component.Members["circle_radius"]; ok { if radius, ok := member.(float64); ok && radius > 0 { // Theoretically we need to clip the damage area to the intersection of the AABB and the circle, but meh. + // TODO: Clip the area to the intersection of the box and the circle cx, cy := (aabbMinX+aabbMaxX)/2, (aabbMinY+aabbMaxY)/2 c.Style = entityDisplayAreaDamageStyle c.DrawPath(x+cx, y+cy, canvas.Circle(radius)) @@ -201,7 +201,7 @@ func (e Entity) Draw(c *canvas.Context) { c.DrawPath(x+aabbMinX, y+aabbMinY, canvas.Rectangle(aabbMaxX-aabbMinX, aabbMaxY-aabbMinY)) } - case "CollisionTriggerComponent": // Checks if another entity is inside the box with the given width and height. + case "CollisionTriggerComponent": // Checks if another entity is inside the given radius and box with the given width and height. var width, height float64 path := &canvas.Path{} if member, ok := component.Members["width"]; ok { @@ -213,6 +213,8 @@ func (e Entity) Draw(c *canvas.Context) { if width > 0 && height > 0 { path = canvas.Rectangle(width, height).Translate(-width/2, -height/2) } + // Theoretically we need to clip the area to the intersection of the box and the circle, but meh. + // TODO: Clip the area to the intersection of the box and the circle //if member, ok := component.Members["radius"]; ok { // if radius, ok := member.(float64); ok && radius > 0 { // path = path.Append(canvas.Circle(radius)) diff --git a/bin/stitch/medianBlendedImage.go b/bin/stitch/medianBlendedImage.go index a8239e1..d6fb1c3 100644 --- a/bin/stitch/medianBlendedImage.go +++ b/bin/stitch/medianBlendedImage.go @@ -76,7 +76,7 @@ func (mbi *MedianBlendedImage) At(x, y int) color.Color { // Opaque returns whether the image is fully opaque. // -// For more speed and smaller filesizes, MedianBlendedImage will be marked as non-transparent. +// For more speed and smaller file size, MedianBlendedImage will be marked as non-transparent. // This will speed up image saving by 2x, as there is no need to iterate over the whole image to find a single non opaque pixel. func (mbi *MedianBlendedImage) Opaque() bool { return true diff --git a/bin/stitch/stitch.go b/bin/stitch/stitch.go index cf7d6e1..7d9fc19 100644 --- a/bin/stitch/stitch.go +++ b/bin/stitch/stitch.go @@ -21,15 +21,14 @@ import ( ) var flagInputPath = flag.String("input", filepath.Join(".", "..", "..", "output"), "The source path of the image tiles to be stitched.") -var flagEntitiesInputPath = flag.String("entities", filepath.Join(".", "..", "..", "output", "entities.json"), "The source path of the entities.json file.") -var flagPlayerPathInputPath = flag.String("player-path", filepath.Join(".", "..", "..", "output", "player-path.json"), "The source path of the player-path.json file.") +var flagEntitiesInputPath = flag.String("entities", filepath.Join(".", "..", "..", "output", "entities.json"), "The path to the entities.json file.") +var flagPlayerPathInputPath = flag.String("player-path", filepath.Join(".", "..", "..", "output", "player-path.json"), "The path to the player-path.json file.") var flagOutputPath = flag.String("output", filepath.Join(".", "output.png"), "The path and filename of the resulting stitched image.") var flagScaleDivider = flag.Int("divide", 1, "A downscaling factor. 2 will produce an image with half the side lengths.") var flagXMin = flag.Int("xmin", 0, "Left bound of the output rectangle. This coordinate is included in the output.") var flagYMin = flag.Int("ymin", 0, "Upper bound of the output rectangle. This coordinate is included in the output.") var flagXMax = flag.Int("xmax", 0, "Right bound of the output rectangle. This coordinate is not included in the output.") var flagYMax = flag.Int("ymax", 0, "Lower bound of the output rectangle. This coordinate is not included in the output.") -var flagPrerender = flag.Bool("prerender", false, "Pre renders the image in RAM before saving. Can speed things up if you have enough RAM.") var flagCleanupThreshold = flag.Float64("cleanup", 0, "Enable cleanup mode with the given threshold. This will DELETE images from the input folder, no stitching will be done in this mode. A good value to start with is 0.999, which deletes images where the sum of the min-max difference of each sub-pixel overlapping with other images is less than 99.9%% of the maximum possible sum of pixel differences.") func main() { @@ -272,43 +271,30 @@ func main() { var wg sync.WaitGroup done := make(chan bool) - if *flagPrerender { - log.Printf("Creating output image with a size of %v", outputRect.Size()) - tempImage := image.NewRGBA(outputRect) + tempImage := NewMedianBlendedImage(tiles, outputRect) + _, max := tempImage.Progress() + bar.SetTotal(int64(max)).Start().SetRefreshRate(1 * time.Second) - log.Printf("Stitching %v tiles into an image at %v", len(tiles), tempImage.Bounds()) - if err := StitchGrid(tiles, tempImage, 512, bar); err != nil { - log.Panic(err) - } - bar.Finish() + wg.Add(1) + go func() { + defer wg.Done() - outputImage = tempImage - } else { - tempImage := NewMedianBlendedImage(tiles, outputRect) - _, max := tempImage.Progress() - bar.SetTotal(int64(max)).Start().SetRefreshRate(1 * time.Second) - - wg.Add(1) - go func() { - defer wg.Done() - - ticker := time.NewTicker(1 * time.Second) - for { - select { - case <-done: - value, _ := tempImage.Progress() - bar.SetCurrent(int64(value)) - bar.Finish() - return - case <-ticker.C: - value, _ := tempImage.Progress() - bar.SetCurrent(int64(value)) - } + ticker := time.NewTicker(1 * time.Second) + for { + select { + case <-done: + value, _ := tempImage.Progress() + bar.SetCurrent(int64(value)) + bar.Finish() + return + case <-ticker.C: + value, _ := tempImage.Progress() + bar.SetCurrent(int64(value)) } - }() + } + }() - outputImage = tempImage - } + outputImage = tempImage log.Printf("Creating output file \"%v\"", *flagOutputPath) f, err := os.Create(*flagOutputPath) @@ -321,10 +307,8 @@ func main() { log.Panic(err) } - if !*flagPrerender { - done <- true - wg.Wait() - } + done <- true + wg.Wait() if err := f.Close(); err != nil { log.Panic(err) diff --git a/bin/stitch/util.go b/bin/stitch/util.go index 4603454..5b766eb 100644 --- a/bin/stitch/util.go +++ b/bin/stitch/util.go @@ -8,15 +8,10 @@ package main import ( "fmt" "image" - "image/color" "math" "os" "sort" - "golang.org/x/image/font" - "golang.org/x/image/font/basicfont" - "golang.org/x/image/math/fixed" - "github.com/google/hilbert" ) @@ -103,36 +98,6 @@ func hilbertifyRectangle(rect image.Rectangle, gridSize int) ([]image.Rectangle, return grid, nil } -func drawLabel(img *image.RGBA, x, y int, label string) { - col := color.RGBA{200, 100, 0, 255} - point := fixed.Point26_6{X: fixed.Int26_6(x * 64), Y: fixed.Int26_6(y * 64)} - - d := &font.Drawer{ - Dst: img, - Src: image.NewUniform(col), - Face: basicfont.Face7x13, - Dot: point, - } - d.DrawString(label) -} - -func intAbs(x int) int { - if x < 0 { - return -x - } - return x -} - -func pointAbs(p image.Point) image.Point { - if p.X < 0 { - p.X = -p.X - } - if p.Y < 0 { - p.Y = -p.Y - } - return p -} - // Integer division that rounds to the next integer towards negative infinity. func divideFloor(a, b int) int { temp := a / b @@ -154,10 +119,3 @@ func divideCeil(a, b int) int { return temp } - -func maxInt(x, y int) int { - if x > y { - return x - } - return y -}