mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-20 07:27:19 -05:00
Decouple asset manager from renderer (#730)
* improve AssetManager implementation Notable changes are: * removed the individual managers inside of d2asset, only one asset manager * AssetManager now has caches for the types of files it loads * created a type for TextDictionary (the txt file structs) * fixed a file path bug in d2loader Source * fixed a asset stream bug in d2loader Asset * d2loader.Loader now needs a d2config.Config on creation (for resolving locale files) * updated the mpq file in d2asset test data, added test case for "sub-directory" * added a Data method to d2asset.Asset. The data is cached on first full read. * renamed ArchiveDataStream to DataStream in d2interface * moved palette utility func out of d2asset and into d2util * bugfix for MacOS mpq loader issue * lint fixes, added data caching to filesystem asset * adding comment for mpq asset close * Decouple d2asset from d2render Notable changes in d2common: * d2dcc.Load now fully decodes the dcc and stores the directions/frames in the dcc struct * un-exported dcc.decodeDirection, it is only used in d2dcc * removed font interface from d2interface, we only have one font implementation * added `Renderer` method to d2interface.Surface, animations use this to bind to a renderer and create surfaces as they need * added `BindRenderer` method to animation interface Notable changes in d2common/d2asset: * **d2asset.NewAssetManager only needs to be passed a d2config.Config**, it is decoupled from d2render * exported Animation * Animation implementation binds to the renderer to create surfaces only on the first time it is rendered * font, dcc, dc6 initialization logic moved out of asset_manager.go * for dc6 and dcc animations, the process of decoding and creating render surfaces has been broken into different methods * the d2asset.Font struct now stores font table data for initialization purposes Notable changes in d2core/d2render: * Surfaces store a renderer reference, this allows animations to bind to the renderer and create a surface just-in-time **These last changes should have been a separate PR, sorry.** Notable changes in d2core/d2ui: * ui.NewSprite now handles creating an animation internally, only needs image and palette path as arguments Notable Changes in d2game: Because of the change in d2ui, all instances of this code pattern... ```golang animation, err := screen.asset.LoadAnimation(imgPath, palettePath) sprite, err := screen.ui.NewSprite(animation) ``` ... becomes this ... ```golang sprite, err := screen.ui.NewSprite(imgPath, palettePath) ```
This commit is contained in:
parent
8a670d7482
commit
7e3aff557b
@ -15,6 +15,7 @@ type DCC struct {
|
|||||||
Version int
|
Version int
|
||||||
NumberOfDirections int
|
NumberOfDirections int
|
||||||
FramesPerDirection int
|
FramesPerDirection int
|
||||||
|
Directions []*DCCDirection
|
||||||
directionOffsets []int
|
directionOffsets []int
|
||||||
fileData []byte
|
fileData []byte
|
||||||
}
|
}
|
||||||
@ -37,6 +38,8 @@ func Load(fileData []byte) (*DCC, error) {
|
|||||||
result.NumberOfDirections = int(bm.GetByte())
|
result.NumberOfDirections = int(bm.GetByte())
|
||||||
result.FramesPerDirection = int(bm.GetInt32())
|
result.FramesPerDirection = int(bm.GetInt32())
|
||||||
|
|
||||||
|
result.Directions = make([]*DCCDirection, result.NumberOfDirections)
|
||||||
|
|
||||||
if bm.GetInt32() != 1 {
|
if bm.GetInt32() != 1 {
|
||||||
return nil, errors.New("this value isn't 1. It has to be 1")
|
return nil, errors.New("this value isn't 1. It has to be 1")
|
||||||
}
|
}
|
||||||
@ -47,13 +50,14 @@ func Load(fileData []byte) (*DCC, error) {
|
|||||||
|
|
||||||
for i := 0; i < result.NumberOfDirections; i++ {
|
for i := 0; i < result.NumberOfDirections; i++ {
|
||||||
result.directionOffsets[i] = int(bm.GetInt32())
|
result.directionOffsets[i] = int(bm.GetInt32())
|
||||||
|
result.Directions[i] = result.decodeDirection(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeDirection decodes and returns the given direction
|
// decodeDirection decodes and returns the given direction
|
||||||
func (dcc *DCC) DecodeDirection(direction int) *DCCDirection {
|
func (dcc *DCC) decodeDirection(direction int) *DCCDirection {
|
||||||
return CreateDCCDirection(d2datautils.CreateBitMuncher(dcc.fileData,
|
return CreateDCCDirection(d2datautils.CreateBitMuncher(dcc.fileData,
|
||||||
dcc.directionOffsets[direction]*directionOffsetMultiplier), dcc)
|
dcc.directionOffsets[direction]*directionOffsetMultiplier), dcc)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
// Animation is an animation
|
// Animation is an animation
|
||||||
type Animation interface {
|
type Animation interface {
|
||||||
|
BindRenderer(Renderer) error
|
||||||
Clone() Animation
|
Clone() Animation
|
||||||
SetSubLoop(startFrame, EndFrame int)
|
SetSubLoop(startFrame, EndFrame int)
|
||||||
Advance(elapsed float64) error
|
Advance(elapsed float64) error
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package d2interface
|
|
||||||
|
|
||||||
import (
|
|
||||||
"image/color"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Font is a graphical representation associated with a set of glyphs.
|
|
||||||
type Font interface {
|
|
||||||
SetColor(c color.Color)
|
|
||||||
GetTextMetrics(text string) (width, height int)
|
|
||||||
RenderText(text string, target Surface) error
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
// Surface represents a renderable surface.
|
// Surface represents a renderable surface.
|
||||||
type Surface interface {
|
type Surface interface {
|
||||||
|
Renderer() Renderer
|
||||||
Clear(color color.Color) error
|
Clear(color color.Color) error
|
||||||
DrawRect(width, height int, color color.Color)
|
DrawRect(width, height int, color color.Color)
|
||||||
DrawLine(x, y int, color color.Color)
|
DrawLine(x, y int, color color.Color)
|
||||||
|
@ -23,6 +23,8 @@ const (
|
|||||||
const defaultPlayLength = 1.0
|
const defaultPlayLength = 1.0
|
||||||
|
|
||||||
type animationFrame struct {
|
type animationFrame struct {
|
||||||
|
decoded bool
|
||||||
|
|
||||||
width int
|
width int
|
||||||
height int
|
height int
|
||||||
offsetX int
|
offsetX int
|
||||||
@ -33,11 +35,13 @@ type animationFrame struct {
|
|||||||
|
|
||||||
type animationDirection struct {
|
type animationDirection struct {
|
||||||
decoded bool
|
decoded bool
|
||||||
frames []*animationFrame
|
frames []animationFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
// animation has directionality, play modes, and frame counting
|
// Animation has directionality, play modes, and frame counting
|
||||||
type animation struct {
|
type Animation struct {
|
||||||
|
renderer d2interface.Renderer
|
||||||
|
onBindRenderer func(renderer d2interface.Renderer) error
|
||||||
directions []animationDirection
|
directions []animationDirection
|
||||||
effect d2enum.DrawEffect
|
effect d2enum.DrawEffect
|
||||||
colorMod color.Color
|
colorMod color.Color
|
||||||
@ -56,14 +60,14 @@ type animation struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetSubLoop sets a sub loop for the animation
|
// SetSubLoop sets a sub loop for the animation
|
||||||
func (a *animation) SetSubLoop(startFrame, endFrame int) {
|
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
|
// 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
|
||||||
}
|
}
|
||||||
@ -112,7 +116,7 @@ func (a *animation) Advance(elapsed float64) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *animation) renderShadow(target d2interface.Surface) error {
|
func (a *Animation) renderShadow(target d2interface.Surface) error {
|
||||||
direction := a.directions[a.directionIndex]
|
direction := a.directions[a.directionIndex]
|
||||||
frame := direction.frames[a.frameIndex]
|
frame := direction.frames[a.frameIndex]
|
||||||
|
|
||||||
@ -131,7 +135,11 @@ func (a *animation) renderShadow(target d2interface.Surface) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render renders the animation to the given surface
|
// Render renders the animation to the given surface
|
||||||
func (a *animation) Render(target d2interface.Surface) error {
|
func (a *Animation) Render(target d2interface.Surface) error {
|
||||||
|
if a.renderer == nil {
|
||||||
|
a.BindRenderer(target.Renderer())
|
||||||
|
}
|
||||||
|
|
||||||
direction := a.directions[a.directionIndex]
|
direction := a.directions[a.directionIndex]
|
||||||
frame := direction.frames[a.frameIndex]
|
frame := direction.frames[a.frameIndex]
|
||||||
|
|
||||||
@ -147,8 +155,22 @@ func (a *animation) Render(target d2interface.Surface) error {
|
|||||||
return target.Render(frame.image)
|
return target.Render(frame.image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BindRenderer binds the given renderer to the animation so that it can initialize
|
||||||
|
// the required surfaces
|
||||||
|
func (a *Animation) BindRenderer(r d2interface.Renderer) error {
|
||||||
|
if a.onBindRenderer == nil {
|
||||||
|
return errors.New("the Animation does not have a onBindRenderer handler")
|
||||||
|
}
|
||||||
|
|
||||||
|
return a.onBindRenderer(r)
|
||||||
|
}
|
||||||
|
|
||||||
// RenderFromOrigin renders the animation from the animation origin
|
// RenderFromOrigin renders the animation from the animation origin
|
||||||
func (a *animation) RenderFromOrigin(target d2interface.Surface, shadow bool) error {
|
func (a *Animation) RenderFromOrigin(target d2interface.Surface, shadow bool) error {
|
||||||
|
if a.renderer == nil {
|
||||||
|
a.BindRenderer(target.Renderer())
|
||||||
|
}
|
||||||
|
|
||||||
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]
|
||||||
@ -171,7 +193,11 @@ func (a *animation) RenderFromOrigin(target d2interface.Surface, shadow bool) er
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 d2interface.Surface, bound image.Rectangle) error {
|
||||||
|
if a.renderer == nil {
|
||||||
|
a.BindRenderer(sfc.Renderer())
|
||||||
|
}
|
||||||
|
|
||||||
direction := a.directions[a.directionIndex]
|
direction := a.directions[a.directionIndex]
|
||||||
frame := direction.frames[a.frameIndex]
|
frame := direction.frames[a.frameIndex]
|
||||||
|
|
||||||
@ -185,7 +211,7 @@ func (a *animation) RenderSection(sfc d2interface.Surface, bound image.Rectangle
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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) (width, height int, err 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")
|
||||||
@ -197,16 +223,17 @@ func (a *animation) GetFrameSize(frameIndex int) (width, height int, err error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentFrameSize gets the Size(width, height) of the current frame.
|
// GetCurrentFrameSize gets the Size(width, height) of the current frame.
|
||||||
func (a *animation) GetCurrentFrameSize() (width, height 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() (maxWidth, maxHeight 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 {
|
||||||
maxWidth = d2math.MaxInt(maxWidth, frame.width)
|
maxWidth = d2math.MaxInt(maxWidth, frame.width)
|
||||||
maxHeight = d2math.MaxInt(maxHeight, frame.height)
|
maxHeight = d2math.MaxInt(maxHeight, frame.height)
|
||||||
@ -216,33 +243,33 @@ func (a *animation) GetFrameBounds() (maxWidth, maxHeight int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetCurrentFrame gets index of current frame in animation
|
// GetCurrentFrame gets index of current frame in animation
|
||||||
func (a *animation) GetCurrentFrame() int {
|
func (a *Animation) GetCurrentFrame() int {
|
||||||
return a.frameIndex
|
return a.frameIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFrameCount gets number of frames in animation
|
// GetFrameCount gets number of frames in animation
|
||||||
func (a *animation) GetFrameCount() int {
|
func (a *Animation) GetFrameCount() int {
|
||||||
direction := a.directions[a.directionIndex]
|
direction := a.directions[a.directionIndex]
|
||||||
return len(direction.frames)
|
return len(direction.frames)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOnFirstFrame gets if the animation on its first frame
|
// IsOnFirstFrame gets if the animation on its first frame
|
||||||
func (a *animation) IsOnFirstFrame() bool {
|
func (a *Animation) IsOnFirstFrame() bool {
|
||||||
return a.frameIndex == 0
|
return a.frameIndex == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOnLastFrame gets if the animation on its last frame
|
// IsOnLastFrame gets if the animation on its last frame
|
||||||
func (a *animation) IsOnLastFrame() bool {
|
func (a *Animation) IsOnLastFrame() bool {
|
||||||
return a.frameIndex == a.GetFrameCount()-1
|
return a.frameIndex == a.GetFrameCount()-1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetDirectionCount gets the number of animation direction
|
// GetDirectionCount gets the number of animation direction
|
||||||
func (a *animation) GetDirectionCount() int {
|
func (a *Animation) GetDirectionCount() int {
|
||||||
return len(a.directions)
|
return len(a.directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDirection places the animation in the direction of an animation
|
// SetDirection places the animation in the direction of an animation
|
||||||
func (a *animation) SetDirection(directionIndex int) error {
|
func (a *Animation) SetDirection(directionIndex int) error {
|
||||||
const smallestInvalidDirectionIndex = 64
|
const smallestInvalidDirectionIndex = 64
|
||||||
if directionIndex >= smallestInvalidDirectionIndex {
|
if directionIndex >= smallestInvalidDirectionIndex {
|
||||||
return errors.New("invalid direction index")
|
return errors.New("invalid direction index")
|
||||||
@ -255,12 +282,12 @@ func (a *animation) SetDirection(directionIndex int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetDirection get the current animation direction
|
// GetDirection get the current animation direction
|
||||||
func (a *animation) GetDirection() int {
|
func (a *Animation) GetDirection() int {
|
||||||
return a.directionIndex
|
return a.directionIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCurrentFrame sets animation at a specific frame
|
// SetCurrentFrame sets animation at a specific frame
|
||||||
func (a *animation) SetCurrentFrame(frameIndex int) error {
|
func (a *Animation) SetCurrentFrame(frameIndex int) error {
|
||||||
if frameIndex >= a.GetFrameCount() {
|
if frameIndex >= a.GetFrameCount() {
|
||||||
return errors.New("invalid frame index")
|
return errors.New("invalid frame index")
|
||||||
}
|
}
|
||||||
@ -272,47 +299,47 @@ func (a *animation) SetCurrentFrame(frameIndex int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Rewind animation to beginning
|
// Rewind animation to beginning
|
||||||
func (a *animation) Rewind() {
|
func (a *Animation) Rewind() {
|
||||||
_ = a.SetCurrentFrame(0)
|
_ = a.SetCurrentFrame(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayForward plays animation forward
|
// PlayForward plays animation forward
|
||||||
func (a *animation) PlayForward() {
|
func (a *Animation) PlayForward() {
|
||||||
a.playMode = playModeForward
|
a.playMode = playModeForward
|
||||||
a.lastFrameTime = 0
|
a.lastFrameTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlayBackward plays animation backward
|
// PlayBackward plays animation backward
|
||||||
func (a *animation) PlayBackward() {
|
func (a *Animation) PlayBackward() {
|
||||||
a.playMode = playModeBackward
|
a.playMode = playModeBackward
|
||||||
a.lastFrameTime = 0
|
a.lastFrameTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause animation
|
// Pause animation
|
||||||
func (a *animation) Pause() {
|
func (a *Animation) Pause() {
|
||||||
a.playMode = playModePause
|
a.playMode = playModePause
|
||||||
a.lastFrameTime = 0
|
a.lastFrameTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPlayLoop sets whether to loop the animation
|
// SetPlayLoop sets whether to loop the animation
|
||||||
func (a *animation) SetPlayLoop(loop bool) {
|
func (a *Animation) SetPlayLoop(loop bool) {
|
||||||
a.playLoop = loop
|
a.playLoop = loop
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPlaySpeed sets play speed of the animation
|
// SetPlaySpeed sets play speed of the animation
|
||||||
func (a *animation) SetPlaySpeed(playSpeed float64) {
|
func (a *Animation) SetPlaySpeed(playSpeed float64) {
|
||||||
a.SetPlayLength(playSpeed * float64(a.GetFrameCount()))
|
a.SetPlayLength(playSpeed * float64(a.GetFrameCount()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPlayLength sets the Animation's play length in seconds
|
// SetPlayLength sets the Animation's play length in seconds
|
||||||
func (a *animation) SetPlayLength(playLength float64) {
|
func (a *Animation) SetPlayLength(playLength float64) {
|
||||||
// TODO refactor to use time.Duration instead of 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) {
|
func (a *Animation) SetPlayLengthMs(playLengthMs int) {
|
||||||
// TODO remove this method
|
// TODO remove this method
|
||||||
const millisecondsPerSecond = 1000.0
|
const millisecondsPerSecond = 1000.0
|
||||||
|
|
||||||
@ -320,24 +347,24 @@ func (a *animation) SetPlayLengthMs(playLengthMs int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetColorMod sets the Animation's color mod
|
// SetColorMod sets the Animation's color mod
|
||||||
func (a *animation) SetColorMod(colorMod color.Color) {
|
func (a *Animation) SetColorMod(colorMod color.Color) {
|
||||||
a.colorMod = colorMod
|
a.colorMod = colorMod
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPlayedCount gets the number of times the application played
|
// GetPlayedCount gets the number of times the application played
|
||||||
func (a *animation) GetPlayedCount() int {
|
func (a *Animation) GetPlayedCount() int {
|
||||||
return a.playedCount
|
return a.playedCount
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetPlayedCount resets the play count
|
// ResetPlayedCount resets the play count
|
||||||
func (a *animation) ResetPlayedCount() {
|
func (a *Animation) ResetPlayedCount() {
|
||||||
a.playedCount = 0
|
a.playedCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *animation) SetEffect(e d2enum.DrawEffect) {
|
func (a *Animation) SetEffect(e d2enum.DrawEffect) {
|
||||||
a.effect = e
|
a.effect = e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *animation) SetShadow(shadow bool) {
|
func (a *Animation) SetShadow(shadow bool) {
|
||||||
a.hasShadow = shadow
|
a.hasShadow = shadow
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package d2asset
|
package d2asset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"log"
|
||||||
@ -32,7 +31,6 @@ const (
|
|||||||
|
|
||||||
// AssetManager loads files and game objects
|
// AssetManager loads files and game objects
|
||||||
type AssetManager struct {
|
type AssetManager struct {
|
||||||
renderer d2interface.Renderer
|
|
||||||
loader *d2loader.Loader
|
loader *d2loader.Loader
|
||||||
tables d2interface.Cache
|
tables d2interface.Cache
|
||||||
animations d2interface.Cache
|
animations d2interface.Cache
|
||||||
@ -80,12 +78,12 @@ func (am *AssetManager) FileExists(filePath string) (bool, error) {
|
|||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 (am *AssetManager) LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
|
func (am *AssetManager) LoadAnimation(animationPath, palettePath string) (d2interface.Animation, error) {
|
||||||
return am.LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone)
|
return am.LoadAnimationWithEffect(animationPath, palettePath, d2enum.DrawEffectNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAnimationWithEffect loads an animation by its resource path and its palette path with a given transparency value
|
// LoadAnimationWithEffect loads an Animation by its resource path and its palette path with a given transparency value
|
||||||
func (am *AssetManager) LoadAnimationWithEffect(animationPath, palettePath string,
|
func (am *AssetManager) LoadAnimationWithEffect(animationPath, palettePath string,
|
||||||
effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
||||||
cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, effect)
|
cachePath := fmt.Sprintf("%s;%s;%d", animationPath, palettePath, effect)
|
||||||
@ -108,17 +106,17 @@ func (am *AssetManager) LoadAnimationWithEffect(animationPath, palettePath strin
|
|||||||
|
|
||||||
switch animAsset.Type() {
|
switch animAsset.Type() {
|
||||||
case types.AssetTypeDC6:
|
case types.AssetTypeDC6:
|
||||||
animation, err = am.createDC6Animation(animationPath, palette, effect)
|
animation, err = am.loadDC6(animationPath, palette, effect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
case types.AssetTypeDCC:
|
case types.AssetTypeDCC:
|
||||||
animation, err = am.createDCCAnimation(animationPath, palette, effect)
|
animation, err = am.loadDCC(animationPath, palette, effect)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown animation format for file: %s", animAsset.Path())
|
return nil, fmt.Errorf("unknown Animation format for file: %s", animAsset.Path())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = am.animations.Insert(cachePath, animation, defaultCacheEntryWeight)
|
err = am.animations.Insert(cachePath, animation, defaultCacheEntryWeight)
|
||||||
@ -140,11 +138,11 @@ func (am *AssetManager) LoadComposite(baseType d2enum.ObjectType, token, palette
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LoadFont loads a font the resource files
|
// LoadFont loads a font the resource files
|
||||||
func (am *AssetManager) LoadFont(tablePath, spritePath, palettePath string) (d2interface.Font, error) {
|
func (am *AssetManager) LoadFont(tablePath, spritePath, palettePath string) (*Font, error) {
|
||||||
cachePath := fmt.Sprintf("%s;%s;%s", tablePath, spritePath, palettePath)
|
cachePath := fmt.Sprintf("%s;%s;%s", tablePath, spritePath, palettePath)
|
||||||
|
|
||||||
if cached, found := am.fonts.Retrieve(cachePath); found {
|
if cached, found := am.fonts.Retrieve(cachePath); found {
|
||||||
return cached.(d2interface.Font), nil
|
return cached.(*Font), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sheet, err := am.LoadAnimation(spritePath, palettePath)
|
sheet, err := am.LoadAnimation(spritePath, palettePath)
|
||||||
@ -161,25 +159,10 @@ func (am *AssetManager) LoadFont(tablePath, spritePath, palettePath string) (d2i
|
|||||||
return nil, fmt.Errorf("invalid font table format: %s", tablePath)
|
return nil, fmt.Errorf("invalid font table format: %s", tablePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, maxCharHeight := sheet.GetFrameBounds()
|
|
||||||
|
|
||||||
glyphs := make(map[rune]fontGlyph)
|
|
||||||
|
|
||||||
for i := 12; i < len(tableData); i += 14 {
|
|
||||||
code := rune(binary.LittleEndian.Uint16(tableData[i : i+2]))
|
|
||||||
|
|
||||||
var glyph fontGlyph
|
|
||||||
glyph.frame = int(binary.LittleEndian.Uint16(tableData[i+8 : i+10]))
|
|
||||||
glyph.width = int(tableData[i+3])
|
|
||||||
glyph.height = maxCharHeight
|
|
||||||
|
|
||||||
glyphs[code] = glyph
|
|
||||||
}
|
|
||||||
|
|
||||||
font := &Font{
|
font := &Font{
|
||||||
sheet: sheet,
|
table: tableData,
|
||||||
glyphs: glyphs,
|
sheet: sheet,
|
||||||
color: color.White,
|
color: color.White,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = am.fonts.Insert(cachePath, font, defaultCacheEntryWeight)
|
err = am.fonts.Insert(cachePath, font, defaultCacheEntryWeight)
|
||||||
@ -229,7 +212,7 @@ func (am *AssetManager) LoadStringTable(tablePath string) (d2tbl.TextDictionary,
|
|||||||
}
|
}
|
||||||
|
|
||||||
table := d2tbl.LoadTextDictionary(data)
|
table := d2tbl.LoadTextDictionary(data)
|
||||||
if table != nil {
|
if table == nil {
|
||||||
return nil, fmt.Errorf("table not found: %s", tablePath)
|
return nil, fmt.Errorf("table not found: %s", tablePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,66 +244,9 @@ func (am *AssetManager) LoadPaletteTransform(path string) (*d2pl2.PL2, error) {
|
|||||||
return pl2, nil
|
return pl2, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// createDC6Animation creates an Animation from d2dc6.DC6 and d2dat.DATPalette
|
// loadDC6 creates an Animation from d2dc6.DC6 and d2dat.DATPalette
|
||||||
func (am *AssetManager) createDC6Animation(dc6Path string,
|
func (am *AssetManager) loadDC6(path string,
|
||||||
palette d2interface.Palette, effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
palette d2interface.Palette, effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
||||||
dc6, err := am.loadDC6(dc6Path)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
anim := DC6Animation{
|
|
||||||
animation: animation{
|
|
||||||
directions: make([]animationDirection, dc6.Directions),
|
|
||||||
playLength: defaultPlayLength,
|
|
||||||
playLoop: true,
|
|
||||||
originAtBottom: true,
|
|
||||||
effect: effect,
|
|
||||||
},
|
|
||||||
dc6Path: dc6Path,
|
|
||||||
dc6: dc6,
|
|
||||||
palette: palette,
|
|
||||||
renderer: am.renderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = anim.SetDirection(0)
|
|
||||||
|
|
||||||
return &anim, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// createDCCAnimation creates an animation from d2dcc.DCC and d2dat.DATPalette
|
|
||||||
func (am *AssetManager) createDCCAnimation(dccPath string,
|
|
||||||
palette d2interface.Palette,
|
|
||||||
effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
|
||||||
dcc, err := am.loadDCC(dccPath)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
anim := animation{
|
|
||||||
playLength: defaultPlayLength,
|
|
||||||
playLoop: true,
|
|
||||||
directions: make([]animationDirection, dcc.NumberOfDirections),
|
|
||||||
effect: effect,
|
|
||||||
}
|
|
||||||
|
|
||||||
DCC := DCCAnimation{
|
|
||||||
animation: anim,
|
|
||||||
AssetManager: am,
|
|
||||||
dccPath: dccPath,
|
|
||||||
palette: palette,
|
|
||||||
renderer: am.renderer,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = DCC.SetDirection(0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &DCC, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (am *AssetManager) loadDC6(path string) (*d2dc6.DC6, error) {
|
|
||||||
dc6Data, err := am.LoadFile(path)
|
dc6Data, err := am.LoadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -331,16 +257,27 @@ func (am *AssetManager) loadDC6(path string) (*d2dc6.DC6, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return dc6, nil
|
animation, err := newDC6Animation(dc6, palette, effect)
|
||||||
|
|
||||||
|
return animation, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *AssetManager) loadDCC(path string) (*d2dcc.DCC, error) {
|
// loadDCC creates an Animation from d2dcc.DCC and d2dat.DATPalette
|
||||||
|
func (am *AssetManager) loadDCC(path string,
|
||||||
|
palette d2interface.Palette, effect d2enum.DrawEffect) (d2interface.Animation, error) {
|
||||||
dccData, err := am.LoadFile(path)
|
dccData, err := am.LoadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return d2dcc.Load(dccData)
|
dcc, err := d2dcc.Load(dccData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
animation, err := newDCCAnimation(dcc, palette, effect)
|
||||||
|
|
||||||
|
return animation, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindTerminalCommands binds the in-game terminal comands for the asset manager.
|
// BindTerminalCommands binds the in-game terminal comands for the asset manager.
|
||||||
@ -368,7 +305,7 @@ func (am *AssetManager) BindTerminalCommands(term d2interface.Terminal) error {
|
|||||||
|
|
||||||
term.OutputInfof("palette cache: %f", cacheStatistics(am.palettes))
|
term.OutputInfof("palette cache: %f", cacheStatistics(am.palettes))
|
||||||
term.OutputInfof("palette transform cache: %f", cacheStatistics(am.transforms))
|
term.OutputInfof("palette transform cache: %f", cacheStatistics(am.transforms))
|
||||||
term.OutputInfof("animation cache: %f", cacheStatistics(am.animations))
|
term.OutputInfof("Animation cache: %f", cacheStatistics(am.animations))
|
||||||
term.OutputInfof("font cache: %f", cacheStatistics(am.fonts))
|
term.OutputInfof("font cache: %f", cacheStatistics(am.fonts))
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -63,6 +63,7 @@ func (c *Composite) Render(target d2interface.Surface) error {
|
|||||||
|
|
||||||
for _, layerIndex := range c.mode.cof.Priority[direction][c.mode.frameIndex] {
|
for _, layerIndex := range c.mode.cof.Priority[direction][c.mode.frameIndex] {
|
||||||
layer := c.mode.layers[layerIndex]
|
layer := c.mode.layers[layerIndex]
|
||||||
|
|
||||||
if layer != nil {
|
if layer != nil {
|
||||||
if err := layer.RenderFromOrigin(target, true); err != nil {
|
if err := layer.RenderFromOrigin(target, true); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -145,6 +146,10 @@ func (c *Composite) SetAnimSpeed(speed int) {
|
|||||||
|
|
||||||
// SetDirection sets the direction of the composite and its layers
|
// SetDirection sets the direction of the composite and its layers
|
||||||
func (c *Composite) SetDirection(direction int) {
|
func (c *Composite) SetDirection(direction int) {
|
||||||
|
if c.mode == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
c.direction = direction
|
c.direction = direction
|
||||||
for layerIdx := range c.mode.layers {
|
for layerIdx := range c.mode.layers {
|
||||||
layer := c.mode.layers[layerIdx]
|
layer := c.mode.layers[layerIdx]
|
||||||
@ -241,7 +246,7 @@ func (c *Composite) createMode(animationMode animationMode, weaponClass string)
|
|||||||
|
|
||||||
animationData := d2data.AnimationData[animationKey]
|
animationData := d2data.AnimationData[animationKey]
|
||||||
if len(animationData) == 0 {
|
if len(animationData) == 0 {
|
||||||
return nil, errors.New("could not find animation data")
|
return nil, errors.New("could not find Animation data")
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := &compositeMode{
|
mode := &compositeMode{
|
||||||
@ -300,7 +305,7 @@ func (c *Composite) loadCompositeLayer(layerKey, layerValue, animationMode, weap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("animation not found")
|
return nil, errors.New("Animation not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSize returns the size of the composite
|
// GetSize returns the size of the composite
|
||||||
|
@ -2,16 +2,13 @@ package d2asset
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2cache"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2loader"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewAssetManager creates and assigns all necessary dependencies for the AssetManager top-level functions to work correctly
|
// NewAssetManager creates and assigns all necessary dependencies for the AssetManager top-level functions to work correctly
|
||||||
func NewAssetManager(renderer d2interface.Renderer, config *d2config.Configuration,
|
func NewAssetManager(config *d2config.Configuration) (*AssetManager, error) {
|
||||||
term d2interface.Terminal) (*AssetManager, error) {
|
|
||||||
manager := &AssetManager{
|
manager := &AssetManager{
|
||||||
renderer,
|
|
||||||
d2loader.NewLoader(config),
|
d2loader.NewLoader(config),
|
||||||
d2cache.CreateCache(animationBudget),
|
d2cache.CreateCache(animationBudget),
|
||||||
d2cache.CreateCache(tableBudget),
|
d2cache.CreateCache(tableBudget),
|
||||||
@ -20,10 +17,5 @@ func NewAssetManager(renderer d2interface.Renderer, config *d2config.Configurati
|
|||||||
d2cache.CreateCache(paletteTransformBudget),
|
d2cache.CreateCache(paletteTransformBudget),
|
||||||
}
|
}
|
||||||
|
|
||||||
if term != nil {
|
|
||||||
err := manager.BindTerminalCommands(term)
|
|
||||||
return manager, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return manager, nil
|
return manager, nil
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,9 @@ package d2asset
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
||||||
"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"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
@ -14,13 +14,58 @@ import (
|
|||||||
var _ d2interface.Animation = &DC6Animation{} // Static check to confirm struct conforms to
|
var _ d2interface.Animation = &DC6Animation{} // Static check to confirm struct conforms to
|
||||||
// interface
|
// interface
|
||||||
|
|
||||||
|
func newDC6Animation(
|
||||||
|
dc6 *d2dc6.DC6,
|
||||||
|
pal d2interface.Palette,
|
||||||
|
effect d2enum.DrawEffect,
|
||||||
|
) (d2interface.Animation, error) {
|
||||||
|
DC6 := &DC6Animation{
|
||||||
|
dc6: dc6,
|
||||||
|
palette: pal,
|
||||||
|
}
|
||||||
|
|
||||||
|
anim := Animation{
|
||||||
|
playLength: defaultPlayLength,
|
||||||
|
playLoop: true,
|
||||||
|
originAtBottom: true,
|
||||||
|
effect: effect,
|
||||||
|
onBindRenderer: func(r d2interface.Renderer) error {
|
||||||
|
if DC6.renderer != r {
|
||||||
|
DC6.renderer = r
|
||||||
|
return DC6.createSurfaces()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
DC6.Animation = anim
|
||||||
|
|
||||||
|
err := DC6.init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return DC6, nil
|
||||||
|
}
|
||||||
|
|
||||||
// DC6Animation is an animation made from a DC6 file
|
// DC6Animation is an animation made from a DC6 file
|
||||||
type DC6Animation struct {
|
type DC6Animation struct {
|
||||||
animation
|
Animation
|
||||||
dc6Path string
|
dc6 *d2dc6.DC6
|
||||||
dc6 *d2dc6.DC6
|
palette d2interface.Palette
|
||||||
palette d2interface.Palette
|
}
|
||||||
renderer d2interface.Renderer
|
|
||||||
|
func (a *DC6Animation) init() error {
|
||||||
|
a.directions = make([]animationDirection, a.dc6.Directions)
|
||||||
|
|
||||||
|
for directionIndex := range a.directions {
|
||||||
|
a.directions[directionIndex].frames = make([]animationFrame, a.dc6.FramesPerDirection)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := a.decode()
|
||||||
|
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDirection decodes and sets the direction
|
// SetDirection decodes and sets the direction
|
||||||
@ -31,7 +76,8 @@ func (a *DC6Animation) SetDirection(directionIndex int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
direction := d2dcc.Dir64ToDcc(directionIndex, len(a.directions))
|
direction := d2dcc.Dir64ToDcc(directionIndex, len(a.directions))
|
||||||
if !a.directions[direction].decoded {
|
|
||||||
|
if !a.directions[directionIndex].decoded {
|
||||||
err := a.decodeDirection(direction)
|
err := a.decodeDirection(direction)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -39,44 +85,115 @@ func (a *DC6Animation) SetDirection(directionIndex int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
a.directionIndex = direction
|
a.directionIndex = direction
|
||||||
a.frameIndex = 0
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DC6Animation) decode() error {
|
||||||
|
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
|
||||||
|
err := a.decodeDirection(directionIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *DC6Animation) decodeDirection(directionIndex int) error {
|
func (a *DC6Animation) decodeDirection(directionIndex int) error {
|
||||||
dc6 := a.dc6
|
for frameIndex := 0; frameIndex < int(a.dc6.FramesPerDirection); frameIndex++ {
|
||||||
startFrame := directionIndex * int(dc6.FramesPerDirection)
|
frame, err := a.decodeFrame(directionIndex, frameIndex)
|
||||||
|
|
||||||
for i := 0; i < int(dc6.FramesPerDirection); i++ {
|
|
||||||
dc6Frame := dc6.Frames[startFrame+i]
|
|
||||||
|
|
||||||
sfc, err := a.renderer.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height),
|
|
||||||
d2enum.FilterNearest)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
indexData := dc6.DecodeFrame(startFrame + i)
|
a.directions[directionIndex].frames[frameIndex] = frame
|
||||||
colorData := d2util.ImgIndexToRGBA(indexData, a.palette)
|
}
|
||||||
|
|
||||||
if err := sfc.ReplacePixels(colorData); err != nil {
|
a.directions[directionIndex].decoded = true
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DC6Animation) decodeFrame(directionIndex, frameIndex int) (animationFrame, error) {
|
||||||
|
startFrame := directionIndex * int(a.dc6.FramesPerDirection)
|
||||||
|
|
||||||
|
dc6Frame := a.dc6.Frames[startFrame+frameIndex]
|
||||||
|
|
||||||
|
frame := animationFrame{
|
||||||
|
width: int(dc6Frame.Width),
|
||||||
|
height: int(dc6Frame.Height),
|
||||||
|
offsetX: int(dc6Frame.OffsetX),
|
||||||
|
offsetY: int(dc6Frame.OffsetY),
|
||||||
|
}
|
||||||
|
|
||||||
|
a.directions[directionIndex].frames[frameIndex].decoded = true
|
||||||
|
|
||||||
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DC6Animation) createSurfaces() error {
|
||||||
|
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
|
||||||
|
err := a.createDirectionSurfaces(directionIndex)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
a.directions[directionIndex].decoded = true
|
|
||||||
a.directions[directionIndex].frames = append(a.directions[directionIndex].frames, &animationFrame{
|
|
||||||
width: int(dc6Frame.Width),
|
|
||||||
height: int(dc6Frame.Height),
|
|
||||||
offsetX: int(dc6Frame.OffsetX),
|
|
||||||
offsetY: int(dc6Frame.OffsetY),
|
|
||||||
image: sfc,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *DC6Animation) createDirectionSurfaces(directionIndex int) error {
|
||||||
|
for frameIndex := 0; frameIndex < int(a.dc6.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 *DC6Animation) createFrameSurface(directionIndex, frameIndex int) (d2interface.Surface, error) {
|
||||||
|
if !a.directions[directionIndex].frames[frameIndex].decoded {
|
||||||
|
frame, err := a.decodeFrame(directionIndex, frameIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.directions[directionIndex].frames[frameIndex] = frame
|
||||||
|
}
|
||||||
|
|
||||||
|
startFrame := directionIndex * int(a.dc6.FramesPerDirection)
|
||||||
|
dc6Frame := a.dc6.Frames[startFrame+frameIndex]
|
||||||
|
indexData := a.dc6.DecodeFrame(startFrame + frameIndex)
|
||||||
|
colorData := d2util.ImgIndexToRGBA(indexData, a.palette)
|
||||||
|
|
||||||
|
if a.renderer == nil {
|
||||||
|
return nil, errors.New("no renderer")
|
||||||
|
}
|
||||||
|
|
||||||
|
sfc, err := a.renderer.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height), d2enum.FilterNearest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sfc.ReplacePixels(colorData); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sfc, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Clone creates a copy of the animation
|
// Clone creates a copy of the animation
|
||||||
func (a *DC6Animation) Clone() d2interface.Animation {
|
func (a *DC6Animation) Clone() d2interface.Animation {
|
||||||
animation := *a
|
animation := *a
|
||||||
|
@ -4,10 +4,11 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
@ -16,13 +17,57 @@ import (
|
|||||||
var _ d2interface.Animation = &DCCAnimation{} // Static check to confirm struct conforms to
|
var _ d2interface.Animation = &DCCAnimation{} // Static check to confirm struct conforms to
|
||||||
// interface
|
// 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
|
// DCCAnimation represents an animation decoded from DCC
|
||||||
type DCCAnimation struct {
|
type DCCAnimation struct {
|
||||||
animation
|
Animation
|
||||||
*AssetManager
|
dcc *d2dcc.DCC
|
||||||
dccPath string
|
palette d2interface.Palette
|
||||||
palette d2interface.Palette
|
}
|
||||||
renderer d2interface.Renderer
|
|
||||||
|
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
|
// Clone creates a copy of the animation
|
||||||
@ -52,18 +97,45 @@ func (a *DCCAnimation) SetDirection(directionIndex int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *DCCAnimation) decodeDirection(directionIndex int) error {
|
func (a *DCCAnimation) decode() error {
|
||||||
dcc, err := a.loadDCC(a.dccPath)
|
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
|
||||||
if err != nil {
|
err := a.decodeDirection(directionIndex)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
direction := dcc.DecodeDirection(directionIndex)
|
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, err := a.decodeFrame(directionIndex, frameIndex)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
a.directions[directionIndex].frames[frameIndex] = frame
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DCCAnimation) decodeFrame(directionIndex, frameIndex int) (animationFrame, error) {
|
||||||
|
dccDirection := a.dcc.Directions[directionIndex]
|
||||||
|
|
||||||
minX, minY := math.MaxInt32, math.MaxInt32
|
minX, minY := math.MaxInt32, math.MaxInt32
|
||||||
maxX, maxY := math.MinInt32, math.MinInt32
|
maxX, maxY := math.MinInt32, math.MinInt32
|
||||||
|
|
||||||
for _, dccFrame := range direction.Frames {
|
for _, dccFrame := range dccDirection.Frames {
|
||||||
minX = d2math.MinInt(minX, dccFrame.Box.Left)
|
minX = d2math.MinInt(minX, dccFrame.Box.Left)
|
||||||
minY = d2math.MinInt(minY, dccFrame.Box.Top)
|
minY = d2math.MinInt(minY, dccFrame.Box.Top)
|
||||||
maxX = d2math.MaxInt(maxX, dccFrame.Box.Right())
|
maxX = d2math.MaxInt(maxX, dccFrame.Box.Right())
|
||||||
@ -73,27 +145,80 @@ func (a *DCCAnimation) decodeDirection(directionIndex int) error {
|
|||||||
frameWidth := maxX - minX
|
frameWidth := maxX - minX
|
||||||
frameHeight := maxY - minY
|
frameHeight := maxY - minY
|
||||||
|
|
||||||
for _, dccFrame := range direction.Frames {
|
frame := animationFrame{
|
||||||
pixels := d2util.ImgIndexToRGBA(dccFrame.PixelData, a.palette)
|
width: frameWidth,
|
||||||
|
height: frameHeight,
|
||||||
|
offsetX: minX,
|
||||||
|
offsetY: minY,
|
||||||
|
decoded: true,
|
||||||
|
}
|
||||||
|
|
||||||
sfc, err := a.renderer.NewSurface(frameWidth, frameHeight, d2enum.FilterNearest)
|
return frame, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *DCCAnimation) createSurfaces() error {
|
||||||
|
for directionIndex := 0; directionIndex < len(a.directions); directionIndex++ {
|
||||||
|
err := a.createDirectionSurfaces(directionIndex)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := sfc.ReplacePixels(pixels); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
a.directions[directionIndex].decoded = true
|
|
||||||
a.directions[directionIndex].frames = append(a.directions[directionIndex].frames, &animationFrame{
|
|
||||||
width: frameWidth,
|
|
||||||
height: frameHeight,
|
|
||||||
offsetX: minX,
|
|
||||||
offsetY: minY,
|
|
||||||
image: sfc,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *DCCAnimation) createDirectionSurfaces(directionIndex int) error {
|
||||||
|
for frameIndex := 0; frameIndex < int(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, err := a.decodeFrame(directionIndex, frameIndex)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
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, err := a.renderer.NewSurface(animFrame.width, animFrame.height, d2enum.FilterNearest)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := sfc.ReplacePixels(colorData); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sfc, nil
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package d2asset
|
package d2asset
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"image/color"
|
"image/color"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -8,8 +9,6 @@ import (
|
|||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ d2interface.Font = &Font{} // Static check to confirm struct conforms to interface
|
|
||||||
|
|
||||||
type fontGlyph struct {
|
type fontGlyph struct {
|
||||||
frame int
|
frame int
|
||||||
width int
|
width int
|
||||||
@ -19,6 +18,7 @@ type fontGlyph struct {
|
|||||||
// Font represents a displayable font
|
// Font represents a displayable font
|
||||||
type Font struct {
|
type Font struct {
|
||||||
sheet d2interface.Animation
|
sheet d2interface.Animation
|
||||||
|
table []byte
|
||||||
glyphs map[rune]fontGlyph
|
glyphs map[rune]fontGlyph
|
||||||
color color.Color
|
color color.Color
|
||||||
}
|
}
|
||||||
@ -30,17 +30,19 @@ func (f *Font) SetColor(c color.Color) {
|
|||||||
|
|
||||||
// GetTextMetrics returns the dimensions of the Font element in pixels
|
// GetTextMetrics returns the dimensions of the Font element in pixels
|
||||||
func (f *Font) GetTextMetrics(text string) (width, height int) {
|
func (f *Font) GetTextMetrics(text string) (width, height int) {
|
||||||
|
if f.glyphs == nil {
|
||||||
|
f.initGlyphs()
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lineWidth int
|
lineWidth int
|
||||||
lineHeight int
|
lineHeight int
|
||||||
totalWidth int
|
|
||||||
totalHeight int
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, c := range text {
|
for _, c := range text {
|
||||||
if c == '\n' {
|
if c == '\n' {
|
||||||
totalWidth = d2math.MaxInt(totalWidth, lineWidth)
|
width = d2math.MaxInt(width, lineWidth)
|
||||||
totalHeight += lineHeight
|
height += lineHeight
|
||||||
lineWidth = 0
|
lineWidth = 0
|
||||||
lineHeight = 0
|
lineHeight = 0
|
||||||
} else if glyph, ok := f.glyphs[c]; ok {
|
} else if glyph, ok := f.glyphs[c]; ok {
|
||||||
@ -49,14 +51,23 @@ func (f *Font) GetTextMetrics(text string) (width, height int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
totalWidth = d2math.MaxInt(totalWidth, lineWidth)
|
width = d2math.MaxInt(width, lineWidth)
|
||||||
totalHeight += lineHeight
|
height += lineHeight
|
||||||
|
|
||||||
return totalWidth, totalHeight
|
return width, height
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderText prints a text using its configured style on a Surface (multi-lines are left-aligned, use label otherwise)
|
// RenderText prints a text using its configured style on a Surface (multi-lines are left-aligned, use label otherwise)
|
||||||
func (f *Font) RenderText(text string, target d2interface.Surface) error {
|
func (f *Font) RenderText(text string, target d2interface.Surface) error {
|
||||||
|
if f.glyphs == nil {
|
||||||
|
err := f.sheet.BindRenderer(target.Renderer())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
f.initGlyphs()
|
||||||
|
}
|
||||||
|
|
||||||
f.sheet.SetColorMod(f.color)
|
f.sheet.SetColorMod(f.color)
|
||||||
|
|
||||||
lines := strings.Split(text, "\n")
|
lines := strings.Split(text, "\n")
|
||||||
@ -95,3 +106,22 @@ func (f *Font) RenderText(text string, target d2interface.Surface) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Font) initGlyphs() {
|
||||||
|
_, maxCharHeight := f.sheet.GetFrameBounds()
|
||||||
|
|
||||||
|
glyphs := make(map[rune]fontGlyph)
|
||||||
|
|
||||||
|
for i := 12; i < len(f.table); i += 14 {
|
||||||
|
code := rune(binary.LittleEndian.Uint16(f.table[i : i+2]))
|
||||||
|
|
||||||
|
var glyph fontGlyph
|
||||||
|
glyph.frame = int(binary.LittleEndian.Uint16(f.table[i+8 : i+10]))
|
||||||
|
glyph.width = int(f.table[i+3])
|
||||||
|
glyph.height = maxCharHeight
|
||||||
|
|
||||||
|
glyphs[code] = glyph
|
||||||
|
}
|
||||||
|
|
||||||
|
f.glyphs = glyphs
|
||||||
|
}
|
||||||
|
@ -4,11 +4,13 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||||||
)
|
)
|
||||||
|
|
||||||
func loadFont(fontStyle FontStyle) (d2interface.Font, error) {
|
func loadFont(fontStyle FontStyle) (*d2asset.Font, error) {
|
||||||
config := getFontStyleConfig(fontStyle)
|
config := getFontStyleConfig(fontStyle)
|
||||||
if config == nil {
|
if config == nil {
|
||||||
return nil, errors.New("invalid font style")
|
return nil, errors.New("invalid font style")
|
||||||
|
@ -3,6 +3,7 @@ package d2gui
|
|||||||
import (
|
import (
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Label is renderable text
|
// Label is renderable text
|
||||||
@ -11,7 +12,7 @@ type Label struct {
|
|||||||
|
|
||||||
renderer d2interface.Renderer
|
renderer d2interface.Renderer
|
||||||
text string
|
text string
|
||||||
font d2interface.Font
|
font *d2asset.Font
|
||||||
surface d2interface.Surface
|
surface d2interface.Surface
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ type Renderer struct {
|
|||||||
|
|
||||||
// Update updates the screen with the given *ebiten.Image
|
// Update updates the screen with the given *ebiten.Image
|
||||||
func (r *Renderer) Update(screen *ebiten.Image) error {
|
func (r *Renderer) Update(screen *ebiten.Image) error {
|
||||||
err := r.renderCallback(createEbitenSurface(screen))
|
err := r.renderCallback(createEbitenSurface(r, screen))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -88,19 +88,18 @@ func (r *Renderer) Run(f func(surface d2interface.Surface) error, width, height
|
|||||||
|
|
||||||
// CreateSurface creates a renderer surface from an existing surface
|
// CreateSurface creates a renderer surface from an existing surface
|
||||||
func (r *Renderer) CreateSurface(surface d2interface.Surface) (d2interface.Surface, error) {
|
func (r *Renderer) CreateSurface(surface d2interface.Surface) (d2interface.Surface, error) {
|
||||||
result := createEbitenSurface(
|
img := surface.(*ebitenSurface).image
|
||||||
surface.(*ebitenSurface).image,
|
sfcState := surfaceState{
|
||||||
surfaceState{
|
filter: ebiten.FilterNearest,
|
||||||
filter: ebiten.FilterNearest,
|
effect: d2enum.DrawEffectNone,
|
||||||
effect: d2enum.DrawEffectNone,
|
saturation: defaultSaturation,
|
||||||
saturation: defaultSaturation,
|
brightness: defaultBrightness,
|
||||||
brightness: defaultBrightness,
|
skewX: defaultSkewX,
|
||||||
skewX: defaultSkewX,
|
skewY: defaultSkewY,
|
||||||
skewY: defaultSkewY,
|
scaleX: defaultScaleX,
|
||||||
scaleX: defaultScaleX,
|
scaleY: defaultScaleY,
|
||||||
scaleY: defaultScaleY,
|
}
|
||||||
},
|
result := createEbitenSurface(r, img, sfcState)
|
||||||
)
|
|
||||||
|
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@ -114,7 +113,7 @@ func (r *Renderer) NewSurface(width, height int, filter d2enum.Filter) (d2interf
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return createEbitenSurface(img), nil
|
return createEbitenSurface(r, img), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsFullScreen returns a boolean for whether or not the renderer is currently set to fullscreen
|
// IsFullScreen returns a boolean for whether or not the renderer is currently set to fullscreen
|
||||||
|
@ -30,6 +30,7 @@ type colorMCacheEntry struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ebitenSurface struct {
|
type ebitenSurface struct {
|
||||||
|
renderer *Renderer
|
||||||
stateStack []surfaceState
|
stateStack []surfaceState
|
||||||
stateCurrent surfaceState
|
stateCurrent surfaceState
|
||||||
image *ebiten.Image
|
image *ebiten.Image
|
||||||
@ -37,7 +38,7 @@ type ebitenSurface struct {
|
|||||||
monotonicClock int64
|
monotonicClock int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func createEbitenSurface(img *ebiten.Image, currentState ...surfaceState) *ebitenSurface {
|
func createEbitenSurface(r *Renderer, img *ebiten.Image, currentState ...surfaceState) *ebitenSurface {
|
||||||
state := surfaceState{
|
state := surfaceState{
|
||||||
effect: d2enum.DrawEffectNone,
|
effect: d2enum.DrawEffectNone,
|
||||||
saturation: defaultSaturation,
|
saturation: defaultSaturation,
|
||||||
@ -52,12 +53,18 @@ func createEbitenSurface(img *ebiten.Image, currentState ...surfaceState) *ebite
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &ebitenSurface{
|
return &ebitenSurface{
|
||||||
|
renderer: r,
|
||||||
image: img,
|
image: img,
|
||||||
stateCurrent: state,
|
stateCurrent: state,
|
||||||
colorMCache: make(map[colorMCacheKey]*colorMCacheEntry),
|
colorMCache: make(map[colorMCacheKey]*colorMCacheEntry),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renderer returns the renderer
|
||||||
|
func (s *ebitenSurface) Renderer() d2interface.Renderer {
|
||||||
|
return s.renderer
|
||||||
|
}
|
||||||
|
|
||||||
// PushTranslation pushes an x,y translation to the state stack
|
// PushTranslation pushes an x,y translation to the state stack
|
||||||
func (s *ebitenSurface) PushTranslation(x, y int) {
|
func (s *ebitenSurface) PushTranslation(x, y int) {
|
||||||
s.stateStack = append(s.stateStack, s.stateCurrent)
|
s.stateStack = append(s.stateStack, s.stateCurrent)
|
||||||
|
@ -191,8 +191,7 @@ func (ui *UIManager) NewButton(buttonType ButtonType, text string) *Button {
|
|||||||
lbl.Color[0] = d2util.Color(greyAlpha100)
|
lbl.Color[0] = d2util.Color(greyAlpha100)
|
||||||
lbl.Alignment = d2gui.HorizontalAlignCenter
|
lbl.Alignment = d2gui.HorizontalAlignCenter
|
||||||
|
|
||||||
animation, _ := ui.asset.LoadAnimation(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
buttonSprite, _ := ui.NewSprite(buttonLayout.ResourceName, buttonLayout.PaletteName)
|
||||||
buttonSprite, _ := ui.NewSprite(animation)
|
|
||||||
|
|
||||||
for i := 0; i < buttonLayout.XSegments; i++ {
|
for i := 0; i < buttonLayout.XSegments; i++ {
|
||||||
w, _, _ := buttonSprite.GetFrameSize(i)
|
w, _, _ := buttonSprite.GetFrameSize(i)
|
||||||
|
@ -31,8 +31,7 @@ func (ui *UIManager) NewCheckbox(checkState bool) *Checkbox {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
animation, _ := ui.asset.LoadAnimation(d2resource.Checkbox, d2resource.PaletteFechar)
|
checkboxSprite, _ := ui.NewSprite(d2resource.Checkbox, d2resource.PaletteFechar)
|
||||||
checkboxSprite, _ := ui.NewSprite(animation)
|
|
||||||
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
|
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
|
||||||
checkboxSprite.SetPosition(0, 0)
|
checkboxSprite.SetPosition(0, 0)
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
||||||
|
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
||||||
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
|
||||||
@ -18,7 +20,7 @@ type Label struct {
|
|||||||
X int
|
X int
|
||||||
Y int
|
Y int
|
||||||
Alignment d2gui.HorizontalAlign
|
Alignment d2gui.HorizontalAlign
|
||||||
font d2interface.Font
|
font *d2asset.Font
|
||||||
Color map[int]color.Color
|
Color map[int]color.Color
|
||||||
backgroundColor color.Color
|
backgroundColor color.Color
|
||||||
}
|
}
|
||||||
@ -26,6 +28,7 @@ type Label struct {
|
|||||||
// NewLabel creates a new instance of a UI label
|
// NewLabel creates a new instance of a UI label
|
||||||
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
|
func (ui *UIManager) NewLabel(fontPath, palettePath string) *Label {
|
||||||
font, _ := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
|
font, _ := ui.asset.LoadFont(fontPath+".tbl", fontPath+".dc6", palettePath)
|
||||||
|
|
||||||
result := &Label{
|
result := &Label{
|
||||||
Alignment: d2gui.HorizontalAlignLeft,
|
Alignment: d2gui.HorizontalAlignLeft,
|
||||||
Color: map[int]color.Color{0: color.White},
|
Color: map[int]color.Color{0: color.White},
|
||||||
|
@ -28,8 +28,7 @@ type Scrollbar struct {
|
|||||||
|
|
||||||
// NewScrollbar creates a scrollbar instance
|
// NewScrollbar creates a scrollbar instance
|
||||||
func (ui *UIManager) NewScrollbar(x, y, height int) *Scrollbar {
|
func (ui *UIManager) NewScrollbar(x, y, height int) *Scrollbar {
|
||||||
animation, _ := ui.asset.LoadAnimation(d2resource.Scrollbar, d2resource.PaletteSky)
|
scrollbarSprite, _ := ui.NewSprite(d2resource.Scrollbar, d2resource.PaletteSky)
|
||||||
scrollbarSprite, _ := ui.NewSprite(animation)
|
|
||||||
result := &Scrollbar{
|
result := &Scrollbar{
|
||||||
visible: true,
|
visible: true,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
@ -22,11 +22,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewSprite creates a new Sprite
|
// NewSprite creates a new Sprite
|
||||||
func (ui *UIManager) NewSprite(animation d2interface.Animation) (*Sprite, error) {
|
func (ui *UIManager) NewSprite(animationPath, palettePath string) (*Sprite, error) {
|
||||||
if animation == nil {
|
animation, err := ui.asset.LoadAnimation(animationPath, palettePath)
|
||||||
|
if animation == nil || err != nil {
|
||||||
return nil, fmt.Errorf(errNoAnimation)
|
return nil, fmt.Errorf(errNoAnimation)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = animation.BindRenderer(ui.renderer)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &Sprite{animation: animation}, nil
|
return &Sprite{animation: animation}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +62,8 @@ func (s *Sprite) RenderSegmented(target d2interface.Surface, segmentsX, segments
|
|||||||
var currentX, maxFrameHeight int
|
var currentX, maxFrameHeight int
|
||||||
|
|
||||||
for x := 0; x < segmentsX; x++ {
|
for x := 0; x < segmentsX; x++ {
|
||||||
if err := s.animation.SetCurrentFrame(x + y*segmentsX + frameOffset*segmentsX*segmentsY); err != nil {
|
idx := x + y*segmentsX + frameOffset*segmentsX*segmentsY
|
||||||
|
if err := s.animation.SetCurrentFrame(idx); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,7 @@ type TextBox struct {
|
|||||||
|
|
||||||
// NewTextbox creates a new instance of a text box
|
// NewTextbox creates a new instance of a text box
|
||||||
func (ui *UIManager) NewTextbox() *TextBox {
|
func (ui *UIManager) NewTextbox() *TextBox {
|
||||||
animation, _ := ui.asset.LoadAnimation(d2resource.TextBox2, d2resource.PaletteUnits)
|
bgSprite, _ := ui.NewSprite(d2resource.TextBox2, d2resource.PaletteUnits)
|
||||||
bgSprite, _ := ui.NewSprite(animation)
|
|
||||||
tb := &TextBox{
|
tb := &TextBox{
|
||||||
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
bgSprite: bgSprite,
|
bgSprite: bgSprite,
|
||||||
|
@ -138,10 +138,8 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
|||||||
|
|
||||||
loading.Progress(tenPercent)
|
loading.Progress(tenPercent)
|
||||||
|
|
||||||
animation, _ := v.asset.LoadAnimation(d2resource.CharacterSelectionBackground,
|
|
||||||
d2resource.PaletteSky)
|
|
||||||
bgX, bgY := 0, 0
|
bgX, bgY := 0, 0
|
||||||
v.background, _ = v.uiManager.NewSprite(animation)
|
v.background, _ = v.uiManager.NewSprite(d2resource.CharacterSelectionBackground, d2resource.PaletteSky)
|
||||||
v.background.SetPosition(bgX, bgY)
|
v.background.SetPosition(bgX, bgY)
|
||||||
|
|
||||||
v.createButtons(loading)
|
v.createButtons(loading)
|
||||||
@ -160,14 +158,11 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
|
|||||||
deleteConfirmX, deleteConfirmY := 400, 185
|
deleteConfirmX, deleteConfirmY := 400, 185
|
||||||
v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY)
|
v.deleteCharConfirmLabel.SetPosition(deleteConfirmX, deleteConfirmY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.CharacterSelectionSelectBox,
|
v.selectionBox, _ = v.uiManager.NewSprite(d2resource.CharacterSelectionSelectBox, d2resource.PaletteSky)
|
||||||
d2resource.PaletteSky)
|
|
||||||
v.selectionBox, _ = v.uiManager.NewSprite(animation)
|
|
||||||
selBoxX, selBoxY := 37, 86
|
selBoxX, selBoxY := 37, 86
|
||||||
v.selectionBox.SetPosition(selBoxX, selBoxY)
|
v.selectionBox.SetPosition(selBoxX, selBoxY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
v.okCancelBox, _ = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||||
v.okCancelBox, _ = v.uiManager.NewSprite(animation)
|
|
||||||
okCancelX, okCancelY := 270, 175
|
okCancelX, okCancelY := 270, 175
|
||||||
v.okCancelBox.SetPosition(okCancelX, okCancelY)
|
v.okCancelBox.SetPosition(okCancelX, okCancelY)
|
||||||
|
|
||||||
|
@ -89,8 +89,7 @@ func (v *Credits) LoadContributors() []string {
|
|||||||
|
|
||||||
// OnLoad is called to load the resources for the credits screen
|
// OnLoad is called to load the resources for the credits screen
|
||||||
func (v *Credits) OnLoad(loading d2screen.LoadingState) {
|
func (v *Credits) OnLoad(loading d2screen.LoadingState) {
|
||||||
animation, _ := v.asset.LoadAnimation(d2resource.CreditsBackground, d2resource.PaletteSky)
|
v.creditsBackground, _ = v.uiManager.NewSprite(d2resource.CreditsBackground, d2resource.PaletteSky)
|
||||||
v.creditsBackground, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.creditsBackground.SetPosition(creditsX, creditsY)
|
v.creditsBackground.SetPosition(creditsX, creditsY)
|
||||||
loading.Progress(twentyPercent)
|
loading.Progress(twentyPercent)
|
||||||
|
|
||||||
|
@ -172,20 +172,16 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) loadBackgroundSprites() {
|
func (v *MainMenu) loadBackgroundSprites() {
|
||||||
animation, _ := v.asset.LoadAnimation(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
v.background, _ = v.uiManager.NewSprite(d2resource.GameSelectScreen, d2resource.PaletteSky)
|
||||||
v.background, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.background.SetPosition(backgroundX, backgroundY)
|
v.background.SetPosition(backgroundX, backgroundY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
v.trademarkBackground, _ = v.uiManager.NewSprite(d2resource.TrademarkScreen, d2resource.PaletteSky)
|
||||||
v.trademarkBackground, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.trademarkBackground.SetPosition(backgroundX, backgroundY)
|
v.trademarkBackground.SetPosition(backgroundX, backgroundY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.TCPIPBackground, d2resource.PaletteSky)
|
v.tcpIPBackground, _ = v.uiManager.NewSprite(d2resource.TCPIPBackground, d2resource.PaletteSky)
|
||||||
v.tcpIPBackground, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
|
v.tcpIPBackground.SetPosition(backgroundX, backgroundY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
v.serverIPBackground, _ = v.uiManager.NewSprite(d2resource.PopUpOkCancel, d2resource.PaletteFechar)
|
||||||
v.serverIPBackground, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
|
v.serverIPBackground.SetPosition(serverIPbackgroundX, serverIPbackgroundY)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,25 +232,21 @@ func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
|
||||||
animation, _ := v.asset.LoadAnimation(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
v.diabloLogoLeft, _ = v.uiManager.NewSprite(d2resource.Diablo2LogoFireLeft, d2resource.PaletteUnits)
|
||||||
v.diabloLogoLeft, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
|
v.diabloLogoLeft.SetEffect(d2enum.DrawEffectModulate)
|
||||||
v.diabloLogoLeft.PlayForward()
|
v.diabloLogoLeft.PlayForward()
|
||||||
v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
|
v.diabloLogoLeft.SetPosition(diabloLogoX, diabloLogoY)
|
||||||
loading.Progress(sixtyPercent)
|
loading.Progress(sixtyPercent)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
|
v.diabloLogoRight, _ = v.uiManager.NewSprite(d2resource.Diablo2LogoFireRight, d2resource.PaletteUnits)
|
||||||
v.diabloLogoRight, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
|
v.diabloLogoRight.SetEffect(d2enum.DrawEffectModulate)
|
||||||
v.diabloLogoRight.PlayForward()
|
v.diabloLogoRight.PlayForward()
|
||||||
v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
|
v.diabloLogoRight.SetPosition(diabloLogoX, diabloLogoY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
|
v.diabloLogoLeftBack, _ = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackLeft, d2resource.PaletteUnits)
|
||||||
v.diabloLogoLeftBack, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
|
v.diabloLogoLeftBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||||
|
|
||||||
animation, _ = v.asset.LoadAnimation(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
v.diabloLogoRightBack, _ = v.uiManager.NewSprite(d2resource.Diablo2LogoBlackRight, d2resource.PaletteUnits)
|
||||||
v.diabloLogoRightBack, _ = v.uiManager.NewSprite(animation)
|
|
||||||
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
|
v.diabloLogoRightBack.SetPosition(diabloLogoX, diabloLogoY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -734,29 +734,23 @@ func (v *SelectHeroClass) loadSprite(animationPath string, position image.Point,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
animation, err := v.asset.LoadAnimation(animationPath, d2resource.PaletteFechar)
|
sprite, err := v.uiManager.NewSprite(animationPath, d2resource.PaletteFechar)
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("could not load animation: %s\n", animationPath)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
animation.PlayForward()
|
|
||||||
animation.SetPlayLoop(playLoop)
|
|
||||||
|
|
||||||
if blend {
|
|
||||||
animation.SetEffect(d2enum.DrawEffectModulate)
|
|
||||||
}
|
|
||||||
|
|
||||||
if playLength != 0 {
|
|
||||||
animation.SetPlayLengthMs(playLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
sprite, err := v.uiManager.NewSprite(animation)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("could not load sprite for the animation: %s\n", animationPath)
|
fmt.Printf("could not load sprite for the animation: %s\n", animationPath)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sprite.PlayForward()
|
||||||
|
sprite.SetPlayLoop(playLoop)
|
||||||
|
|
||||||
|
if blend {
|
||||||
|
sprite.SetEffect(d2enum.DrawEffectModulate)
|
||||||
|
}
|
||||||
|
|
||||||
|
if playLength != 0 {
|
||||||
|
sprite.SetPlayLengthMs(playLength)
|
||||||
|
}
|
||||||
|
|
||||||
sprite.SetPosition(position.X, position.Y)
|
sprite.SetPosition(position.X, position.Y)
|
||||||
|
|
||||||
return sprite
|
return sprite
|
||||||
|
@ -381,21 +381,16 @@ func (g *GameControls) OnMouseButtonDown(event d2interface.MouseEvent) bool {
|
|||||||
|
|
||||||
// Load the resources required for the GameControls
|
// Load the resources required for the GameControls
|
||||||
func (g *GameControls) Load() {
|
func (g *GameControls) Load() {
|
||||||
animation, _ := g.asset.LoadAnimation(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
g.globeSprite, _ = g.uiManager.NewSprite(d2resource.GameGlobeOverlap, d2resource.PaletteSky)
|
||||||
g.globeSprite, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = g.asset.LoadAnimation(d2resource.HealthManaIndicator, d2resource.PaletteSky)
|
g.hpManaStatusSprite, _ = g.uiManager.NewSprite(d2resource.HealthManaIndicator, d2resource.PaletteSky)
|
||||||
g.hpManaStatusSprite, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = g.asset.LoadAnimation(d2resource.GamePanels, d2resource.PaletteSky)
|
g.mainPanel, _ = g.uiManager.NewSprite(d2resource.GamePanels, d2resource.PaletteSky)
|
||||||
g.mainPanel, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = g.asset.LoadAnimation(d2resource.MenuButton, d2resource.PaletteSky)
|
g.menuButton, _ = g.uiManager.NewSprite(d2resource.MenuButton, d2resource.PaletteSky)
|
||||||
_ = animation.SetCurrentFrame(2)
|
_ = g.menuButton.SetCurrentFrame(2)
|
||||||
g.menuButton, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = g.asset.LoadAnimation(d2resource.GenericSkills, d2resource.PaletteSky)
|
g.skillIcon, _ = g.uiManager.NewSprite(d2resource.GenericSkills, d2resource.PaletteSky)
|
||||||
g.skillIcon, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
g.loadUIButtons()
|
g.loadUIButtons()
|
||||||
|
|
||||||
|
@ -94,9 +94,8 @@ func (h *Overlay) Load() {
|
|||||||
prevY = 0
|
prevY = 0
|
||||||
)
|
)
|
||||||
for frameIndex := 0; frameIndex < 7; frameIndex++ {
|
for frameIndex := 0; frameIndex < 7; frameIndex++ {
|
||||||
animation, _ := h.asset.LoadAnimation(d2resource.HelpBorder, d2resource.PaletteSky)
|
f, _ := h.uiManager.NewSprite(d2resource.HelpBorder, d2resource.PaletteSky)
|
||||||
_ = animation.SetCurrentFrame(frameIndex)
|
_ = f.SetCurrentFrame(frameIndex)
|
||||||
f, _ := h.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
ww, hh := f.GetCurrentFrameSize()
|
ww, hh := f.GetCurrentFrameSize()
|
||||||
//fmt.Printf("Help frame %d size: %d, %d\n", frameIndex, ww, hh)
|
//fmt.Printf("Help frame %d size: %d, %d\n", frameIndex, ww, hh)
|
||||||
@ -143,9 +142,7 @@ func (h *Overlay) Load() {
|
|||||||
h.text = append(h.text, newLabel)
|
h.text = append(h.text, newLabel)
|
||||||
|
|
||||||
// Close
|
// Close
|
||||||
|
close, _ := h.uiManager.NewSprite(d2resource.SquareButton, d2resource.PaletteSky)
|
||||||
anim, _ := h.asset.LoadAnimation(d2resource.SquareButton, d2resource.PaletteSky)
|
|
||||||
close, _ := h.uiManager.NewSprite(anim)
|
|
||||||
_ = close.SetCurrentFrame(0)
|
_ = close.SetCurrentFrame(0)
|
||||||
close.SetPosition(685, 57)
|
close.SetPosition(685, 57)
|
||||||
h.frames = append(h.frames, close)
|
h.frames = append(h.frames, close)
|
||||||
@ -344,8 +341,7 @@ func (h *Overlay) createBullet(c callout) {
|
|||||||
newLabel.SetPosition(c.LabelX, c.LabelY)
|
newLabel.SetPosition(c.LabelX, c.LabelY)
|
||||||
h.text = append(h.text, newLabel)
|
h.text = append(h.text, newLabel)
|
||||||
|
|
||||||
anim, _ := h.asset.LoadAnimation(d2resource.HelpYellowBullet, d2resource.PaletteSky)
|
newDot, _ := h.uiManager.NewSprite(d2resource.HelpYellowBullet, d2resource.PaletteSky)
|
||||||
newDot, _ := h.uiManager.NewSprite(anim)
|
|
||||||
_ = newDot.SetCurrentFrame(0)
|
_ = newDot.SetCurrentFrame(0)
|
||||||
newDot.SetPosition(c.DotX, c.DotY+14)
|
newDot.SetPosition(c.DotX, c.DotY+14)
|
||||||
h.frames = append(h.frames, newDot)
|
h.frames = append(h.frames, newDot)
|
||||||
@ -370,8 +366,7 @@ func (h *Overlay) createCallout(c callout) {
|
|||||||
}
|
}
|
||||||
h.lines = append(h.lines, l)
|
h.lines = append(h.lines, l)
|
||||||
|
|
||||||
anim, _ := h.asset.LoadAnimation(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
|
newDot, _ := h.uiManager.NewSprite(d2resource.HelpWhiteBullet, d2resource.PaletteSky)
|
||||||
newDot, _ := h.uiManager.NewSprite(anim)
|
|
||||||
_ = newDot.SetCurrentFrame(0)
|
_ = newDot.SetCurrentFrame(0)
|
||||||
newDot.SetPosition(c.DotX, c.DotY)
|
newDot.SetPosition(c.DotX, c.DotY)
|
||||||
h.frames = append(h.frames, newDot)
|
h.frames = append(h.frames, newDot)
|
||||||
|
@ -78,10 +78,8 @@ func NewHeroStatsPanel(asset *d2asset.AssetManager, ui *d2ui.UIManager, heroName
|
|||||||
|
|
||||||
// Load the data for the hero status panel
|
// Load the data for the hero status panel
|
||||||
func (s *HeroStatsPanel) Load() {
|
func (s *HeroStatsPanel) Load() {
|
||||||
animation, _ := s.asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
|
s.frame, _ = s.uiManager.NewSprite(d2resource.Frame, d2resource.PaletteSky)
|
||||||
s.frame, _ = s.uiManager.NewSprite(animation)
|
s.panel, _ = s.uiManager.NewSprite(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
||||||
animation, _ = s.asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
|
||||||
s.panel, _ = s.uiManager.NewSprite(animation)
|
|
||||||
s.initStatValueLabels()
|
s.initStatValueLabels()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +71,9 @@ func (g *Inventory) Close() {
|
|||||||
|
|
||||||
// Load the resources required by the inventory
|
// Load the resources required by the inventory
|
||||||
func (g *Inventory) Load() {
|
func (g *Inventory) Load() {
|
||||||
animation, _ := g.asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
|
g.frame, _ = g.uiManager.NewSprite(d2resource.Frame, d2resource.PaletteSky)
|
||||||
g.frame, _ = g.uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = g.asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
g.panel, _ = g.uiManager.NewSprite(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
|
||||||
g.panel, _ = g.uiManager.NewSprite(animation)
|
|
||||||
items := []InventoryItem{
|
items := []InventoryItem{
|
||||||
diablo2item.NewItem("kit", "Crimson", "of the Bat", "of Frost").Identify(),
|
diablo2item.NewItem("kit", "Crimson", "of the Bat", "of Frost").Identify(),
|
||||||
diablo2item.NewItem("rin", "Steel", "of Shock").Identify(),
|
diablo2item.NewItem("rin", "Steel", "of Shock").Identify(),
|
||||||
|
@ -121,17 +121,8 @@ func (g *ItemGrid) loadItem(item InventoryItem) {
|
|||||||
var itemSprite *d2ui.Sprite
|
var itemSprite *d2ui.Sprite
|
||||||
|
|
||||||
// TODO: Put the pattern into D2Shared
|
// TODO: Put the pattern into D2Shared
|
||||||
animation, err := g.asset.LoadAnimation(
|
imgPath := fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode())
|
||||||
fmt.Sprintf("/data/global/items/inv%s.dc6", item.GetItemCode()),
|
itemSprite, err := g.uiManager.NewSprite(imgPath, d2resource.PaletteSky)
|
||||||
d2resource.PaletteSky,
|
|
||||||
)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to load sprite for item (%s): %v", item.GetItemCode(), err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
itemSprite, err = g.uiManager.NewSprite(animation)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Failed to load sprite, error: " + err.Error())
|
log.Printf("Failed to load sprite, error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,9 @@ func newMiniPanel(asset *d2asset.AssetManager, uiManager *d2ui.UIManager, isSing
|
|||||||
miniPanelContainerPath = d2resource.MinipanelSmall
|
miniPanelContainerPath = d2resource.MinipanelSmall
|
||||||
}
|
}
|
||||||
|
|
||||||
animation, _ := asset.LoadAnimation(miniPanelContainerPath, d2resource.PaletteSky)
|
containerSprite, _ := uiManager.NewSprite(miniPanelContainerPath, d2resource.PaletteSky)
|
||||||
containerSprite, _ := uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
animation, _ = asset.LoadAnimation(d2resource.MinipanelButton, d2resource.PaletteSky)
|
buttonSprite, _ := uiManager.NewSprite(d2resource.MinipanelButton, d2resource.PaletteSky)
|
||||||
buttonSprite, _ := uiManager.NewSprite(animation)
|
|
||||||
|
|
||||||
rectangle := d2geom.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26}
|
rectangle := d2geom.Rectangle{Left: 325, Top: 526, Width: 156, Height: 26}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user