package storage import ( "errors" "fmt" "image" "image/color" "image/draw" "image/png" "log" "os" ) type Tile struct { Dirty bool Image *image.RGBA } var tiles [][]Tile type WrongSizeError struct { ExpectedSize int ActualSize image.Point X int Y int } func (err *WrongSizeError) Error() string { return fmt.Sprintf("expected %dx%d tile, got %dx%d (coords: %d-%d)", err.ExpectedSize, err.ExpectedSize, err.ActualSize.X, err.ActualSize.Y, err.X, err.Y) } func Load(path string, canvasSize int, tileSize int) { if err := os.Chdir(path); err != nil { panic(err) } tiles = make([][]Tile, canvasSize) for i := range tiles { tiles[i] = make([]Tile, canvasSize) } for y := range tiles { for x := range tiles[y] { tiles[y][x].Image = image.NewRGBA(image.Rect(0, 0, tileSize, tileSize)) filename := fmt.Sprintf("%d-%d.png", x, y) file, err := os.Open(filename) if err != nil { file, err = os.Create(filename) if err != nil { panic(err) } draw.Draw(tiles[y][x].Image, tiles[y][x].Image.Bounds(), &image.Uniform{C: image.White}, image.Point{}, draw.Src) if err = png.Encode(file, tiles[y][x].Image); err != nil { panic(err) } log.Printf("Created tile (%d-%d)\n", x, y) } else { img, _, err := image.Decode(file) if err != nil { panic(err) } draw.Draw(tiles[y][x].Image, img.Bounds(), img, img.Bounds().Min, draw.Src) } defer file.Close() if tiles[y][x].Image.Bounds().Size().X != tileSize && tiles[y][x].Image.Bounds().Size().Y != tileSize { panic(WrongSizeError{ExpectedSize: tileSize, ActualSize: tiles[y][x].Image.Bounds().Size(), X: x, Y: y}) } tiles[y][x].Dirty = false } } } func Save() { for y := range tiles { for x := range tiles[y] { if tiles[y][x].Dirty { filename := fmt.Sprintf("%d-%d.png", x, y) file, err := os.OpenFile(filename, os.O_WRONLY, 0644) if err != nil { panic(err) } defer file.Close() if err = png.Encode(file, tiles[y][x].Image); err != nil { panic(err) } tiles[y][x].Dirty = false } } } } func GetTile(x int, y int) (*Tile, error) { if x >= len(tiles) || y >= len(tiles) { return nil, errors.New("tile coordinates out of range") } return &tiles[y][x], nil } func SetPixel(tx int, ty int, x int, y int, c color.Color) error { if ty >= len(tiles) || tx >= len(tiles[y]) { return errors.New("tile coordinates out of range") } if x >= tiles[y][x].Image.Bounds().Size().X || y >= tiles[y][x].Image.Bounds().Size().Y { return errors.New("pixel coordinates out of range") } tiles[y][x].Image.Set(x, y, c) tiles[y][x].Dirty = true return nil }