package conv import ( "fmt" "image/color" "image/png" "log" "os" "github.com/faiface/pixel" "ur.gs/ordoor/internal/data" ) var transparent = color.RGBA{0, 0, 0, 0} // Important conversions: // // * Width & height now stored using int // * Colour data is now 32-bit rather than using a palette type Sprite struct { Width int Height int Pic *pixel.PictureData Spr *pixel.Sprite } type Object struct { Name string Sprites []Sprite } func maxWidth(obj *data.Object) int { out := 0 for _, spr := range obj.Sprites { width := int(spr.Width) if width > out { out = width } } return out } func fullHeight(obj *data.Object) int { out := 0 for _, spr := range obj.Sprites { out = out + int(spr.Height) } return out } func ConvertObjects(objects []*data.Object) (map[string]*Object, *pixel.PictureData) { // This needs to be the maxWidth of all the objects, added together maxX := 0 for _, obj := range objects { maxX = maxX + maxWidth(obj) } // This needs to be the largest fullHeight of all the objects maxY := 0 for _, obj := range objects { height := fullHeight(obj) if height > maxY { maxY = height } } xOffset := 0 spritesheet := pixel.MakePictureData(pixel.R(0.0, 0.0, float64(maxX), float64(maxY))) out := make(map[string]*Object) for _, rawObj := range objects { log.Println("xOffset:", xOffset) cObj := ConvertObjectWithSpritesheet(rawObj, rawObj.Name, spritesheet, xOffset) xOffset = xOffset + maxWidth(rawObj) out[cObj.Name] = cObj } f, _ := os.Create("spritesheet.png") img := spritesheet.Image() png.Encode(f, img) f.Close() return out, spritesheet } func ConvertObjectWithSpritesheet(rawObj *data.Object, name string, pic *pixel.PictureData, xOffset int) *Object { out := &Object{ Name: name, Sprites: make([]Sprite, len(rawObj.Sprites)), } // We store the sprites vertically in the provided pic yOffset := 0 log.Printf("Converting %v: xOffset = %v", name, xOffset) for i, rawSpr := range rawObj.Sprites { spr := spriteToPic(name, i, rawSpr, pic, xOffset, yOffset) log.Printf(" %#v", spr.Frame()) out.Sprites[i] = Sprite{ Width: int(rawSpr.Width), Height: int(rawSpr.Height), Pic: pic, Spr: spr, } yOffset = yOffset + int(rawSpr.Height) } return out } func ConvertObject(rawObj *data.Object, name string) *Object { out := &Object{ Name: name, Sprites: make([]Sprite, len(rawObj.Sprites)), } for i, rawSpr := range rawObj.Sprites { pic := pixel.MakePictureData( pixel.R( float64(0), float64(0), float64(rawSpr.Width), float64(rawSpr.Height), ), ) spr := spriteToPic(name, i, rawSpr, pic, 0, 0) out.Sprites[i] = Sprite{ Width: int(rawSpr.Width), Height: int(rawSpr.Height), Pic: pic, Spr: spr, } } return out } func spriteToPic(name string, idx int, sprite *data.Sprite, pic *pixel.PictureData, xOffset, yOffset int) *pixel.Sprite { width := int(sprite.Width) height := int(sprite.Height) //log.Printf("%v %v: width=%v height=%v", name, idx, width, height) for y := 0; y < height; y++ { for x := 0; x < width; x++ { b := sprite.Data[y*width+x] // Update the picture if err := setPaletteColor(pic, x+xOffset, y+yOffset, b); err != nil { //log.Printf("%s %d: %d,%d: %v", name, idx, x, y, err) } } } // FIXME: I really don't get this fetish for starting at the bottom-left bounds := pixel.R( float64(xOffset), float64(yOffset), float64(xOffset+width), float64(yOffset+height), ) //bounds.Min = bounds.Min.ScaledXY(pixel.Vec{1.0, -1.0}) //bounds.Max = bounds.Max.ScaledXY(pixel.Vec{1.0, -1.0}) return pixel.NewSprite(pic, bounds) } func setPaletteColor(pic *pixel.PictureData, x int, y int, colorIdx byte) error { vec := pixel.V(float64(x), float64(y)) idx := pic.Index(vec) if idx > len(pic.Pix)-1 { return fmt.Errorf("Got index %v which exceeds bounds", idx) } r, g, b, a := data.ColorPalette[int(colorIdx)].RGBA() color := color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)} pic.Pix[idx] = color return nil }