1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-20 06:05:23 +00: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:
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 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)
} }

View File

@ -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)

View File

@ -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

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