diff --git a/formats/dat/dat.go b/formats/dat/dat.go index e560116..20c2c5d 100644 --- a/formats/dat/dat.go +++ b/formats/dat/dat.go @@ -2,20 +2,30 @@ package dat import ( "encoding/binary" + imageColor "image/color" "io" - - "github.com/FooSoft/lazarus/math" ) type Palette struct { - Colors [256]math.Color3b + Colors [256]imageColor.NRGBA } -func NewFromReader(r io.Reader) (*Palette, error) { - p := new(Palette) - if err := binary.Read(r, binary.LittleEndian, p); err != nil { +type color struct { + B byte + G byte + R byte +} + +func NewFromReader(reader io.Reader) (*Palette, error) { + var colors [256]color + if err := binary.Read(reader, binary.LittleEndian, &colors); err != nil { return nil, err } - return p, nil + palette := new(Palette) + for i, color := range colors { + palette.Colors[i] = imageColor.NRGBA{color.R, color.G, color.B, 0xff} + } + + return palette, nil } diff --git a/formats/dc6/dc6.go b/formats/dc6/dc6.go index 23f607b..2b2f132 100644 --- a/formats/dc6/dc6.go +++ b/formats/dc6/dc6.go @@ -8,23 +8,23 @@ import ( ) type fileHeader struct { - Version uint32 - UnusedFlags uint32 - UnusedFormat uint32 - UnusedSkipColor uint32 - DirCount uint32 - FramesPerDir uint32 + Version uint32 + _ uint32 // unused: flags + _ uint32 // unused: format + _ uint32 // unused: skipColor + DirCount uint32 + FramesPerDir uint32 } type frameHeader struct { - Flip uint32 - Width uint32 - Height uint32 - OffsetX uint32 - OffsetY uint32 - UnusedAllocSize uint32 - UnusedNextBlock uint32 - Length uint32 + Flip uint32 + Width uint32 + Height uint32 + OffsetX uint32 + OffsetY uint32 + _ uint32 // unused: allocSize + _ uint32 // unused: nextBlock + Length uint32 } type Direction struct { @@ -51,10 +51,8 @@ func NewFromReader(reader io.ReadSeeker) (*Sprite, error) { return nil, err } - frameCount := int(fileHead.DirCount * fileHead.FramesPerDir) - var frameOffsets []uint32 - for i := 0; i < frameCount; i++ { + for i := uint32(0); i < fileHead.DirCount*fileHead.FramesPerDir; i++ { var frameOffset uint32 if err := binary.Read(reader, binary.LittleEndian, &frameOffset); err != nil { return nil, err @@ -65,9 +63,9 @@ func NewFromReader(reader io.ReadSeeker) (*Sprite, error) { sprite.Directions = make([]Direction, fileHead.FramesPerDir) - for i := 0; i < frameCount; i++ { + for i, frameOffset := range frameOffsets { var frameHead frameHeader - if _, err := reader.Seek(int64(frameOffsets[i]), io.SeekStart); err != nil { + if _, err := reader.Seek(int64(frameOffset), io.SeekStart); err != nil { return nil, err } @@ -97,33 +95,36 @@ func NewFromReader(reader io.ReadSeeker) (*Sprite, error) { } func extractFrame(reader io.ReadSeeker, writer io.WriteSeeker, header frameHeader) error { - var ( - x uint32 - y = header.Height - 1 - ) - - var offset uint32 - for offset < header.Length { - var chunkSize byte - if err := binary.Read(reader, binary.LittleEndian, &chunkSize); err != nil { + var x, y uint32 + for readOffset := uint32(0); readOffset < header.Length; readOffset++ { + var chunk byte + if err := binary.Read(reader, binary.LittleEndian, &chunk); err != nil { return err } - if chunkSize == 0x80 { - x = 0 - y-- - } else if (chunkSize & 0x80) != 0 { - x += uint32(chunkSize & 0x7f) + if chunk&0x80 > 0 { + if skipLength := uint32(chunk & 0x7f); skipLength > 0 { + x += skipLength + } else { + x = 0 + y++ + } + } else { - if _, err := writer.Seek(int64(header.Width*y+x), io.SeekStart); err != nil { + writeOffset := int64(header.Width*(header.Height-y-1) + x) + if header.Flip != 0 { + writeOffset = int64(header.Width*y + x) + } + + if _, err := writer.Seek(writeOffset, io.SeekStart); err != nil { return err } - if _, err := io.CopyN(writer, reader, int64(chunkSize)); err != nil { + if _, err := io.CopyN(writer, reader, int64(chunk)); err != nil { return err } - offset += uint32(chunkSize) - x += uint32(chunkSize) + readOffset += uint32(chunk) + x += uint32(chunk) } } diff --git a/math/color.go b/math/color.go deleted file mode 100644 index 5810bba..0000000 --- a/math/color.go +++ /dev/null @@ -1,5 +0,0 @@ -package math - -type Color3b struct { - R, G, B byte -} diff --git a/streaming/bytewriter.go b/streaming/bytewriter.go index 6e04d43..1ef4da2 100644 --- a/streaming/bytewriter.go +++ b/streaming/bytewriter.go @@ -52,5 +52,6 @@ func (w *writer) Seek(offset int64, whence int) (int64, error) { return int64(w.offset), errors.New("cannot seek past end of buffer") } + w.offset = result return int64(w.offset), nil } diff --git a/tools/dc6/dc6.go b/tools/dc6/dc6.go index efa2308..df44d1b 100644 --- a/tools/dc6/dc6.go +++ b/tools/dc6/dc6.go @@ -3,8 +3,11 @@ package main import ( "flag" "fmt" + "image" + "image/png" "os" "path" + "path/filepath" "github.com/FooSoft/lazarus/formats/dat" "github.com/FooSoft/lazarus/formats/dc6" @@ -28,40 +31,64 @@ func loadSprite(path string) (*dc6.Sprite, error) { return dc6.NewFromReader(fp) } -func extractSprite(palettePath, spritePath, targetDir string) error { - _, err := loadPalette(palettePath) +func extractSprite(spritePath string, palette *dat.Palette, targetDir string) error { + sprite, err := loadSprite(spritePath) if err != nil { return err } - _, err = loadSprite(spritePath) - if err != nil { - return err + for di, direction := range sprite.Directions { + for fi, frame := range direction.Frames { + img := image.NewNRGBA(image.Rect(0, 0, frame.Width, frame.Height)) + for y := 0; y < frame.Height; y++ { + for x := 0; x < frame.Width; x++ { + img.Set(x, y, palette.Colors[frame.Data[y*frame.Width+x]]) + } + } + + basePath := filepath.Base(spritePath) + targetPath := fmt.Sprintf("%s_%d_%d.png", filepath.Join(targetDir, basePath), di, fi) + + fp, err := os.Create(targetPath) + if err != nil { + return err + } + defer fp.Close() + + if err := png.Encode(fp, img); err != nil { + return err + } + } } return nil } func main() { - var ( - targetDir = flag.String("target", ".", "target directory") - ) - + targetDir := flag.String("target", ".", "target directory") flag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options] palette_file dc6_file\n", path.Base(os.Args[0])) + fmt.Fprintf(os.Stderr, "Usage: %s [options] palette_file [dc6_files]\n", path.Base(os.Args[0])) fmt.Fprintf(os.Stderr, "Parameters:\n\n") flag.PrintDefaults() } flag.Parse() - if flag.NArg() < 2 { + if flag.NArg() < 1 { flag.Usage() os.Exit(2) } - if err := extractSprite(flag.Arg(0), flag.Arg(1), *targetDir); err != nil { + palette, err := loadPalette(flag.Arg(0)) + if err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } + + for i := 1; i < flag.NArg(); i++ { + if err := extractSprite(flag.Arg(1), palette, *targetDir); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + } }