mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-10-01 15:46:17 -04:00
Decouple bitmuncher (#495)
* adding comments to d2interface for linter * moved d2render renderer interfaces and types into d2interface * fixed most lint errors for monstats loader * decouple bitmuncher to interface
This commit is contained in:
parent
06202a2ddf
commit
691368cba7
@ -1,66 +1,117 @@
|
|||||||
package d2common
|
package d2common
|
||||||
|
|
||||||
|
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
|
|
||||||
|
// BitMuncher is used for parsing files that are not byte-aligned such as the DCC files.
|
||||||
type BitMuncher struct {
|
type BitMuncher struct {
|
||||||
data []byte
|
data []byte
|
||||||
Offset int
|
offset int
|
||||||
BitsRead int
|
bitsRead int
|
||||||
}
|
}
|
||||||
|
|
||||||
func CreateBitMuncher(data []byte, offset int) *BitMuncher {
|
const (
|
||||||
return &BitMuncher{
|
twosComplimentNegativeOne = 4294967295
|
||||||
data: data,
|
byteLen = 8
|
||||||
Offset: offset,
|
oneBit = 0x01
|
||||||
BitsRead: 0,
|
fourBytes = byteLen * 4
|
||||||
}
|
)
|
||||||
|
|
||||||
|
// CreateBitMuncher Creates a BitMuncher
|
||||||
|
func CreateBitMuncher(data []byte, offset int) d2interface.BitMuncher {
|
||||||
|
return (&BitMuncher{}).Init(data, offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
func CopyBitMuncher(source *BitMuncher) *BitMuncher {
|
// CopyBitMuncher Creates a copy of the source BitMuncher
|
||||||
return &BitMuncher{
|
func CopyBitMuncher(source d2interface.BitMuncher) d2interface.BitMuncher {
|
||||||
source.data,
|
return source.Copy()
|
||||||
source.Offset,
|
|
||||||
0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Init initializes the BitMuncher with data and an offset
|
||||||
|
func (v *BitMuncher) Init(data []byte, offset int) d2interface.BitMuncher {
|
||||||
|
v.data = data
|
||||||
|
v.offset = offset
|
||||||
|
v.bitsRead = 0
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy returns a copy of a BitMuncher
|
||||||
|
func (v BitMuncher) Copy() d2interface.BitMuncher {
|
||||||
|
v.bitsRead = 0
|
||||||
|
return &v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Offset returns the offset of the BitMuncher
|
||||||
|
func (v *BitMuncher) Offset() int {
|
||||||
|
return v.offset
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetOffset sets the offset of the BitMuncher
|
||||||
|
func (v *BitMuncher) SetOffset(n int) {
|
||||||
|
v.offset = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// BitsRead returns the number of bits the BitMuncher has read
|
||||||
|
func (v *BitMuncher) BitsRead() int {
|
||||||
|
return v.bitsRead
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBitsRead sets the number of bits the BitMuncher has read
|
||||||
|
func (v *BitMuncher) SetBitsRead(n int) {
|
||||||
|
v.bitsRead = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBit reads a bit and returns it as uint32
|
||||||
func (v *BitMuncher) GetBit() uint32 {
|
func (v *BitMuncher) GetBit() uint32 {
|
||||||
result := uint32(v.data[v.Offset/8]>>uint(v.Offset%8)) & 0x01
|
result := uint32(v.data[v.offset/byteLen]>>uint(v.offset%byteLen)) & oneBit
|
||||||
v.Offset++
|
v.offset++
|
||||||
v.BitsRead++
|
v.bitsRead++
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SkipBits skips bits, incrementing the offset and bits read
|
||||||
func (v *BitMuncher) SkipBits(bits int) {
|
func (v *BitMuncher) SkipBits(bits int) {
|
||||||
v.Offset += bits
|
v.offset += bits
|
||||||
v.BitsRead += bits
|
v.bitsRead += bits
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetByte reads a byte from data
|
||||||
func (v *BitMuncher) GetByte() byte {
|
func (v *BitMuncher) GetByte() byte {
|
||||||
return byte(v.GetBits(8))
|
return byte(v.GetBits(byteLen))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetInt32 reads an int32 from data
|
||||||
func (v *BitMuncher) GetInt32() int32 {
|
func (v *BitMuncher) GetInt32() int32 {
|
||||||
return v.MakeSigned(v.GetBits(32), 32)
|
return v.MakeSigned(v.GetBits(fourBytes), fourBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUInt32 reads an unsigned uint32 from data
|
||||||
func (v *BitMuncher) GetUInt32() uint32 {
|
func (v *BitMuncher) GetUInt32() uint32 {
|
||||||
return v.GetBits(32)
|
return v.GetBits(fourBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetBits given a number of bits to read, reads that number of
|
||||||
|
// bits and retruns as a uint32
|
||||||
func (v *BitMuncher) GetBits(bits int) uint32 {
|
func (v *BitMuncher) GetBits(bits int) uint32 {
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
result := uint32(0)
|
result := uint32(0)
|
||||||
for i := 0; i < bits; i++ {
|
for i := 0; i < bits; i++ {
|
||||||
result |= v.GetBit() << uint(i)
|
result |= v.GetBit() << uint(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSignedBits Given a number of bits, reads that many bits and returns as int
|
||||||
func (v *BitMuncher) GetSignedBits(bits int) int {
|
func (v *BitMuncher) GetSignedBits(bits int) int {
|
||||||
return int(v.MakeSigned(v.GetBits(bits), bits))
|
return int(v.MakeSigned(v.GetBits(bits), bits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeSigned converts a uint32 value into an int32
|
||||||
func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
|
func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
|
||||||
if bits == 0 {
|
if bits == 0 {
|
||||||
return 0
|
return 0
|
||||||
@ -73,13 +124,17 @@ func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
|
|||||||
if (value & (1 << uint(bits-1))) == 0 {
|
if (value & (1 << uint(bits-1))) == 0 {
|
||||||
return int32(value)
|
return int32(value)
|
||||||
}
|
}
|
||||||
// We need to extend the signed bit out so that the negative value representation still works with the 2s compliment rule.
|
|
||||||
result := uint32(4294967295)
|
// We need to extend the signed bit out so that the negative value
|
||||||
|
// representation still works with the 2s compliment rule.
|
||||||
|
result := uint32(twosComplimentNegativeOne)
|
||||||
|
|
||||||
for i := byte(0); i < byte(bits); i++ {
|
for i := byte(0); i < byte(bits); i++ {
|
||||||
if ((value >> uint(i)) & 1) == 0 {
|
if ((value >> uint(i)) & 1) == 0 {
|
||||||
result -= uint32(1 << uint(i))
|
result -= uint32(1 << uint(i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force casting to a signed value
|
// Force casting to a signed value
|
||||||
return int32(result)
|
return int32(result)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@ package d2dcc
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ type DCCDirection struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateDCCDirection creates an instance of a DCCDirection.
|
// CreateDCCDirection creates an instance of a DCCDirection.
|
||||||
func CreateDCCDirection(bm *d2common.BitMuncher, file *DCC) *DCCDirection { //nolint:funlen // Can't reduce
|
func CreateDCCDirection(bm d2interface.BitMuncher, file *DCC) *DCCDirection { //nolint:funlen // Can't reduce
|
||||||
var crazyBitTable = []byte{0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32}
|
var crazyBitTable = []byte{0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 26, 28, 30, 32}
|
||||||
|
|
||||||
result := &DCCDirection{}
|
result := &DCCDirection{}
|
||||||
@ -130,29 +132,29 @@ func CreateDCCDirection(bm *d2common.BitMuncher, file *DCC) *DCCDirection { //no
|
|||||||
result.PixelBuffer = nil
|
result.PixelBuffer = nil
|
||||||
|
|
||||||
// Verify that everything we expected to read was actually read (sanity check)...
|
// Verify that everything we expected to read was actually read (sanity check)...
|
||||||
if equalCellsBitstream.BitsRead != result.EqualCellsBitstreamSize {
|
if equalCellsBitstream.BitsRead() != result.EqualCellsBitstreamSize {
|
||||||
log.Panic("Did not read the correct number of bits!")
|
log.Panic("Did not read the correct number of bits!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if pixelMaskBitstream.BitsRead != result.PixelMaskBitstreamSize {
|
if pixelMaskBitstream.BitsRead() != result.PixelMaskBitstreamSize {
|
||||||
log.Panic("Did not read the correct number of bits!")
|
log.Panic("Did not read the correct number of bits!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if encodingTypeBitsream.BitsRead != result.EncodingTypeBitsreamSize {
|
if encodingTypeBitsream.BitsRead() != result.EncodingTypeBitsreamSize {
|
||||||
log.Panic("Did not read the correct number of bits!")
|
log.Panic("Did not read the correct number of bits!")
|
||||||
}
|
}
|
||||||
|
|
||||||
if rawPixelCodesBitstream.BitsRead != result.RawPixelCodesBitstreamSize {
|
if rawPixelCodesBitstream.BitsRead() != result.RawPixelCodesBitstreamSize {
|
||||||
log.Panic("Did not read the correct number of bits!")
|
log.Panic("Did not read the correct number of bits!")
|
||||||
}
|
}
|
||||||
|
|
||||||
bm.SkipBits(pixelCodeandDisplacement.BitsRead)
|
bm.SkipBits(pixelCodeandDisplacement.BitsRead())
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
//nolint:gocognit nolint:gocyclo // Can't reduce
|
//nolint:gocognit nolint:gocyclo // Can't reduce
|
||||||
func (v *DCCDirection) generateFrames(pcd *d2common.BitMuncher) {
|
func (v *DCCDirection) generateFrames(pcd d2interface.BitMuncher) {
|
||||||
pbIdx := 0
|
pbIdx := 0
|
||||||
|
|
||||||
for _, cell := range v.Cells {
|
for _, cell := range v.Cells {
|
||||||
@ -255,7 +257,7 @@ func (v *DCCDirection) generateFrames(pcd *d2common.BitMuncher) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//nolint:funlen nolint:gocognit // can't reduce
|
//nolint:funlen nolint:gocognit // can't reduce
|
||||||
func (v *DCCDirection) fillPixelBuffer(pcd, ec, pm, et, rp *d2common.BitMuncher) {
|
func (v *DCCDirection) fillPixelBuffer(pcd, ec, pm, et, rp d2interface.BitMuncher) {
|
||||||
var pixelMaskLookup = []int{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}
|
var pixelMaskLookup = []int{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}
|
||||||
|
|
||||||
lastPixel := uint32(0)
|
lastPixel := uint32(0)
|
||||||
|
@ -3,6 +3,8 @@ package d2dcc
|
|||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ type DCCDirectionFrame struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateDCCDirectionFrame Creates a DCCDirectionFrame for a DCC.
|
// CreateDCCDirectionFrame Creates a DCCDirectionFrame for a DCC.
|
||||||
func CreateDCCDirectionFrame(bits *d2common.BitMuncher, direction *DCCDirection) *DCCDirectionFrame {
|
func CreateDCCDirectionFrame(bits d2interface.BitMuncher, direction *DCCDirection) *DCCDirectionFrame {
|
||||||
result := &DCCDirectionFrame{}
|
result := &DCCDirectionFrame{}
|
||||||
|
|
||||||
bits.GetBits(direction.Variable0Bits) // Variable0
|
bits.GetBits(direction.Variable0Bits) // Variable0
|
||||||
|
18
d2common/d2interface/bitmuncher.go
Normal file
18
d2common/d2interface/bitmuncher.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package d2interface
|
||||||
|
|
||||||
|
type BitMuncher interface {
|
||||||
|
Init(data []byte, offset int) BitMuncher
|
||||||
|
Copy() BitMuncher
|
||||||
|
Offset() int
|
||||||
|
SetOffset(int)
|
||||||
|
BitsRead() int
|
||||||
|
SetBitsRead(int)
|
||||||
|
GetBit() uint32
|
||||||
|
SkipBits(bits int)
|
||||||
|
GetByte() byte
|
||||||
|
GetInt32() int32
|
||||||
|
GetUInt32() uint32
|
||||||
|
GetBits(bits int) uint32
|
||||||
|
GetSignedBits(bits int) int
|
||||||
|
MakeSigned(value uint32, bits int) int32
|
||||||
|
}
|
8
d2common/d2interface/bitstream.go
Normal file
8
d2common/d2interface/bitstream.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package d2interface
|
||||||
|
|
||||||
|
type BitStream interface {
|
||||||
|
ReadBits(bitCount int) int
|
||||||
|
PeekByte() int
|
||||||
|
EnsureBits(bitCount int) bool
|
||||||
|
WasteBits(bitCount int)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user