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 (
"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
}

View File

@ -9,9 +9,9 @@ import (
type fileHeader struct {
Version uint32
UnusedFlags uint32
UnusedFormat uint32
UnusedSkipColor uint32
_ uint32 // unused: flags
_ uint32 // unused: format
_ uint32 // unused: skipColor
DirCount uint32
FramesPerDir uint32
}
@ -22,8 +22,8 @@ type frameHeader struct {
Height uint32
OffsetX uint32
OffsetY uint32
UnusedAllocSize uint32
UnusedNextBlock uint32
_ uint32 // unused: allocSize
_ uint32 // unused: nextBlock
Length uint32
}
@ -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 {
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
}
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)
}
}

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")
}
w.offset = result
return int64(w.offset), nil
}

View File

@ -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)
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)
}
}
}