finish dc6 extractor, simplify decoder and palette code
This commit is contained in:
parent
0d8210e26c
commit
52b2bbd9a6
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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")
|
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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
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)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user