1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-03 06:20:43 +00:00
OpenDiablo2/d2core/d2asset/dcc_animation.go
Ziemas 826b1224f6 This DCC frame size calculation seems useless
TBH there some to be some other overcomplicated things going on in
DCCAnimation but too tired to use brain right now.
2021-01-02 01:56:09 +01:00

200 lines
4.5 KiB
Go

package d2asset
import (
"errors"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
var _ d2interface.Animation = &DCCAnimation{} // Static check to confirm struct conforms to
// interface
func newDCCAnimation(
dcc *d2dcc.DCC,
pal d2interface.Palette,
effect d2enum.DrawEffect,
) (d2interface.Animation, error) {
DCC := &DCCAnimation{
dcc: dcc,
palette: pal,
}
anim := &Animation{
playLength: defaultPlayLength,
playLoop: true,
effect: effect,
onBindRenderer: func(r d2interface.Renderer) error {
if DCC.renderer != r {
DCC.renderer = r
return DCC.createSurfaces()
}
return nil
},
}
DCC.Animation = *anim
err := DCC.init()
if err != nil {
return nil, err
}
return DCC, nil
}
// DCCAnimation represents an animation decoded from DCC
type DCCAnimation struct {
Animation
dcc *d2dcc.DCC
palette d2interface.Palette
}
func (a *DCCAnimation) init() error {
a.directions = make([]animationDirection, a.dcc.NumberOfDirections)
for directionIndex := range a.directions {
a.directions[directionIndex].frames = make([]animationFrame, a.dcc.FramesPerDirection)
}
err := a.decode()
return err
}
// Clone creates a copy of the animation
func (a *DCCAnimation) Clone() d2interface.Animation {
clone := &DCCAnimation{}
clone.Animation = *a.Animation.Clone().(*Animation)
clone.dcc = a.dcc.Clone()
clone.palette = a.palette
return clone
}
// SetDirection places the animation in the direction of an animation
func (a *DCCAnimation) SetDirection(directionIndex int) error {
const smallestInvalidDirectionIndex = 64
if directionIndex >= smallestInvalidDirectionIndex {
return errors.New("invalid direction index")
}
direction := d2dcc.Dir64ToDcc(directionIndex, len(a.directions))
if !a.directions[direction].decoded {
err := a.decodeDirection(direction)
if err != nil {
return err
}
}
a.directionIndex = direction
a.frameIndex = 0
return nil
}
func (a *DCCAnimation) decode() error {
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
err := a.decodeDirection(directionIndex)
if err != nil {
return err
}
}
return nil
}
func (a *DCCAnimation) decodeDirection(directionIndex int) error {
dccDirection := a.dcc.Directions[directionIndex]
for frameIndex := range dccDirection.Frames {
if a.directions[directionIndex].frames == nil {
a.directions[directionIndex].frames = make([]animationFrame, a.dcc.FramesPerDirection)
}
a.directions[directionIndex].decoded = true
frame := a.decodeFrame(directionIndex)
a.directions[directionIndex].frames[frameIndex] = frame
}
return nil
}
func (a *DCCAnimation) decodeFrame(directionIndex int) animationFrame {
dccDirection := a.dcc.Directions[directionIndex]
frame := animationFrame{
width: dccDirection.Box.Width,
height: dccDirection.Box.Height,
offsetX: dccDirection.Box.Left,
offsetY: dccDirection.Box.Top,
decoded: true,
}
return frame
}
func (a *DCCAnimation) createSurfaces() error {
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
err := a.createDirectionSurfaces(directionIndex)
if err != nil {
return err
}
}
return nil
}
func (a *DCCAnimation) createDirectionSurfaces(directionIndex int) error {
for frameIndex := 0; frameIndex < a.dcc.FramesPerDirection; frameIndex++ {
if !a.directions[directionIndex].decoded {
err := a.decodeDirection(directionIndex)
if err != nil {
return err
}
}
surface, err := a.createFrameSurface(directionIndex, frameIndex)
if err != nil {
return err
}
a.directions[directionIndex].frames[frameIndex].image = surface
}
return nil
}
func (a *DCCAnimation) createFrameSurface(directionIndex, frameIndex int) (d2interface.Surface, error) {
if !a.directions[directionIndex].frames[frameIndex].decoded {
frame := a.decodeFrame(directionIndex)
a.directions[directionIndex].frames[frameIndex] = frame
}
dccFrame := a.dcc.Directions[directionIndex].Frames[frameIndex]
animFrame := a.directions[directionIndex].frames[frameIndex]
indexData := dccFrame.PixelData
if len(indexData) != (animFrame.width * animFrame.height) {
return nil, errors.New("pixel data incorrect")
}
colorData := d2util.ImgIndexToRGBA(indexData, a.palette)
if a.renderer == nil {
return nil, errors.New("no renderer")
}
sfc := a.renderer.NewSurface(animFrame.width, animFrame.height)
sfc.ReplacePixels(colorData)
return sfc, nil
}