lazarus/formats/dc6/dc6.go

130 lines
2.8 KiB
Go
Raw Normal View History

2018-12-14 04:03:47 +00:00
package dc6
import (
"encoding/binary"
"io"
2018-12-31 17:59:58 +00:00
"github.com/FooSoft/lazarus/math"
"github.com/FooSoft/lazarus/streaming"
)
type fileHeader struct {
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 int32
OffsetY int32
_ uint32 // unused: allocSize
_ uint32 // unused: nextBlock
Length uint32
}
type Direction struct {
Frames []Frame
}
type Frame struct {
2018-12-31 17:59:58 +00:00
Size math.Vec2i
Offset math.Vec2i
Data []byte
}
2019-01-01 18:30:35 +00:00
type Dc6Animation struct {
Directions []Direction
}
2019-01-01 18:30:35 +00:00
func NewFromReader(reader io.ReadSeeker) (*Dc6Animation, error) {
sprite := new(Dc6Animation)
var fileHead fileHeader
if err := binary.Read(reader, binary.LittleEndian, &fileHead); err != nil {
return nil, err
}
var frameOffsets []uint32
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
}
frameOffsets = append(frameOffsets, frameOffset)
}
sprite.Directions = make([]Direction, fileHead.DirCount)
for i, frameOffset := range frameOffsets {
var frameHead frameHeader
if _, err := reader.Seek(int64(frameOffset), io.SeekStart); err != nil {
return nil, err
}
if err := binary.Read(reader, binary.LittleEndian, &frameHead); err != nil {
return nil, err
}
data := make([]byte, frameHead.Width*frameHead.Height)
writer := streaming.NewWriter(data)
if err := extractFrame(reader, writer, frameHead); err != nil {
2018-12-17 03:30:53 +00:00
return nil, err
}
2018-12-31 17:59:58 +00:00
var (
size = math.Vec2i{X: int(frameHead.Width), Y: int(frameHead.Height)}
offset = math.Vec2i{X: int(frameHead.OffsetX), Y: int(frameHead.OffsetY)}
frame = Frame{size, offset, data}
direction = &sprite.Directions[i/int(fileHead.FramesPerDir)]
)
direction.Frames = append(direction.Frames, frame)
}
return sprite, nil
}
func extractFrame(reader io.ReadSeeker, writer io.WriteSeeker, header frameHeader) error {
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 {
2018-12-17 03:30:53 +00:00
return err
}
if chunk&0x80 > 0 {
if skipLength := uint32(chunk & 0x7f); skipLength > 0 {
x += skipLength
} else {
x = 0
y++
}
2018-12-17 03:30:53 +00:00
} 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 {
2018-12-17 03:30:53 +00:00
return err
}
if _, err := io.CopyN(writer, reader, int64(chunk)); err != nil {
2018-12-17 03:30:53 +00:00
return err
}
readOffset += uint32(chunk)
x += uint32(chunk)
2018-12-17 03:30:53 +00:00
}
}
return nil
}