OpenDiablo2/d2data/d2dc6/dc6.go

137 lines
3.4 KiB
Go

package d2dc6
import (
"encoding/binary"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2datadict"
"github.com/go-restruct/restruct"
)
type DC6File struct {
// Header
Version int32 `struct:"int32"`
Flags uint32 `struct:"uint32"`
Encoding uint32 `struct:"uint32"`
Termination []byte `struct:"[4]byte"`
Directions uint32 `struct:"uint32"`
FramesPerDirection uint32 `struct:"uint32"`
FramePointers []uint32 `struct:"[]uint32,size=Directions*FramesPerDirection"`
Frames []*DC6Frame `struct-size:"Directions*FramesPerDirection"`
valid bool
}
type DC6Header struct {
Version int32 `struct:"int32"`
Flags uint32 `struct:"uint32"`
Encoding uint32 `struct:"uint32"`
Termination []byte `struct:"[4]byte"`
Directions int32 `struct:"int32"`
FramesPerDirection int32 `struct:"int32"`
}
type DC6FrameHeader struct {
Flipped int32 `struct:"int32"`
Width int32 `struct:"int32"`
Height int32 `struct:"int32"`
OffsetX int32 `struct:"int32"`
OffsetY int32 `struct:"int32"`
Unknown uint32 `struct:"uint32"`
NextBlock uint32 `struct:"uint32"`
Length uint32 `struct:"uint32"`
}
type DC6Frame struct {
Flipped uint32 `struct:"uint32"`
Width uint32 `struct:"uint32"`
Height uint32 `struct:"uint32"`
OffsetX int32 `struct:"int32"`
OffsetY int32 `struct:"int32"`
Unknown uint32 `struct:"uint32"`
NextBlock uint32 `struct:"uint32"`
Length uint32 `struct:"uint32,sizeof=FrameData"`
FrameData []byte
Terminator []byte `struct:"[3]byte"`
colorData []byte
palette d2datadict.PaletteRec
valid bool
}
func (frame *DC6Frame) ColorData() []byte {
if frame.colorData == nil {
frame.completeLoad()
}
return frame.colorData
}
func (frame *DC6Frame) completeLoad() {
frame.valid = true
indexData := make([]int16, frame.Width*frame.Height)
for fi := range indexData {
indexData[fi] = -1
}
x := uint32(0)
y := frame.Height - 1
dataPointer := 0
for {
b := frame.FrameData[dataPointer]
dataPointer++
if b == 0x80 {
if y == 0 {
break
}
y--
x = 0
} else if (b & 0x80) > 0 {
transparentPixels := b & 0x7F
for ti := byte(0); ti < transparentPixels; ti++ {
indexData[x+(y*frame.Width)+uint32(ti)] = -1
}
x += uint32(transparentPixels)
} else {
for bi := 0; bi < int(b); bi++ {
indexData[x+(y*frame.Width)+uint32(bi)] = int16(frame.FrameData[dataPointer])
dataPointer++
}
x += uint32(b)
}
}
// Probably don't need this data again
frame.FrameData = nil
frame.colorData = make([]byte, int(frame.Width*frame.Height)*4)
for i := uint32(0); i < frame.Width*frame.Height; i++ {
if indexData[i] < 1 { // TODO: Is this == -1 or < 1?
continue
}
frame.colorData[i*4] = frame.palette.Colors[indexData[i]].R
frame.colorData[(i*4)+1] = frame.palette.Colors[indexData[i]].G
frame.colorData[(i*4)+2] = frame.palette.Colors[indexData[i]].B
frame.colorData[(i*4)+3] = 0xFF
}
}
// LoadDC6 uses restruct to read the binary dc6 data into structs then parses image data from the frame data.
func LoadDC6(data []byte, palette d2datadict.PaletteRec) (DC6File, error) {
result := DC6File{valid: true}
restruct.EnableExprBeta()
err := restruct.Unpack(data, binary.LittleEndian, &result)
if err != nil {
result.valid = false
log.Printf("failed to read dc6: %v", err)
}
for _, frame := range result.Frames {
frame.palette = palette
}
return result, err
}