diff --git a/d2common/d2data/d2datadict/palette.go b/d2common/d2data/d2datadict/palette.go index 91161d94..67c8ed25 100644 --- a/d2common/d2data/d2datadict/palette.go +++ b/d2common/d2data/d2datadict/palette.go @@ -2,33 +2,21 @@ package d2datadict import ( "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat" ) -// PaletteRGB represents a color in a palette -type PaletteRGB struct { - R, G, B uint8 -} - // PaletteType represents a palette type PaletteRec struct { Name d2enum.PaletteType - Colors [256]PaletteRGB + Colors [256]d2dat.DATColor } var Palettes map[d2enum.PaletteType]PaletteRec // CreatePalette creates a palette func CreatePalette(name d2enum.PaletteType, data []byte) PaletteRec { - result := PaletteRec{Name: name} - - for i := 0; i <= 255; i++ { - result.Colors[i] = PaletteRGB{ - B: data[i*3], - G: data[(i*3)+1], - R: data[(i*3)+2], - } - } - return result + palette, _ := d2dat.LoadDAT(data) + return PaletteRec{Name: name, Colors: palette.Colors} } func LoadPalette(paletteType d2enum.PaletteType, file []byte) { @@ -37,5 +25,4 @@ func LoadPalette(paletteType d2enum.PaletteType, file []byte) { } palette := CreatePalette(paletteType, file) Palettes[paletteType] = palette - } diff --git a/d2common/d2fileformats/d2dat/d2dat.go b/d2common/d2fileformats/d2dat/d2dat.go new file mode 100644 index 00000000..c217b3cc --- /dev/null +++ b/d2common/d2fileformats/d2dat/d2dat.go @@ -0,0 +1,21 @@ +package d2dat + +type DATColor struct { + R uint8 + G uint8 + B uint8 +} + +type DATPalette struct { + Colors [256]DATColor +} + +func LoadDAT(data []byte) (*DATPalette, error) { + palette := &DATPalette{} + + for i := 0; i < 256; i++ { + palette.Colors[i] = DATColor{B: data[i*3], G: data[i*3+1], R: data[i*3+2]} + } + + return palette, nil +} diff --git a/d2common/d2fileformats/d2dc6/dc6.go b/d2common/d2fileformats/d2dc6/dc6.go index 296db42f..2e59d7b3 100644 --- a/d2common/d2fileformats/d2dc6/dc6.go +++ b/d2common/d2fileformats/d2dc6/dc6.go @@ -2,9 +2,7 @@ package d2dc6 import ( "encoding/binary" - "log" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/go-restruct/restruct" ) @@ -19,7 +17,6 @@ type DC6File struct { FramePointers []uint32 `struct:"[]uint32,size=Directions*FramesPerDirection"` Frames []*DC6Frame `struct-size:"Directions*FramesPerDirection"` - valid bool } type DC6Header struct { @@ -53,83 +50,16 @@ type DC6Frame struct { 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} +func LoadDC6(data []byte) (*DC6File, error) { + result := &DC6File{} 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 nil, err } return result, err diff --git a/d2common/d2fileformats/d2ds1/ds1.go b/d2common/d2fileformats/d2ds1/ds1.go index b47b2239..86ec24f3 100644 --- a/d2common/d2fileformats/d2ds1/ds1.go +++ b/d2common/d2fileformats/d2ds1/ds1.go @@ -24,8 +24,8 @@ type DS1 struct { SubstitutionGroups []SubstitutionGroup } -func LoadDS1(fileData []byte) DS1 { - ds1 := DS1{ +func LoadDS1(fileData []byte) (*DS1, error) { + ds1 := &DS1{ NumberOfFloors: 1, NumberOfWalls: 1, NumberOfShadowLayers: 1, @@ -243,5 +243,5 @@ func LoadDS1(fileData []byte) DS1 { } } } - return ds1 + return ds1, nil } diff --git a/d2common/d2fileformats/d2dt1/dt1.go b/d2common/d2fileformats/d2dt1/dt1.go index 8a2719a0..f3070406 100644 --- a/d2common/d2fileformats/d2dt1/dt1.go +++ b/d2common/d2fileformats/d2dt1/dt1.go @@ -1,7 +1,7 @@ package d2dt1 import ( - "log" + "fmt" "github.com/OpenDiablo2/OpenDiablo2/d2common" ) @@ -19,13 +19,13 @@ const ( BlockFormatIsometric BlockDataFormat = 1 ) -func LoadDT1(fileData []byte) DT1 { - result := DT1{} +func LoadDT1(fileData []byte) (*DT1, error) { + result := &DT1{} br := d2common.CreateStreamReader(fileData) ver1 := br.GetInt32() ver2 := br.GetInt32() if ver1 != 7 || ver2 != 6 { - log.Panicf("Expected to have a version of 7.6, but got %d.%d instead", ver1, ver2) + return nil, fmt.Errorf("Expected to have a version of 7.6, but got %d.%d instead", ver1, ver2) } br.SkipBytes(260) numberOfTiles := br.GetInt32() @@ -79,5 +79,5 @@ func LoadDT1(fileData []byte) DT1 { } } - return result + return result, nil } diff --git a/d2core/d2asset/animation.go b/d2core/d2asset/animation.go index 7122cb6e..edeb817f 100644 --- a/d2core/d2asset/animation.go +++ b/d2core/d2asset/animation.go @@ -6,7 +6,7 @@ import ( "math" "github.com/OpenDiablo2/OpenDiablo2/d2common" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" @@ -53,7 +53,7 @@ type Animation struct { subEndingFrame int } -func createAnimationFromDCC(dcc *d2dcc.DCC, palette *d2datadict.PaletteRec, transparency int) (*Animation, error) { +func createAnimationFromDCC(dcc *d2dcc.DCC, palette *d2dat.DATPalette, transparency int) (*Animation, error) { animation := &Animation{ playLength: 1.0, playLoop: true, @@ -115,7 +115,7 @@ func createAnimationFromDCC(dcc *d2dcc.DCC, palette *d2datadict.PaletteRec, tran return animation, nil } -func createAnimationFromDC6(dc6 *d2dc6.DC6File) (*Animation, error) { +func createAnimationFromDC6(dc6 *d2dc6.DC6File, palette *d2dat.DATPalette) (*Animation, error) { animation := &Animation{ playLength: 1.0, playLoop: true, @@ -128,7 +128,52 @@ func createAnimationFromDC6(dc6 *d2dc6.DC6File) (*Animation, error) { return nil, err } - if err := image.ReplacePixels(dc6Frame.ColorData()); err != nil { + indexData := make([]int, dc6Frame.Width*dc6Frame.Height) + for i := range indexData { + indexData[i] = -1 + } + + x := 0 + y := int(dc6Frame.Height) - 1 + offset := 0 + + for { + b := int(dc6Frame.FrameData[offset]) + offset++ + + if b == 0x80 { + if y == 0 { + break + } + y-- + x = 0 + } else if b&0x80 > 0 { + transparentPixels := b & 0x7f + for i := 0; i < transparentPixels; i++ { + indexData[x+y*int(dc6Frame.Width)+i] = -1 + } + x += transparentPixels + } else { + for i := 0; i < b; i++ { + indexData[x+y*int(dc6Frame.Width)+i] = int(dc6Frame.FrameData[offset]) + offset++ + } + x += b + } + } + + colorData := make([]byte, dc6Frame.Width*dc6Frame.Height*4) + for i := 0; i < int(dc6Frame.Width*dc6Frame.Height); i++ { + if indexData[i] < 1 { // TODO: Is this == -1 or < 1? + continue + } + colorData[i*4] = palette.Colors[indexData[i]].R + colorData[i*4+1] = palette.Colors[indexData[i]].G + colorData[i*4+2] = palette.Colors[indexData[i]].B + colorData[i*4+3] = 0xff + } + + if err := image.ReplacePixels(colorData); err != nil { return nil, err } diff --git a/d2core/d2asset/animation_manager.go b/d2core/d2asset/animation_manager.go index 3195f444..cb91d027 100644 --- a/d2core/d2asset/animation_manager.go +++ b/d2core/d2asset/animation_manager.go @@ -30,12 +30,17 @@ func (am *animationManager) loadAnimation(animationPath, palettePath string, tra ext := strings.ToLower(filepath.Ext(animationPath)) switch ext { case ".dc6": - dc6, err := loadDC6(animationPath, palettePath) + dc6, err := loadDC6(animationPath) if err != nil { return nil, err } - animation, err = createAnimationFromDC6(dc6) + palette, err := loadPalette(palettePath) + if err != nil { + return nil, err + } + + animation, err = createAnimationFromDC6(dc6, palette) if err != nil { return nil, err } diff --git a/d2core/d2asset/asset_manager.go b/d2core/d2asset/asset_manager.go index 9f9dc94b..326fe51f 100644 --- a/d2core/d2asset/asset_manager.go +++ b/d2core/d2asset/asset_manager.go @@ -3,8 +3,8 @@ package d2asset import ( "errors" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2cof" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" ) @@ -22,28 +22,23 @@ type assetManager struct { fontManager *fontManager } -func loadPalette(palettePath string) (*d2datadict.PaletteRec, error) { +func loadPalette(palettePath string) (*d2dat.DATPalette, error) { verifyWasInit() return singleton.paletteManager.loadPalette(palettePath) } -func loadDC6(dc6Path, palettePath string) (*d2dc6.DC6File, error) { +func loadDC6(dc6Path string) (*d2dc6.DC6File, error) { dc6Data, err := LoadFile(dc6Path) if err != nil { return nil, err } - paletteData, err := loadPalette(palettePath) + dc6, err := d2dc6.LoadDC6(dc6Data) if err != nil { return nil, err } - dc6, err := d2dc6.LoadDC6(dc6Data, *paletteData) - if err != nil { - return nil, err - } - - return &dc6, nil + return dc6, nil } func loadDCC(dccPath string) (*d2dcc.DCC, error) { diff --git a/d2core/d2asset/palette_manager.go b/d2core/d2asset/palette_manager.go index fceb976f..29371527 100644 --- a/d2core/d2asset/palette_manager.go +++ b/d2core/d2asset/palette_manager.go @@ -2,7 +2,7 @@ package d2asset import ( "github.com/OpenDiablo2/OpenDiablo2/d2common" - "github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict" + "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat" ) type paletteManager struct { @@ -17,9 +17,9 @@ func createPaletteManager() *paletteManager { return &paletteManager{d2common.CreateCache(paletteBudget)} } -func (pm *paletteManager) loadPalette(palettePath string) (*d2datadict.PaletteRec, error) { +func (pm *paletteManager) loadPalette(palettePath string) (*d2dat.DATPalette, error) { if palette, found := pm.cache.Retrieve(palettePath); found { - return palette.(*d2datadict.PaletteRec), nil + return palette.(*d2dat.DATPalette), nil } paletteData, err := LoadFile(palettePath) @@ -27,7 +27,11 @@ func (pm *paletteManager) loadPalette(palettePath string) (*d2datadict.PaletteRe return nil, err } - palette := d2datadict.CreatePalette("", paletteData) - pm.cache.Insert(palettePath, &palette, 1) - return &palette, nil + palette, err := d2dat.LoadDAT(paletteData) + if err != nil { + return nil, err + } + + pm.cache.Insert(palettePath, palette, 1) + return palette, nil } diff --git a/d2core/d2map/region.go b/d2core/d2map/region.go index 57df634e..ce786f47 100644 --- a/d2core/d2map/region.go +++ b/d2core/d2map/region.go @@ -80,7 +80,7 @@ type MapRegion struct { levelType d2datadict.LevelTypeRecord levelPreset d2datadict.LevelPresetRecord tiles []d2dt1.Tile - ds1 d2ds1.DS1 + ds1 *d2ds1.DS1 palette d2datadict.PaletteRec startX float64 startY float64 @@ -111,7 +111,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio panic(err) } - dt1 := d2dt1.LoadDT1(fileData) + dt1, _ := d2dt1.LoadDT1(fileData) region.tiles = append(region.tiles, dt1.Tiles...) } } @@ -137,7 +137,7 @@ func loadRegion(seed int64, tileOffsetX, tileOffsetY int, levelType d2enum.Regio if err != nil { panic(err) } - region.ds1 = d2ds1.LoadDS1(fileData) + region.ds1, _ = d2ds1.LoadDS1(fileData) region.tileRect = d2common.Rectangle{ Left: tileOffsetX, Top: tileOffsetY,