2020-01-26 00:39:13 -05:00
|
|
|
package d2dc6
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"log"
|
|
|
|
|
2020-01-31 23:18:11 -05:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
|
2020-01-26 00:39:13 -05:00
|
|
|
"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
|
|
|
|
}
|