1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-12 18:50:42 +00:00

Animation manager abstraction (#544)

* abstracted palettes, colors, and palette manager

* make asset manager use the palette manager interface

* added BGRA setter/getter, fixed lint errors

* abstraction for animation and animation manager
This commit is contained in:
dk 2020-07-05 10:01:44 -07:00 committed by GitHub
parent 8809fb2c22
commit c1a88c9cf7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 293 additions and 88 deletions

View File

@ -1,11 +1,22 @@
package d2dat package d2dat
import "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
const (
// index offset helpers
b = iota
g
r
o
)
// Load loads a DAT file. // Load loads a DAT file.
func Load(data []byte) (*DATPalette, error) { func Load(data []byte) (d2interface.Palette, error) {
palette := &DATPalette{} palette := &DATPalette{}
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
palette.Colors[i] = DATColor{B: data[i*3], G: data[i*3+1], R: data[i*3+2]} // offsets look like i*3+n, where n is 0,1,2
palette.colors[i] = &DATColor{b: data[i*o+b], g: data[i*o+g], r: data[i*o+r]}
} }
return palette, nil return palette, nil

View File

@ -2,7 +2,76 @@ package d2dat
// DATColor represents a single color in a DAT file. // DATColor represents a single color in a DAT file.
type DATColor struct { type DATColor struct {
R uint8 r uint8
G uint8 g uint8
B uint8 b uint8
a uint8
} }
const (
colorBits = 8
mask = 0xff
)
const (
bitShift0 = iota*colorBits
bitShift8
bitShift16
bitShift24
)
// R gets the red component
func (c *DATColor) R() uint8 {
return c.r
}
// G gets the green component
func (c *DATColor) G() uint8 {
return c.g
}
// B gets the blue component
func (c *DATColor) B() uint8 {
return c.b
}
// A gets the alpha component
func (c *DATColor) A() uint8 {
return mask
}
// RGBA gets the combination of the color components (0xRRGGBBAA)
func (c *DATColor) RGBA() uint32 {
return toComposite(c.r, c.g, c.b, c.a)
}
// SetRGBA sets the color components using the given RGBA form
func (c *DATColor) SetRGBA(rgba uint32) {
c.r, c.g, c.b, c.a = toComponent(rgba)
}
func (c *DATColor) BGRA() uint32 {
return toComposite(c.b, c.g, c.r, c.a)
}
func (c *DATColor) SetBGRA(bgra uint32) {
c.b, c.g, c.r, c.a = toComponent(bgra)
}
func toComposite (w,x,y,z uint8) uint32 {
composite := uint32(w)<<bitShift24
composite += uint32(x)<<bitShift16
composite += uint32(y)<<bitShift8
composite += uint32(z)<<bitShift0
return composite
}
func toComponent (wxyz uint32) (w,x,y,z uint8){
w = uint8(wxyz>>bitShift24 & mask)
x = uint8(wxyz>>bitShift16 & mask)
y = uint8(wxyz>>bitShift8 & mask)
z = uint8(wxyz>>bitShift0 & mask)
return w, x, y, z
}

View File

@ -1,6 +1,34 @@
package d2dat package d2dat
import (
"fmt"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
const (
numColors = 256
)
// DATPalette represents a 256 color palette. // DATPalette represents a 256 color palette.
type DATPalette struct { type DATPalette struct {
Colors [256]DATColor colors [numColors]d2interface.Color
}
// NumColors returns the number of colors in the palette
func (p *DATPalette) NumColors() int {
return len(p.colors)
}
// GetColors returns the slice of colors in the palette
func (p *DATPalette) GetColors() [numColors]d2interface.Color {
return p.colors
}
// GetColor returns a color by index
func (p *DATPalette) GetColor(idx int) (d2interface.Color, error) {
if color := p.colors[idx]; color != nil {
return color, nil
}
return nil, fmt.Errorf("cannot find color index '%d in palette'", idx)
} }

View File

@ -0,0 +1,39 @@
package d2interface
import (
"image"
"image/color"
)
// Animation is an animation
type Animation interface {
Clone() Animation
SetSubLoop(startFrame, EndFrame int)
Advance(elapsed float64) error
Render(target Surface) error
RenderFromOrigin(target Surface) error
RenderSection(sfc Surface, bound image.Rectangle) error
GetFrameSize(frameIndex int) (int, int, error)
GetCurrentFrameSize() (int, int)
GetFrameBounds() (int, int)
GetCurrentFrame() int
GetFrameCount() int
IsOnFirstFrame() bool
IsOnLastFrame() bool
GetDirectionCount() int
SetDirection(directionIndex int) error
GetDirection() int
SetCurrentFrame(frameIndex int) error
Rewind()
PlayForward()
PlayBackward()
Pause()
SetPlayLoop(loop bool)
SetPlaySpeed(playSpeed float64)
SetPlayLength(playLength float64)
SetPlayLengthMs(playLengthMs int)
SetColorMod(colorMod color.Color)
GetPlayedCount() int
ResetPlayedCount()
SetBlend(blend bool)
}

View File

@ -0,0 +1,6 @@
package d2interface
type ArchivedAnimationManager interface {
Cacher
LoadAnimation(animationPath, palettePath string, transparency int) (Animation, error)
}

View File

@ -0,0 +1,5 @@
package d2interface
type ArchivedPaletteManager interface {
LoadPalette(palettePath string) (Palette, error)
}

View File

@ -0,0 +1,22 @@
package d2interface
const numColors = 256
// Color represents a color
type Color interface {
R() uint8
G() uint8
B() uint8
A() uint8
RGBA() uint32
SetRGBA(uint32)
BGRA() uint32
SetBGRA(uint32)
}
// Palette is a color palette
type Palette interface {
NumColors() int
GetColors() [256]Color
GetColor(idx int) (Color, error)
}

View File

@ -8,10 +8,9 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" d2iface "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
) )
@ -32,7 +31,7 @@ type animationFrame struct {
offsetX int offsetX int
offsetY int offsetY int
image d2interface.Surface image d2iface.Surface
} }
type animationDirection struct { type animationDirection struct {
@ -41,27 +40,25 @@ type animationDirection struct {
// Animation has directionality, play modes, and frame counting // Animation has directionality, play modes, and frame counting
type Animation struct { type Animation struct {
directions []*animationDirection directions []*animationDirection
frameIndex int colorMod color.Color
directionIndex int frameIndex int
lastFrameTime float64 directionIndex int
playedCount int lastFrameTime float64
playedCount int
compositeMode d2enum.CompositeMode compositeMode d2enum.CompositeMode
colorMod color.Color
originAtBottom bool
playMode playMode playMode playMode
playLength float64 playLength float64
playLoop bool
hasSubLoop bool // runs after first animation ends
subStartingFrame int subStartingFrame int
subEndingFrame int subEndingFrame int
originAtBottom bool
playLoop bool
hasSubLoop bool // runs after first animation ends
} }
// CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette // CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette
func CreateAnimationFromDCC(renderer d2interface.Renderer, dcc *d2dcc.DCC, palette *d2dat.DATPalette, func CreateAnimationFromDCC(renderer d2iface.Renderer, dcc *d2dcc.DCC, palette d2iface.Palette,
transparency int) (*Animation, error) { transparency int) (d2iface.Animation, error) {
animation := &Animation{ animation := &Animation{
playLength: defaultPlayLength, playLength: defaultPlayLength,
playLoop: true, playLoop: true,
@ -87,18 +84,22 @@ func CreateAnimationFromDCC(renderer d2interface.Renderer, dcc *d2dcc.DCC, palet
for y := 0; y < frameHeight; y++ { for y := 0; y < frameHeight; y++ {
for x := 0; x < frameWidth; x++ { for x := 0; x < frameWidth; x++ {
if paletteIndex := dccFrame.PixelData[y*frameWidth+x]; paletteIndex != 0 { paletteIndex := dccFrame.PixelData[y*frameWidth+x]
palColor := palette.Colors[paletteIndex]
offset := (x + y*frameWidth) * bytesPerPixel if paletteIndex == 0 {
pixels[offset] = palColor.R continue
pixels[offset+1] = palColor.G
pixels[offset+2] = palColor.B
pixels[offset+3] = byte(transparency)
} }
palColor := palette.GetColors()[paletteIndex]
offset := (x + y*frameWidth) * bytesPerPixel
pixels[offset] = palColor.R()
pixels[offset+1] = palColor.G()
pixels[offset+2] = palColor.B()
pixels[offset+3] = byte(transparency)
} }
} }
sfc, err := renderer.NewSurface(frameWidth, frameHeight, d2interface.FilterNearest) sfc, err := renderer.NewSurface(frameWidth, frameHeight, d2iface.FilterNearest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -126,7 +127,8 @@ func CreateAnimationFromDCC(renderer d2interface.Renderer, dcc *d2dcc.DCC, palet
} }
// CreateAnimationFromDC6 creates an Animation from d2dc6.DC6 and d2dat.DATPalette // CreateAnimationFromDC6 creates an Animation from d2dc6.DC6 and d2dat.DATPalette
func CreateAnimationFromDC6(renderer d2interface.Renderer, dc6 *d2dc6.DC6, palette *d2dat.DATPalette) (*Animation, error) { func CreateAnimationFromDC6(renderer d2iface.Renderer, dc6 *d2dc6.DC6,
palette d2iface.Palette) (d2iface.Animation, error) {
animation := &Animation{ animation := &Animation{
playLength: defaultPlayLength, playLength: defaultPlayLength,
playLoop: true, playLoop: true,
@ -134,7 +136,8 @@ func CreateAnimationFromDC6(renderer d2interface.Renderer, dc6 *d2dc6.DC6, palet
} }
for frameIndex, dc6Frame := range dc6.Frames { for frameIndex, dc6Frame := range dc6.Frames {
sfc, err := renderer.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height), d2interface.FilterNearest) sfc, err := renderer.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height),
d2iface.FilterNearest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -177,14 +180,16 @@ func CreateAnimationFromDC6(renderer d2interface.Renderer, dc6 *d2dc6.DC6, palet
colorData := make([]byte, int(dc6Frame.Width)*int(dc6Frame.Height)*bytesPerPixel) colorData := make([]byte, int(dc6Frame.Width)*int(dc6Frame.Height)*bytesPerPixel)
for i := 0; i < int(dc6Frame.Width*dc6Frame.Height); i++ { for i := 0; i < int(dc6Frame.Width*dc6Frame.Height); i++ {
if indexData[i] < 1 { // TODO: Is this == -1 or < 1? // TODO: Is this == -1 or < 1?
if indexData[i] < 1 {
continue continue
} }
colorData[i*bytesPerPixel] = palette.Colors[indexData[i]].R c := palette.GetColors()[indexData[i]]
colorData[i*bytesPerPixel+1] = palette.Colors[indexData[i]].G colorData[i*bytesPerPixel] = c.R()
colorData[i*bytesPerPixel+2] = palette.Colors[indexData[i]].B colorData[i*bytesPerPixel+1] = c.G()
colorData[i*bytesPerPixel+3] = 0xff colorData[i*bytesPerPixel+2] = c.B()
colorData[i*bytesPerPixel+3] = c.A()
} }
if err := sfc.ReplacePixels(colorData); err != nil { if err := sfc.ReplacePixels(colorData); err != nil {
@ -209,17 +214,20 @@ func CreateAnimationFromDC6(renderer d2interface.Renderer, dc6 *d2dc6.DC6, palet
return animation, nil return animation, nil
} }
func (a *Animation) Clone() *Animation { // Clone creates a copy of the animation
func (a *Animation) Clone() d2iface.Animation {
animation := *a animation := *a
return &animation return &animation
} }
func (a *Animation) SetSubLoop(startFrame, EndFrame int) { // SetSubLoop sets a sub loop for the animation
func (a *Animation) SetSubLoop(startFrame, endFrame int) {
a.subStartingFrame = startFrame a.subStartingFrame = startFrame
a.subEndingFrame = EndFrame a.subEndingFrame = endFrame
a.hasSubLoop = true a.hasSubLoop = true
} }
// Advance advances the animation state
func (a *Animation) Advance(elapsed float64) error { func (a *Animation) Advance(elapsed float64) error {
if a.playMode == playModePause { if a.playMode == playModePause {
return nil return nil
@ -234,6 +242,7 @@ func (a *Animation) Advance(elapsed float64) error {
for i := 0; i < framesAdvanced; i++ { for i := 0; i < framesAdvanced; i++ {
startIndex := 0 startIndex := 0
endIndex := frameCount endIndex := frameCount
if a.hasSubLoop && a.playedCount > 0 { if a.hasSubLoop && a.playedCount > 0 {
startIndex = a.subStartingFrame startIndex = a.subStartingFrame
endIndex = a.subEndingFrame endIndex = a.subEndingFrame
@ -268,7 +277,8 @@ func (a *Animation) Advance(elapsed float64) error {
return nil return nil
} }
func (a *Animation) Render(target d2interface.Surface) error { // Render renders the animation to the given surface
func (a *Animation) Render(target d2iface.Surface) error {
direction := a.directions[a.directionIndex] direction := a.directions[a.directionIndex]
frame := direction.frames[a.frameIndex] frame := direction.frames[a.frameIndex]
@ -284,11 +294,13 @@ func (a *Animation) Render(target d2interface.Surface) error {
return target.Render(frame.image) return target.Render(frame.image)
} }
func (a *Animation) RenderFromOrigin(target d2interface.Surface) error { // RenderFromOrigin renders the animation from the animation origin
func (a *Animation) RenderFromOrigin(target d2iface.Surface) error {
if a.originAtBottom { if a.originAtBottom {
direction := a.directions[a.directionIndex] direction := a.directions[a.directionIndex]
frame := direction.frames[a.frameIndex] frame := direction.frames[a.frameIndex]
target.PushTranslation(0, -frame.height) target.PushTranslation(0, -frame.height)
defer target.Pop() defer target.Pop()
} }
@ -296,37 +308,40 @@ func (a *Animation) RenderFromOrigin(target d2interface.Surface) error {
} }
// RenderSection renders the section of the animation frame enclosed by bounds // RenderSection renders the section of the animation frame enclosed by bounds
func (a *Animation) RenderSection(sfc d2interface.Surface, bound image.Rectangle) error { func (a *Animation) RenderSection(sfc d2iface.Surface, bound image.Rectangle) error {
direction := a.directions[a.directionIndex] direction := a.directions[a.directionIndex]
frame := direction.frames[a.frameIndex] frame := direction.frames[a.frameIndex]
sfc.PushTranslation(frame.offsetX, frame.offsetY) sfc.PushTranslation(frame.offsetX, frame.offsetY)
sfc.PushCompositeMode(a.compositeMode) sfc.PushCompositeMode(a.compositeMode)
sfc.PushColor(a.colorMod) sfc.PushColor(a.colorMod)
defer sfc.PopN(3) defer sfc.PopN(3)
return sfc.RenderSection(frame.image, bound) return sfc.RenderSection(frame.image, bound)
} }
// GetFrameSize gets the Size(width, height) of a indexed frame. // GetFrameSize gets the Size(width, height) of a indexed frame.
func (a *Animation) GetFrameSize(frameIndex int) (int, int, error) { func (a *Animation) GetFrameSize(frameIndex int) (width, height int, err error) {
direction := a.directions[a.directionIndex] direction := a.directions[a.directionIndex]
if frameIndex >= len(direction.frames) { if frameIndex >= len(direction.frames) {
return 0, 0, errors.New("invalid frame index") return 0, 0, errors.New("invalid frame index")
} }
frame := direction.frames[frameIndex] frame := direction.frames[frameIndex]
return frame.width, frame.height, nil return frame.width, frame.height, nil
} }
// GetCurrentFrameSize gets the Size(width, height) of the current frame. // GetCurrentFrameSize gets the Size(width, height) of the current frame.
func (a *Animation) GetCurrentFrameSize() (int, int) { func (a *Animation) GetCurrentFrameSize() (width, height int) {
width, height, _ := a.GetFrameSize(a.frameIndex) width, height, _ = a.GetFrameSize(a.frameIndex)
return width, height return width, height
} }
// GetFrameBounds gets maximum Size(width, height) of all frame. // GetFrameBounds gets maximum Size(width, height) of all frame.
func (a *Animation) GetFrameBounds() (int, int) { func (a *Animation) GetFrameBounds() (maxWidth, maxHeight int) {
maxWidth, maxHeight := 0, 0 maxWidth, maxHeight = 0, 0
direction := a.directions[a.directionIndex] direction := a.directions[a.directionIndex]
for _, frame := range direction.frames { for _, frame := range direction.frames {
@ -427,13 +442,15 @@ func (a *Animation) SetPlaySpeed(playSpeed float64) {
} }
// SetPlayLength sets the Animation's play length in seconds // SetPlayLength sets the Animation's play length in seconds
func (a *Animation) SetPlayLength(playLength float64) { // TODO refactor to use time.Duration instead of float64 func (a *Animation) SetPlayLength(playLength float64) {
// TODO refactor to use time.Duration instead of float64
a.playLength = playLength a.playLength = playLength
a.lastFrameTime = 0 a.lastFrameTime = 0
} }
// SetPlayLengthMs sets the Animation's play length in milliseconds // SetPlayLengthMs sets the Animation's play length in milliseconds
func (a *Animation) SetPlayLengthMs(playLengthMs int) { // TODO remove this method func (a *Animation) SetPlayLengthMs(playLengthMs int) {
// TODO remove this method
const millisecondsPerSecond = 1000.0 const millisecondsPerSecond = 1000.0
a.SetPlayLength(float64(playLengthMs) / millisecondsPerSecond) a.SetPlayLength(float64(playLengthMs) / millisecondsPerSecond)
} }

View File

@ -19,6 +19,14 @@ type animationManager struct {
renderer d2interface.Renderer renderer d2interface.Renderer
} }
func (am *animationManager) ClearCache() {
panic("implement me")
}
func (am *animationManager) GetCache() d2interface.Cache {
panic("implement me")
}
func createAnimationManager(renderer d2interface.Renderer) *animationManager { func createAnimationManager(renderer d2interface.Renderer) *animationManager {
return &animationManager{ return &animationManager{
renderer: renderer, renderer: renderer,
@ -26,13 +34,15 @@ func createAnimationManager(renderer d2interface.Renderer) *animationManager {
} }
} }
func (am *animationManager) loadAnimation(animationPath, palettePath string, transparency int) (*Animation, error) { func (am *animationManager) LoadAnimation(
animationPath, palettePath string,
transparency int ) (d2interface.Animation, error) {
cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, transparency) cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, transparency)
if animation, found := am.cache.Retrieve(cachePath); found { if animation, found := am.cache.Retrieve(cachePath); found {
return animation.(*Animation).Clone(), nil return animation.(*Animation).Clone(), nil
} }
var animation *Animation var animation d2interface.Animation
ext := strings.ToLower(filepath.Ext(animationPath)) ext := strings.ToLower(filepath.Ext(animationPath))
switch ext { switch ext {

View File

@ -10,9 +10,9 @@ import (
type assetManager struct { type assetManager struct {
archiveManager d2interface.ArchiveManager archiveManager d2interface.ArchiveManager
archivedFileManager d2interface.ArchivedFileManager archivedFileManager d2interface.ArchivedFileManager
paletteManager *paletteManager paletteManager d2interface.ArchivedPaletteManager
paletteTransformManager *paletteTransformManager paletteTransformManager *paletteTransformManager
animationManager *animationManager animationManager d2interface.ArchivedAnimationManager
fontManager *fontManager fontManager *fontManager
} }

View File

@ -164,7 +164,7 @@ type compositeMode struct {
weaponClass string weaponClass string
playedCount int playedCount int
layers []*Animation layers []d2interface.Animation
frameCount int frameCount int
frameIndex int frameIndex int
@ -194,7 +194,7 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
cof: cof, cof: cof,
animationMode: animationMode, animationMode: animationMode,
weaponClass: weaponClass, weaponClass: weaponClass,
layers: make([]*Animation, d2enum.CompositeTypeMax), layers: make([]d2interface.Animation, d2enum.CompositeTypeMax),
frameCount: animationData[0].FramesPerDirection, frameCount: animationData[0].FramesPerDirection,
animationSpeed: 1.0 / ((float64(animationData[0].AnimationSpeed) * 25.0) / 256.0), animationSpeed: 1.0 / ((float64(animationData[0].AnimationSpeed) * 25.0) / 256.0),
} }
@ -240,7 +240,7 @@ func (c *Composite) createMode(animationMode, weaponClass string) (*compositeMod
} }
func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weaponClass, func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weaponClass,
palettePath string, transparency int) (*Animation, error) { palettePath string, transparency int) (d2interface.Animation, error) {
animationPaths := []string{ animationPaths := []string{
fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass), fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dcc", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass),
fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dc6", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass), fmt.Sprintf("%s/%s/%s/%s%s%s%s%s.dc6", c.basePath, c.token, layerKey, c.token, layerKey, layerValue, animationMode, weaponClass),

View File

@ -5,7 +5,6 @@ import (
"log" "log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
) )
@ -106,13 +105,14 @@ func FileExists(filePath string) (bool, error) {
} }
// LoadAnimation loads an animation by its resource path and its palette path // LoadAnimation loads an animation by its resource path and its palette path
func LoadAnimation(animationPath, palettePath string) (*Animation, error) { func LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
return LoadAnimationWithTransparency(animationPath, palettePath, 255) return LoadAnimationWithTransparency(animationPath, palettePath, 255)
} }
// LoadAnimationWithTransparency loads an animation by its resource path and its palette path with a given transparency value // LoadAnimationWithTransparency loads an animation by its resource path and its palette path with a given transparency value
func LoadAnimationWithTransparency(animationPath, palettePath string, transparency int) (*Animation, error) { func LoadAnimationWithTransparency(animationPath, palettePath string,
return singleton.animationManager.loadAnimation(animationPath, palettePath, transparency) transparency int) (d2interface.Animation, error) {
return singleton.animationManager.LoadAnimation(animationPath, palettePath, transparency)
} }
// LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it // LoadComposite creates a composite object from a ObjectLookupRecord and palettePath describing it
@ -126,6 +126,6 @@ func LoadFont(tablePath, spritePath, palettePath string) (*Font, error) {
} }
// LoadPalette loads a palette from a given palette path // LoadPalette loads a palette from a given palette path
func LoadPalette(palettePath string) (*d2dat.DATPalette, error) { func LoadPalette(palettePath string) (d2interface.Palette, error) {
return singleton.paletteManager.loadPalette(palettePath) return singleton.paletteManager.LoadPalette(palettePath)
} }

View File

@ -19,7 +19,7 @@ type fontGlyph struct {
// Font represents a displayable font // Font represents a displayable font
type Font struct { type Font struct {
sheet *Animation sheet d2interface.Animation
glyphs map[rune]fontGlyph glyphs map[rune]fontGlyph
color color.Color color color.Color
} }

View File

@ -18,9 +18,9 @@ func createPaletteManager() *paletteManager {
return &paletteManager{d2common.CreateCache(paletteBudget)} return &paletteManager{d2common.CreateCache(paletteBudget)}
} }
func (pm *paletteManager) loadPalette(palettePath string) (*d2dat.DATPalette, error) { func (pm *paletteManager) LoadPalette(palettePath string) (d2interface.Palette, error) {
if palette, found := pm.cache.Retrieve(palettePath); found { if palette, found := pm.cache.Retrieve(palettePath); found {
return palette.(*d2dat.DATPalette), nil return palette.(d2interface.Palette), nil
} }
paletteData, err := LoadFile(palettePath) paletteData, err := LoadFile(palettePath)

View File

@ -18,7 +18,8 @@ func loadFont(fontStyle FontStyle) (*d2asset.Font, error) {
return d2asset.LoadFont(config.fontBasePath+".tbl", config.fontBasePath+".dc6", config.palettePath) return d2asset.LoadFont(config.fontBasePath+".tbl", config.fontBasePath+".dc6", config.palettePath)
} }
func renderSegmented(animation *d2asset.Animation, segmentsX, segmentsY, frameOffset int, target d2interface.Surface) error { func renderSegmented(animation d2interface.Animation, segmentsX, segmentsY, frameOffset int,
target d2interface.Surface) error {
var currentY int var currentY int
for y := 0; y < segmentsY; y++ { for y := 0; y < segmentsY; y++ {
var currentX int var currentX int

View File

@ -13,10 +13,10 @@ import (
type manager struct { type manager struct {
layout *Layout layout *Layout
cursorAnim *d2asset.Animation cursorAnim d2interface.Animation
cursorX int cursorX int
cursorY int cursorY int
loadingAnim *d2asset.Animation loadingAnim d2interface.Animation
cursorVisible bool cursorVisible bool
loading bool loading bool
} }

View File

@ -19,7 +19,7 @@ type Sprite struct {
segmentsY int segmentsY int
frameOffset int frameOffset int
animation *d2asset.Animation animation d2interface.Animation
} }
type AnimatedSprite struct { type AnimatedSprite struct {

View File

@ -2,7 +2,6 @@ package d2mapentity
import ( import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
// AnimatedEntity represents an animation that can be projected onto the map. // AnimatedEntity represents an animation that can be projected onto the map.
@ -12,11 +11,11 @@ type AnimatedEntity struct {
action int action int
repetitions int repetitions int
animation *d2asset.Animation animation d2interface.Animation
} }
// CreateAnimatedEntity creates an instance of AnimatedEntity // CreateAnimatedEntity creates an instance of AnimatedEntity
func CreateAnimatedEntity(x, y int, animation *d2asset.Animation) *AnimatedEntity { func CreateAnimatedEntity(x, y int, animation d2interface.Animation) *AnimatedEntity {
entity := &AnimatedEntity{ entity := &AnimatedEntity{
mapEntity: createMapEntity(x, y), mapEntity: createMapEntity(x, y),
animation: animation, animation: animation,

View File

@ -21,11 +21,11 @@ func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, t
for n > 0 { for n > 0 {
colorIndex := block.EncodedData[idx] colorIndex := block.EncodedData[idx]
if colorIndex != 0 { if colorIndex != 0 {
pixelColor := mr.palette.Colors[colorIndex] pixelColor := mr.palette.GetColors()[colorIndex]
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x)) offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = pixelColor.R (*pixels)[offset] = pixelColor.R()
(*pixels)[offset+1] = pixelColor.G (*pixels)[offset+1] = pixelColor.G()
(*pixels)[offset+2] = pixelColor.B (*pixels)[offset+2] = pixelColor.B()
(*pixels)[offset+3] = 255 (*pixels)[offset+3] = 255
} }
x++ x++
@ -58,12 +58,12 @@ func (mr *MapRenderer) decodeTileGfxData(blocks []d2dt1.Block, pixels *[]byte, t
for b2 > 0 { for b2 > 0 {
colorIndex := block.EncodedData[idx] colorIndex := block.EncodedData[idx]
if colorIndex != 0 { if colorIndex != 0 {
pixelColor := mr.palette.Colors[colorIndex] pixelColor := mr.palette.GetColors()[colorIndex]
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x)) offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
(*pixels)[offset] = pixelColor.R (*pixels)[offset] = pixelColor.R()
(*pixels)[offset+1] = pixelColor.G (*pixels)[offset+1] = pixelColor.G()
(*pixels)[offset+2] = pixelColor.B (*pixels)[offset+2] = pixelColor.B()
(*pixels)[offset+3] = 255 (*pixels)[offset+3] = 255
} }

View File

@ -7,7 +7,6 @@ import (
"math" "math"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
@ -19,7 +18,7 @@ import (
type MapRenderer struct { type MapRenderer struct {
renderer d2interface.Renderer // The renderer to use for drawing operations renderer d2interface.Renderer // The renderer to use for drawing operations
mapEngine *d2mapengine.MapEngine // The map engine that is being rendered mapEngine *d2mapengine.MapEngine // The map engine that is being rendered
palette *d2dat.DATPalette // The palette used for this map palette d2interface.Palette // The palette used for this map
viewport *Viewport // The viewport for the map renderer (used for rendering offsets) viewport *Viewport // The viewport for the map renderer (used for rendering offsets)
camera Camera // The camera for this map renderer (used to determine where on the map we are rendering) camera Camera // The camera for this map renderer (used to determine where on the map we are rendering)
debugVisLevel int // Debug visibility index (0=none, 1=tiles, 2=sub-tiles) debugVisLevel int // Debug visibility index (0=none, 1=tiles, 2=sub-tiles)
@ -354,7 +353,7 @@ func (mr *MapRenderer) Advance(elapsed float64) {
} }
} }
func loadPaletteForAct(levelType d2enum.RegionIdType) (*d2dat.DATPalette, error) { func loadPaletteForAct(levelType d2enum.RegionIdType) (d2interface.Palette, error) {
var palettePath string var palettePath string
switch levelType { switch levelType {
case d2enum.RegionAct1Town, d2enum.RegionAct1Wilderness, d2enum.RegionAct1Cave, d2enum.RegionAct1Crypt, case d2enum.RegionAct1Town, d2enum.RegionAct1Wilderness, d2enum.RegionAct1Cave, d2enum.RegionAct1Crypt,

View File

@ -8,21 +8,20 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common" "github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
) )
// Sprite is a positioned visual object. // Sprite is a positioned visual object.
type Sprite struct { type Sprite struct {
x int x int
y int y int
animation *d2asset.Animation animation d2interface.Animation
} }
var ( var (
ErrNoAnimation = errors.New("no animation was specified") ErrNoAnimation = errors.New("no animation was specified")
) )
func LoadSprite(animation *d2asset.Animation) (*Sprite, error) { func LoadSprite(animation d2interface.Animation) (*Sprite, error) {
if animation == nil { if animation == nil {
return nil, ErrNoAnimation return nil, ErrNoAnimation
} }