finish dc6 extractor, simplify decoder and palette code

This commit is contained in:
Alex Yatskov 2018-12-17 15:09:30 -08:00
parent 0d8210e26c
commit 52b2bbd9a6
5 changed files with 95 additions and 61 deletions

View File

@ -2,20 +2,30 @@ package dat
import ( import (
"encoding/binary" "encoding/binary"
imageColor "image/color"
"io" "io"
"github.com/FooSoft/lazarus/math"
) )
type Palette struct { type Palette struct {
Colors [256]math.Color3b Colors [256]imageColor.NRGBA
} }
func NewFromReader(r io.Reader) (*Palette, error) { type color struct {
p := new(Palette) B byte
if err := binary.Read(r, binary.LittleEndian, p); err != nil { 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 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
} }

View File

@ -9,9 +9,9 @@ import (
type fileHeader struct { type fileHeader struct {
Version uint32 Version uint32
UnusedFlags uint32 _ uint32 // unused: flags
UnusedFormat uint32 _ uint32 // unused: format
UnusedSkipColor uint32 _ uint32 // unused: skipColor
DirCount uint32 DirCount uint32
FramesPerDir uint32 FramesPerDir uint32
} }
@ -22,8 +22,8 @@ type frameHeader struct {
Height uint32 Height uint32
OffsetX uint32 OffsetX uint32
OffsetY uint32 OffsetY uint32
UnusedAllocSize uint32 _ uint32 // unused: allocSize
UnusedNextBlock uint32 _ uint32 // unused: nextBlock
Length uint32 Length uint32
} }
@ -51,10 +51,8 @@ func NewFromReader(reader io.ReadSeeker) (*Sprite, error) {
return nil, err return nil, err
} }
frameCount := int(fileHead.DirCount * fileHead.FramesPerDir)
var frameOffsets []uint32 var frameOffsets []uint32
for i := 0; i < frameCount; i++ { for i := uint32(0); i < fileHead.DirCount*fileHead.FramesPerDir; i++ {
var frameOffset uint32 var frameOffset uint32
if err := binary.Read(reader, binary.LittleEndian, &frameOffset); err != nil { if err := binary.Read(reader, binary.LittleEndian, &frameOffset); err != nil {
return nil, err return nil, err
@ -65,9 +63,9 @@ func NewFromReader(reader io.ReadSeeker) (*Sprite, error) {
sprite.Directions = make([]Direction, fileHead.FramesPerDir) sprite.Directions = make([]Direction, fileHead.FramesPerDir)
for i := 0; i < frameCount; i++ { for i, frameOffset := range frameOffsets {
var frameHead frameHeader 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 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 { func extractFrame(reader io.ReadSeeker, writer io.WriteSeeker, header frameHeader) error {
var ( var x, y uint32
x uint32 for readOffset := uint32(0); readOffset < header.Length; readOffset++ {
y = header.Height - 1 var chunk byte
) if err := binary.Read(reader, binary.LittleEndian, &chunk); err != nil {
var offset uint32
for offset < header.Length {
var chunkSize byte
if err := binary.Read(reader, binary.LittleEndian, &chunkSize); err != nil {
return err return err
} }
if chunkSize == 0x80 { if chunk&0x80 > 0 {
x = 0 if skipLength := uint32(chunk & 0x7f); skipLength > 0 {
y-- x += skipLength
} else if (chunkSize & 0x80) != 0 {
x += uint32(chunkSize & 0x7f)
} else { } else {
if _, err := writer.Seek(int64(header.Width*y+x), io.SeekStart); err != nil { x = 0
y++
}
} else {
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 return err
} }
if _, err := io.CopyN(writer, reader, int64(chunkSize)); err != nil { if _, err := io.CopyN(writer, reader, int64(chunk)); err != nil {
return err return err
} }
offset += uint32(chunkSize) readOffset += uint32(chunk)
x += uint32(chunkSize) x += uint32(chunk)
} }
} }

View File

@ -1,5 +0,0 @@
package math
type Color3b struct {
R, G, B byte
}

View File

@ -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") return int64(w.offset), errors.New("cannot seek past end of buffer")
} }
w.offset = result
return int64(w.offset), nil return int64(w.offset), nil
} }

View File

@ -3,8 +3,11 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"image"
"image/png"
"os" "os"
"path" "path"
"path/filepath"
"github.com/FooSoft/lazarus/formats/dat" "github.com/FooSoft/lazarus/formats/dat"
"github.com/FooSoft/lazarus/formats/dc6" "github.com/FooSoft/lazarus/formats/dc6"
@ -28,40 +31,64 @@ func loadSprite(path string) (*dc6.Sprite, error) {
return dc6.NewFromReader(fp) return dc6.NewFromReader(fp)
} }
func extractSprite(palettePath, spritePath, targetDir string) error { func extractSprite(spritePath string, palette *dat.Palette, targetDir string) error {
_, err := loadPalette(palettePath) sprite, err := loadSprite(spritePath)
if err != nil { if err != nil {
return err return err
} }
_, err = loadSprite(spritePath) 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 { if err != nil {
return err return err
} }
defer fp.Close()
if err := png.Encode(fp, img); err != nil {
return err
}
}
}
return nil return nil
} }
func main() { func main() {
var ( targetDir := flag.String("target", ".", "target directory")
targetDir = flag.String("target", ".", "target directory")
)
flag.Usage = func() { 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") fmt.Fprintf(os.Stderr, "Parameters:\n\n")
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.Parse() flag.Parse()
if flag.NArg() < 2 { if flag.NArg() < 1 {
flag.Usage() flag.Usage()
os.Exit(2) 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) fmt.Fprintln(os.Stderr, err)
os.Exit(1) 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)
}
}
} }