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:
dk 2020-06-29 17:21:09 -07:00 committed by GitHub
parent 06202a2ddf
commit 691368cba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 118 additions and 33 deletions

View File

@ -1,66 +1,117 @@
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 {
data []byte
Offset int
BitsRead int
offset int
bitsRead int
}
func CreateBitMuncher(data []byte, offset int) *BitMuncher {
return &BitMuncher{
data: data,
Offset: offset,
BitsRead: 0,
}
const (
twosComplimentNegativeOne = 4294967295
byteLen = 8
oneBit = 0x01
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 {
return &BitMuncher{
source.data,
source.Offset,
0,
}
// CopyBitMuncher Creates a copy of the source BitMuncher
func CopyBitMuncher(source d2interface.BitMuncher) d2interface.BitMuncher {
return source.Copy()
}
// 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 {
result := uint32(v.data[v.Offset/8]>>uint(v.Offset%8)) & 0x01
v.Offset++
v.BitsRead++
result := uint32(v.data[v.offset/byteLen]>>uint(v.offset%byteLen)) & oneBit
v.offset++
v.bitsRead++
return result
}
// SkipBits skips bits, incrementing the offset and bits read
func (v *BitMuncher) SkipBits(bits int) {
v.Offset += bits
v.BitsRead += bits
v.offset += bits
v.bitsRead += bits
}
// GetByte reads a byte from data
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 {
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 {
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 {
if bits == 0 {
return 0
}
result := uint32(0)
for i := 0; i < bits; i++ {
result |= v.GetBit() << uint(i)
}
return result
}
// GetSignedBits Given a number of bits, reads that many bits and returns as int
func (v *BitMuncher) GetSignedBits(bits int) int {
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 {
if bits == 0 {
return 0
@ -73,13 +124,17 @@ func (v *BitMuncher) MakeSigned(value uint32, bits int) int32 {
if (value & (1 << uint(bits-1))) == 0 {
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++ {
if ((value >> uint(i)) & 1) == 0 {
result -= uint32(1 << uint(i))
}
}
// Force casting to a signed value
return int32(result)
}

View File

@ -3,6 +3,8 @@ package d2dcc
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
)
@ -34,7 +36,7 @@ type DCCDirection struct {
}
// 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}
result := &DCCDirection{}
@ -130,29 +132,29 @@ func CreateDCCDirection(bm *d2common.BitMuncher, file *DCC) *DCCDirection { //no
result.PixelBuffer = nil
// 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!")
}
if pixelMaskBitstream.BitsRead != result.PixelMaskBitstreamSize {
if pixelMaskBitstream.BitsRead() != result.PixelMaskBitstreamSize {
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!")
}
if rawPixelCodesBitstream.BitsRead != result.RawPixelCodesBitstreamSize {
if rawPixelCodesBitstream.BitsRead() != result.RawPixelCodesBitstreamSize {
log.Panic("Did not read the correct number of bits!")
}
bm.SkipBits(pixelCodeandDisplacement.BitsRead)
bm.SkipBits(pixelCodeandDisplacement.BitsRead())
return result
}
//nolint:gocognit nolint:gocyclo // Can't reduce
func (v *DCCDirection) generateFrames(pcd *d2common.BitMuncher) {
func (v *DCCDirection) generateFrames(pcd d2interface.BitMuncher) {
pbIdx := 0
for _, cell := range v.Cells {
@ -255,7 +257,7 @@ func (v *DCCDirection) generateFrames(pcd *d2common.BitMuncher) {
}
//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}
lastPixel := uint32(0)

View File

@ -3,6 +3,8 @@ package d2dcc
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
)
@ -24,7 +26,7 @@ type DCCDirectionFrame struct {
}
// 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{}
bits.GetBits(direction.Variable0Bits) // Variable0

View 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
}

View File

@ -0,0 +1,8 @@
package d2interface
type BitStream interface {
ReadBits(bitCount int) int
PeekByte() int
EnsureBits(bitCount int) bool
WasteBits(bitCount int)
}