finish dc6 extractor, simplify decoder and palette code
This commit is contained in:
parent
0d8210e26c
commit
52b2bbd9a6
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
package math
|
||||
|
||||
type Color3b struct {
|
||||
R, G, B byte
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user