Render to surface, not ebiten texture (#268)

* Render to surface, not ebiten texture

* Fix debug text
This commit is contained in:
Alex Yatskov 2019-12-28 13:46:08 -08:00 committed by Tim Sarbin
parent 0c2b7cfd8d
commit 49b9a190f2
27 changed files with 280 additions and 201 deletions

View File

@ -9,7 +9,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2data/d2dc6"
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
"github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -192,18 +192,15 @@ func (a *Animation) Advance(elapsed float64) error {
return nil
}
func (a *Animation) Render(target *ebiten.Image, offsetX, offsetY int) error {
func (a *Animation) Render(target *d2surface.Surface) error {
direction := a.directions[a.directionIndex]
frame := direction.frames[a.frameIndex]
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(frame.offsetX+offsetX), float64(frame.offsetY+offsetY))
opts.CompositeMode = a.compositeMode
if a.colorMod != nil {
opts.ColorM = d2corehelper.ColorToColorM(a.colorMod)
}
return target.DrawImage(frame.image, opts)
target.PushTranslation(frame.offsetX, frame.offsetY)
target.PushCompositeMode(a.compositeMode)
target.PushColor(a.colorMod)
defer target.PopN(3)
return target.Render(frame.image)
}
func (a *Animation) GetFrameSize(frameIndex int) (int, int, error) {

View File

@ -9,7 +9,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2data"
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
"github.com/OpenDiablo2/D2Shared/d2data/d2dcc"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type Composite struct {
@ -45,7 +45,7 @@ func (c *Composite) Advance(elapsed float64) error {
return nil
}
func (c *Composite) Render(target *ebiten.Image, offsetX, offsetY int) error {
func (c *Composite) Render(target *d2surface.Surface) error {
if c.mode == nil {
return nil
}
@ -53,7 +53,7 @@ func (c *Composite) Render(target *ebiten.Image, offsetX, offsetY int) error {
for _, layerIndex := range c.mode.drawOrder[c.mode.frameIndex] {
layer := c.mode.layers[layerIndex]
if layer != nil {
if err := layer.Render(target, offsetX, offsetY); err != nil {
if err := layer.Render(target); err != nil {
return err
}
}

View File

@ -6,8 +6,6 @@ import (
"os"
"strings"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/OpenDiablo2/D2Shared/d2common"
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
dh "github.com/OpenDiablo2/D2Shared/d2helper"
@ -15,6 +13,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/d2corecommon/d2coreinterface"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
@ -195,7 +194,7 @@ func (v *CharacterSelect) onExitButtonClicked() {
func (v *CharacterSelect) Unload() {
}
func (v *CharacterSelect) Render(screen *ebiten.Image) {
func (v *CharacterSelect) Render(screen *d2surface.Surface) {
v.background.RenderSegmented(screen, 4, 3, 0)
v.d2HeroTitle.Render(screen)
actualSelectionIndex := v.selectedCharacter - (v.charScrollbar.GetCurrentOffset() * 2)
@ -210,10 +209,12 @@ func (v *CharacterSelect) Render(screen *ebiten.Image) {
v.characterNameLabel[i].Render(screen)
v.characterStatsLabel[i].Render(screen)
v.characterExpLabel[i].Render(screen)
v.characterImage[i].Render(screen, v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
screen.PushTranslation(v.characterNameLabel[i].X-40, v.characterNameLabel[i].Y+50)
v.characterImage[i].Render(screen)
screen.Pop()
}
if v.showDeleteConfirmation {
ebitenutil.DrawRect(screen, 0.0, 0.0, 800.0, 600.0, color.RGBA{0, 0, 0, 128})
screen.DrawRect(800, 600, color.RGBA{0, 0, 0, 128})
v.okCancelBox.RenderSegmented(screen, 2, 1, 0)
v.deleteCharConfirmLabel.Render(screen)
}

View File

@ -18,8 +18,8 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common"
dh "github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
type labelItem struct {
@ -107,7 +107,7 @@ func (v *Credits) Unload() {
}
// Render renders the credits scene
func (v *Credits) Render(screen *ebiten.Image) {
func (v *Credits) Render(screen *d2surface.Surface) {
v.creditsBackground.RenderSegmented(screen, 4, 3, 0)
for _, label := range v.labels {
if label.Available {

View File

@ -11,8 +11,8 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2player"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
type Game struct {
@ -87,8 +87,8 @@ func (v *Game) Load() []func() {
func (v *Game) Unload() {
}
func (v Game) Render(screen *ebiten.Image) {
screen.Fill(color.Black)
func (v Game) Render(screen *d2surface.Surface) {
screen.Clear(color.Black)
v.mapEngine.Render(screen)
v.gameControls.Render(screen)
}

View File

@ -18,9 +18,8 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
// MainMenu represents the main menu
@ -223,7 +222,7 @@ func (v *MainMenu) Unload() {
}
// Render renders the main menu
func (v *MainMenu) Render(screen *ebiten.Image) {
func (v *MainMenu) Render(screen *d2surface.Surface) {
if v.ShowTrademarkScreen {
v.trademarkBackground.RenderSegmented(screen, 4, 3, 0)
} else {

View File

@ -1,7 +1,6 @@
package d2scene
import (
"fmt"
"math"
"os"
@ -12,9 +11,9 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/hajimehoshi/ebiten/inpututil"
)
@ -160,7 +159,7 @@ func (v *MapEngineTest) Unload() {
}
func (v *MapEngineTest) Render(screen *ebiten.Image) {
func (v *MapEngineTest) Render(screen *d2surface.Surface) {
v.mapEngine.Render(screen)
screenX := v.uiManager.CursorX
screenY := v.uiManager.CursorY
@ -173,14 +172,6 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
}
tileRect := curRegion.GetTileRect()
line := fmt.Sprintf("%d, %d (Tile %d.%d, %d.%d)",
screenX,
screenY,
int(math.Floor(worldX))-tileRect.Left,
subtileX,
int(math.Floor(worldY))-tileRect.Top,
subtileY,
)
levelFilesToPick := make([]string, 0)
fileIndex := v.fileIndex
@ -199,12 +190,20 @@ func (v *MapEngineTest) Render(screen *ebiten.Image) {
v.fileIndex = fileIndex
}
v.filesCount = len(levelFilesToPick)
ebitenutil.DebugPrintAt(screen, line, 5, 5)
ebitenutil.DebugPrintAt(screen, "Map: "+curRegion.GetLevelType().Name, 5, 17)
ebitenutil.DebugPrintAt(screen, fmt.Sprintf("%v: %v/%v [%v, %v]", regionPath, fileIndex+1, v.filesCount, v.currentRegion, v.levelPreset), 5, 29)
ebitenutil.DebugPrintAt(screen, "N - next region, P - previous region", 5, 41)
ebitenutil.DebugPrintAt(screen, "Shift+N - next preset, Shift+P - previous preset", 5, 53)
ebitenutil.DebugPrintAt(screen, "Ctrl+N - next file, Ctrl+P - previous file", 5, 65)
screen.PushTranslation(5, 5)
screen.DrawText("%d, %d (Tile %d.%d, %d.%d)", screenX, screenY, int(math.Floor(worldX))-tileRect.Left, subtileX, int(math.Floor(worldY))-tileRect.Top, subtileY)
screen.PushTranslation(0, 16)
screen.DrawText("Map: " + curRegion.GetLevelType().Name)
screen.PushTranslation(0, 16)
screen.DrawText("%v: %v/%v [%v, %v]", regionPath, fileIndex+1, v.filesCount, v.currentRegion, v.levelPreset)
screen.PushTranslation(0, 16)
screen.DrawText("N - next region, P - previous region")
screen.PushTranslation(0, 16)
screen.DrawText("Shift+N - next preset, Shift+P - previous preset")
screen.PushTranslation(0, 16)
screen.DrawText("Ctrl+N - next file, Ctrl+P - previous file")
screen.PopN(6)
}
func (v *MapEngineTest) Update(tickTime float64) {

View File

@ -16,8 +16,8 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common"
dh "github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
)
type HeroRenderInfo struct {
@ -444,7 +444,7 @@ func (v SelectHeroClass) onOkButtonClicked() {
v.sceneProvider.SetNextScene(CreateGame(v.sceneProvider, v.uiManager, v.soundManager, gameState))
}
func (v *SelectHeroClass) Render(screen *ebiten.Image) {
func (v *SelectHeroClass) Render(screen *d2surface.Surface) {
v.bgImage.RenderSegmented(screen, 4, 3, 0)
v.headingLabel.Render(screen)
if v.selectedHero != d2enum.HeroNone {
@ -560,7 +560,7 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
}
func (v *SelectHeroClass) renderHero(screen *ebiten.Image, hero d2enum.Hero) {
func (v *SelectHeroClass) renderHero(screen *d2surface.Surface, hero d2enum.Hero) {
renderInfo := v.heroRenderInfo[hero]
switch renderInfo.Stance {
case d2enum.HeroStanceIdle:
@ -647,7 +647,7 @@ func setSpriteToFirstFrame(sprite *d2render.Sprite) {
}
}
func drawSprite(sprite *d2render.Sprite, target *ebiten.Image) {
func drawSprite(sprite *d2render.Sprite, target *d2surface.Surface) {
if sprite != nil {
sprite.Render(target)
}

View File

@ -28,7 +28,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2ui"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/hajimehoshi/ebiten/inpututil"
)
@ -176,30 +175,41 @@ func (v *Engine) Update() {
}
// Draw draws the game
func (v Engine) Draw(screen *ebiten.Image) {
func (v Engine) Draw(target *d2surface.Surface) {
if v.loadingProgress < 1.0 {
v.LoadingSprite.SetCurrentFrame(int(d2helper.Max(0, d2helper.Min(uint32(v.LoadingSprite.GetFrameCount()-1), uint32(float64(v.LoadingSprite.GetFrameCount()-1)*v.loadingProgress)))))
v.LoadingSprite.Render(screen)
v.LoadingSprite.Render(target)
} else {
if v.CurrentScene == nil {
log.Fatal("no scene loaded")
}
v.CurrentScene.Render(screen)
v.UIManager.Render(screen)
v.CurrentScene.Render(target)
v.UIManager.Render(target)
}
if v.showFPS {
ebitenutil.DebugPrintAt(screen, "vsync:"+strconv.FormatBool(ebiten.IsVsyncEnabled())+"\nFPS:"+strconv.Itoa(int(ebiten.CurrentFPS())), 5, 565)
target.PushTranslation(5, 565)
target.DrawText("vsync:" + strconv.FormatBool(ebiten.IsVsyncEnabled()) + "\nFPS:" + strconv.Itoa(int(ebiten.CurrentFPS())))
target.Pop()
cx, cy := ebiten.CursorPosition()
var m runtime.MemStats
runtime.ReadMemStats(&m)
ebitenutil.DebugPrintAt(screen, "Alloc "+strconv.FormatInt(int64(m.Alloc)/1024/1024, 10), 680, 0)
ebitenutil.DebugPrintAt(screen, "Pause "+strconv.FormatInt(int64(m.PauseTotalNs/1024/1024), 10), 680, 10)
ebitenutil.DebugPrintAt(screen, "HeapSys "+strconv.FormatInt(int64(m.HeapSys/1024/1024), 10), 680, 20)
ebitenutil.DebugPrintAt(screen, "NumGC "+strconv.FormatInt(int64(m.NumGC), 10), 680, 30)
cx, cy := ebiten.CursorPosition()
ebitenutil.DebugPrintAt(screen, "Coords "+strconv.FormatInt(int64(cx), 10)+","+strconv.FormatInt(int64(cy), 10), 680, 40)
target.PushTranslation(680, 0)
target.DrawText("Alloc " + strconv.FormatInt(int64(m.Alloc)/1024/1024, 10))
target.PushTranslation(0, 16)
target.DrawText("Pause " + strconv.FormatInt(int64(m.PauseTotalNs/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("HeapSys " + strconv.FormatInt(int64(m.HeapSys/1024/1024), 10))
target.PushTranslation(0, 16)
target.DrawText("NumGC " + strconv.FormatInt(int64(m.NumGC), 10))
target.PushTranslation(0, 16)
target.DrawText("Coords " + strconv.FormatInt(int64(cx), 10) + "," + strconv.FormatInt(int64(cy), 10))
target.PopN(5)
}
d2term.Render(d2surface.CreateSurface(screen))
d2term.Render(target)
}
// SetNextScene tells the engine what scene to load on the next update cycle

View File

@ -5,7 +5,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type Hero struct {
@ -52,8 +52,8 @@ func (v *Hero) Advance(tickTime float64) {
v.AnimatedEntity.Advance(tickTime)
}
func (v *Hero) Render(target *ebiten.Image, offsetX, offsetY int) {
v.AnimatedEntity.Render(target, offsetX, offsetY)
func (v *Hero) Render(target *d2surface.Surface) {
v.AnimatedEntity.Render(target)
}
func (v *Hero) GetPosition() (float64, float64) {

View File

@ -5,7 +5,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type NPC struct {
@ -44,8 +44,8 @@ func (v *NPC) SetPaths(paths []d2common.Path) {
v.HasPaths = len(paths) > 0
}
func (v *NPC) Render(target *ebiten.Image, offsetX, offsetY int) {
v.AnimatedEntity.Render(target, offsetX, offsetY)
func (v *NPC) Render(target *d2surface.Surface) {
v.AnimatedEntity.Render(target)
}
func (v *NPC) GetPosition() (float64, float64) {

View File

@ -1,10 +1,10 @@
package d2coreinterface
import "github.com/hajimehoshi/ebiten"
import "github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
// Drawable represents an instance that can be drawn
type Drawable interface {
Render(target *ebiten.Image)
Render(target *d2surface.Surface)
GetSize() (width, height int)
SetPosition(x, y int)
GetPosition() (x, y int)

View File

@ -1,13 +1,11 @@
package d2coreinterface
import (
"github.com/hajimehoshi/ebiten"
)
import "github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
// Scene defines the function necessary for scene management
type Scene interface {
Load() []func()
Unload()
Render(screen *ebiten.Image)
Render(target *d2surface.Surface)
Update(tickTime float64)
}

View File

@ -5,6 +5,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -67,8 +68,8 @@ func (g *GameControls) Load() {
}
// TODO: consider caching the panels to single image that is reused.
func (g *GameControls) Render(target *ebiten.Image) {
width, height := target.Size()
func (g *GameControls) Render(target *d2surface.Surface) {
width, height := target.GetSize()
offset := int(0)
// Left globe holder

View File

@ -8,7 +8,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2data/d2datadict"
"github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
// AnimatedEntity represents an entity on the map that can be animated
@ -70,14 +70,13 @@ func (v AnimatedEntity) Wait() bool {
}
// Render draws this animated entity onto the target
func (v *AnimatedEntity) Render(target *ebiten.Image, offsetX, offsetY int) {
localX := (v.subcellX - v.subcellY) * 16
localY := ((v.subcellX + v.subcellY) * 8) - 5
v.composite.Render(
target,
int(v.offsetX)+offsetX+int(localX),
int(v.offsetY)+offsetY+int(localY),
func (v *AnimatedEntity) Render(target *d2surface.Surface) {
target.PushTranslation(
int(v.offsetX)+int((v.subcellX-v.subcellY)*16),
int(v.offsetY)+int(((v.subcellX+v.subcellY)*8)-5),
)
defer target.Pop()
v.composite.Render(target)
}
func (v AnimatedEntity) GetDirection() int {

View File

@ -3,17 +3,16 @@ package d2mapengine
import (
"strings"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type MapEntity interface {
Render(target *ebiten.Image, screenX, screenY int)
GetPosition() (float64, float64)
Render(target *d2surface.Surface)
Advance(tickTime float64)
GetPosition() (float64, float64)
}
type MapEngine struct {
@ -134,7 +133,7 @@ func (me *MapEngine) Advance(tickTime float64) {
}
}
func (me *MapEngine) Render(target *ebiten.Image) {
func (me *MapEngine) Render(target *d2surface.Surface) {
for _, region := range me.regions {
if region.isVisbile(me.viewport) {
region.renderPass1(me.viewport, target)

View File

@ -1,7 +1,6 @@
package d2mapengine
import (
"fmt"
"image/color"
"log"
"math"
@ -9,7 +8,6 @@ import (
"strconv"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
"github.com/OpenDiablo2/D2Shared/d2common"
"github.com/OpenDiablo2/D2Shared/d2common/d2enum"
@ -20,8 +18,8 @@ import (
"github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core"
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type MapRegion struct {
@ -234,7 +232,7 @@ func (mr *MapRegion) getTileWorldPosition(tileX, tileY int) (float64, float64) {
return float64(tileX + mr.tileRect.Left), float64(tileY + mr.tileRect.Top)
}
func (mr *MapRegion) renderPass1(viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderPass1(viewport *Viewport, target *d2surface.Surface) {
for tileY := range mr.ds1.Tiles {
for tileX, tile := range mr.ds1.Tiles[tileY] {
worldX, worldY := mr.getTileWorldPosition(tileX, tileY)
@ -247,7 +245,7 @@ func (mr *MapRegion) renderPass1(viewport *Viewport, target *ebiten.Image) {
}
}
func (mr *MapRegion) renderPass2(entities []MapEntity, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderPass2(entities []MapEntity, viewport *Viewport, target *d2surface.Surface) {
for tileY := range mr.ds1.Tiles {
for tileX, tile := range mr.ds1.Tiles[tileY] {
worldX, worldY := mr.getTileWorldPosition(tileX, tileY)
@ -258,8 +256,9 @@ func (mr *MapRegion) renderPass2(entities []MapEntity, viewport *Viewport, targe
for _, entity := range entities {
entWorldX, entWorldY := entity.GetPosition()
if entWorldX == worldX && entWorldY == worldY {
screenX, screenY := viewport.GetTranslationScreen()
entity.Render(target, screenX, screenY)
target.PushTranslation(viewport.GetTranslationScreen())
entity.Render(target)
target.Pop()
}
}
@ -269,7 +268,7 @@ func (mr *MapRegion) renderPass2(entities []MapEntity, viewport *Viewport, targe
}
}
func (mr *MapRegion) renderPass3(viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderPass3(viewport *Viewport, target *d2surface.Surface) {
for tileY := range mr.ds1.Tiles {
for tileX, tile := range mr.ds1.Tiles[tileY] {
worldX, worldY := mr.getTileWorldPosition(tileX, tileY)
@ -282,7 +281,7 @@ func (mr *MapRegion) renderPass3(viewport *Viewport, target *ebiten.Image) {
}
}
func (mr *MapRegion) renderTilePass1(tile d2ds1.TileRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderTilePass1(tile d2ds1.TileRecord, viewport *Viewport, target *d2surface.Surface) {
for _, wall := range tile.Walls {
if !wall.Hidden && wall.Prop1 != 0 && wall.Type.LowerWall() {
mr.renderWall(wall, viewport, target)
@ -302,7 +301,7 @@ func (mr *MapRegion) renderTilePass1(tile d2ds1.TileRecord, viewport *Viewport,
}
}
func (mr *MapRegion) renderTilePass2(tile d2ds1.TileRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderTilePass2(tile d2ds1.TileRecord, viewport *Viewport, target *d2surface.Surface) {
for _, wall := range tile.Walls {
if !wall.Hidden && wall.Type.UpperWall() {
mr.renderWall(wall, viewport, target)
@ -310,7 +309,7 @@ func (mr *MapRegion) renderTilePass2(tile d2ds1.TileRecord, viewport *Viewport,
}
}
func (mr *MapRegion) renderTilePass3(tile d2ds1.TileRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderTilePass3(tile d2ds1.TileRecord, viewport *Viewport, target *d2surface.Surface) {
for _, wall := range tile.Walls {
if wall.Type == d2enum.Roof {
mr.renderWall(wall, viewport, target)
@ -318,7 +317,7 @@ func (mr *MapRegion) renderTilePass3(tile d2ds1.TileRecord, viewport *Viewport,
}
}
func (mr *MapRegion) renderFloor(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderFloor(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *d2surface.Surface) {
var img *ebiten.Image
if !tile.Animated {
img = mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tile.RandomIndex)
@ -331,14 +330,15 @@ func (mr *MapRegion) renderFloor(tile d2ds1.FloorShadowRecord, viewport *Viewpor
}
viewport.PushTranslationOrtho(-80, float64(tile.YAdjust))
screenX, screenY := viewport.GetTranslationScreen()
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(screenX), float64(screenY))
target.DrawImage(img, opts)
viewport.PopTranslation()
defer viewport.PopTranslation()
target.PushTranslation(viewport.GetTranslationScreen())
defer target.Pop()
target.Render(img)
}
func (mr *MapRegion) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderWall(tile d2ds1.WallRecord, viewport *Viewport, target *d2surface.Surface) {
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
if img == nil {
log.Printf("Render called on uncached wall {%v,%v,%v}", tile.Style, tile.Sequence, tile.Type)
@ -346,14 +346,15 @@ func (mr *MapRegion) renderWall(tile d2ds1.WallRecord, viewport *Viewport, targe
}
viewport.PushTranslationOrtho(-80, float64(tile.YAdjust))
screenX, screenY := viewport.GetTranslationScreen()
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(screenX), float64(screenY))
target.DrawImage(img, opts)
viewport.PopTranslation()
defer viewport.PopTranslation()
target.PushTranslation(viewport.GetTranslationScreen())
defer target.Pop()
target.Render(img)
}
func (mr *MapRegion) renderShadow(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderShadow(tile d2ds1.FloorShadowRecord, viewport *Viewport, target *d2surface.Surface) {
img := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tile.RandomIndex)
if img == nil {
log.Printf("Render called on uncached shadow {%v,%v}", tile.Style, tile.Sequence)
@ -361,15 +362,16 @@ func (mr *MapRegion) renderShadow(tile d2ds1.FloorShadowRecord, viewport *Viewpo
}
viewport.PushTranslationOrtho(-80, float64(tile.YAdjust))
screenX, screenY := viewport.GetTranslationScreen()
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(screenX), float64(screenY))
opts.ColorM = d2corehelper.ColorToColorM(color.RGBA{255, 255, 255, 160})
target.DrawImage(img, opts)
viewport.PopTranslation()
defer viewport.PopTranslation()
target.PushTranslation(viewport.GetTranslationScreen())
target.PushColor(color.RGBA{255, 255, 255, 160})
defer target.PopN(2)
target.Render(img)
}
func (mr *MapRegion) renderDebug(debugVisLevel int, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderDebug(debugVisLevel int, viewport *Viewport, target *d2surface.Surface) {
for tileY := range mr.ds1.Tiles {
for tileX := range mr.ds1.Tiles[tileY] {
worldX, worldY := mr.getTileWorldPosition(tileX, tileY)
@ -380,7 +382,7 @@ func (mr *MapRegion) renderDebug(debugVisLevel int, viewport *Viewport, target *
}
}
func (mr *MapRegion) renderTileDebug(x, y int, debugVisLevel int, viewport *Viewport, target *ebiten.Image) {
func (mr *MapRegion) renderTileDebug(x, y int, debugVisLevel int, viewport *Viewport, target *d2surface.Surface) {
if debugVisLevel > 0 {
subtileColor := color.RGBA{80, 80, 255, 100}
tileColor := color.RGBA{255, 255, 255, 255}
@ -389,22 +391,34 @@ func (mr *MapRegion) renderTileDebug(x, y int, debugVisLevel int, viewport *View
screenX2, screenY2 := viewport.WorldToScreen(float64(x+1), float64(y))
screenX3, screenY3 := viewport.WorldToScreen(float64(x), float64(y+1))
ebitenutil.DrawLine(target, float64(screenX1), float64(screenY1), float64(screenX2), float64(screenY2), tileColor)
ebitenutil.DrawLine(target, float64(screenX1), float64(screenY1), float64(screenX3), float64(screenY3), tileColor)
ebitenutil.DebugPrintAt(target, fmt.Sprintf("%v,%v", x, y), screenX1-10, screenY1+10)
target.PushTranslation(screenX1, screenY1)
defer target.Pop()
target.DrawLine(screenX2-screenX1, screenY2-screenY1, tileColor)
target.DrawLine(screenX3-screenX1, screenY3-screenY1, tileColor)
target.PushTranslation(-10, 10)
target.DrawText("%v, %v", x, y)
target.Pop()
if debugVisLevel > 1 {
for i := 1; i <= 4; i++ {
x := i * 16
y := i * 8
ebitenutil.DrawLine(target, float64(screenX1-x), float64(screenY1+y), float64(screenX1-x+80), float64(screenY1+y+40), subtileColor)
ebitenutil.DrawLine(target, float64(screenX1+x), float64(screenY1+y), float64(screenX1+x-80), float64(screenY1+y+40), subtileColor)
target.PushTranslation(-x, y)
target.DrawLine(80, 40, subtileColor)
target.Pop()
target.PushTranslation(x, y)
target.DrawLine(-80, 40, subtileColor)
target.Pop()
}
tile := mr.ds1.Tiles[y][x]
for i := range tile.Floors {
ebitenutil.DebugPrintAt(target, fmt.Sprintf("f: %v-%v", tile.Floors[i].Style, tile.Floors[i].Sequence), screenX1-20, screenY1+10+(i+1)*14)
for i, floor := range tile.Floors {
target.PushTranslation(-20, 10+(i+1)*14)
target.DrawText("f: %v-%v", floor.Style, floor.Sequence)
target.Pop()
}
}
}

View File

@ -1,16 +1,20 @@
package d2surface
import (
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
"github.com/hajimehoshi/ebiten"
"github.com/hajimehoshi/ebiten/ebitenutil"
)
type surfaceState struct {
x int
y int
mode ebiten.CompositeMode
x int
y int
mode ebiten.CompositeMode
filter ebiten.Filter
color color.Color
}
type Surface struct {
@ -23,7 +27,8 @@ func CreateSurface(image *ebiten.Image) *Surface {
return &Surface{
image: image,
stateCurrent: surfaceState{
mode: ebiten.CompositeModeSourceOver,
filter: ebiten.FilterNearest,
mode: ebiten.CompositeModeSourceOver,
},
}
}
@ -39,6 +44,16 @@ func (s *Surface) PushCompositeMode(mode ebiten.CompositeMode) {
s.stateCurrent.mode = mode
}
func (s *Surface) PushFilter(filter ebiten.Filter) {
s.stateStack = append(s.stateStack, s.stateCurrent)
s.stateCurrent.filter = filter
}
func (s *Surface) PushColor(color color.Color) {
s.stateStack = append(s.stateStack, s.stateCurrent)
s.stateCurrent.color = color
}
func (s *Surface) Pop() {
count := len(s.stateStack)
if count == 0 {
@ -49,14 +64,36 @@ func (s *Surface) Pop() {
s.stateStack = s.stateStack[:count-1]
}
func (s *Surface) PopN(n int) {
for i := 0; i < n; i++ {
s.Pop()
}
}
func (s *Surface) Render(image *ebiten.Image) error {
opts := &ebiten.DrawImageOptions{CompositeMode: s.stateCurrent.mode}
opts.GeoM.Translate(float64(s.stateCurrent.x), float64(s.stateCurrent.y))
opts.Filter = s.stateCurrent.filter
if s.stateCurrent.color != nil {
opts.ColorM = d2corehelper.ColorToColorM(s.stateCurrent.color)
}
return s.image.DrawImage(image, opts)
}
func (s *Surface) DrawText(text string) {
ebitenutil.DebugPrintAt(s.image, text, s.stateCurrent.x, s.stateCurrent.y)
func (s *Surface) DrawText(format string, params ...interface{}) {
ebitenutil.DebugPrintAt(s.image, fmt.Sprintf(format, params...), s.stateCurrent.x, s.stateCurrent.y)
}
func (s *Surface) DrawLine(x, y int, color color.Color) {
ebitenutil.DrawLine(
s.image,
float64(s.stateCurrent.x),
float64(s.stateCurrent.y),
float64(s.stateCurrent.x+x),
float64(s.stateCurrent.y+y),
color,
)
}
func (s *Surface) DrawRect(width, height int, color color.Color) {
@ -70,6 +107,14 @@ func (s *Surface) DrawRect(width, height int, color color.Color) {
)
}
func (s *Surface) Clear(color color.Color) error {
return s.image.Fill(color)
}
func (s *Surface) GetSize() (int, int) {
return s.image.Size()
}
func (s *Surface) GetDepth() int {
return len(s.stateStack)
}

View File

@ -3,6 +3,7 @@ package d2ui
import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -72,7 +73,7 @@ func (v Scrollbar) GetLastDirChange() int {
return v.lastDirChange
}
func (v *Scrollbar) Render(target *ebiten.Image) {
func (v *Scrollbar) Render(target *d2surface.Surface) {
if !v.visible || v.maxOffset == 0 {
return
}

View File

@ -6,8 +6,8 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2corehelper"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -127,33 +127,38 @@ func CreateButton(buttonType ButtonType, text string) Button {
}
result.normalImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
normalSurface := d2surface.CreateSurface(result.normalImage)
_, fontHeight := font.GetTextMetrics(text)
textY := int((result.height/2)-(int(fontHeight)/2)) + buttonLayout.TextOffset
buttonSprite.SetPosition(0, 0)
buttonSprite.SetBlend(true)
buttonSprite.RenderSegmented(result.normalImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.normalImage)
buttonSprite.RenderSegmented(normalSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, normalSurface)
if buttonLayout.AllowFrameChange {
if totalButtonTypes > 1 {
result.pressedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
buttonSprite.RenderSegmented(result.pressedImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
font.Render(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, result.pressedImage)
pressedSurface := d2surface.CreateSurface(result.pressedImage)
buttonSprite.RenderSegmented(pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
font.Render(-2, textY+2, text, color.RGBA{100, 100, 100, 255}, pressedSurface)
}
if totalButtonTypes > 2 {
result.toggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
buttonSprite.RenderSegmented(result.toggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.toggledImage)
toggledSurface := d2surface.CreateSurface(result.toggledImage)
buttonSprite.RenderSegmented(toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, toggledSurface)
}
if totalButtonTypes > 3 {
result.pressedToggledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
buttonSprite.RenderSegmented(result.pressedToggledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.pressedToggledImage)
pressedToggledSurface := d2surface.CreateSurface(result.pressedToggledImage)
buttonSprite.RenderSegmented(pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, pressedToggledSurface)
}
if buttonLayout.DisabledFrame != -1 {
result.disabledImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
buttonSprite.RenderSegmented(result.disabledImage, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, result.disabledImage)
disabledSurface := d2surface.CreateSurface(result.disabledImage)
buttonSprite.RenderSegmented(disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
font.Render(0, textY, text, color.RGBA{100, 100, 100, 255}, disabledSurface)
}
}
return result
@ -173,25 +178,24 @@ func (v *Button) Activate() {
}
// Render renders the button
func (v Button) Render(target *ebiten.Image) {
opts := &ebiten.DrawImageOptions{
CompositeMode: ebiten.CompositeModeSourceAtop,
Filter: ebiten.FilterNearest,
}
opts.GeoM.Translate(float64(v.x), float64(v.y))
func (v Button) Render(target *d2surface.Surface) {
target.PushCompositeMode(ebiten.CompositeModeSourceAtop)
target.PushFilter(ebiten.FilterNearest)
target.PushTranslation(v.x, v.y)
defer target.PopN(3)
if !v.enabled {
//opts.CompositeMode = ebiten.CompositeModeLighter
opts.ColorM = d2corehelper.ColorToColorM(color.RGBA{128, 128, 128, 195})
target.DrawImage(v.disabledImage, opts)
target.PushColor(color.RGBA{128, 128, 128, 195})
defer target.Pop()
target.Render(v.disabledImage)
} else if v.toggled && v.pressed {
target.DrawImage(v.pressedToggledImage, opts)
target.Render(v.pressedToggledImage)
} else if v.pressed {
target.DrawImage(v.pressedImage, opts)
target.Render(v.pressedImage)
} else if v.toggled {
target.DrawImage(v.toggledImage, opts)
target.Render(v.toggledImage)
} else {
target.DrawImage(v.normalImage, opts)
target.Render(v.normalImage)
}
}

View File

@ -3,6 +3,7 @@ package d2ui
import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -30,23 +31,25 @@ func CreateCheckbox(checkState bool) Checkbox {
checkboxSprite.SetPosition(0, 0)
result.Image, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
checkboxSprite.RenderSegmented(result.Image, 1, 1, 0)
surface := d2surface.CreateSurface(result.Image)
checkboxSprite.RenderSegmented(surface, 1, 1, 0)
result.checkedImage, _ = ebiten.NewImage(int(result.width), int(result.height), ebiten.FilterNearest)
checkboxSprite.RenderSegmented(result.checkedImage, 1, 1, 1)
checkedSurface := d2surface.CreateSurface(result.checkedImage)
checkboxSprite.RenderSegmented(checkedSurface, 1, 1, 1)
return result
}
func (v Checkbox) Render(target *ebiten.Image) {
opts := &ebiten.DrawImageOptions{
CompositeMode: ebiten.CompositeModeSourceAtop,
Filter: ebiten.FilterNearest,
}
opts.GeoM.Translate(float64(v.x), float64(v.y))
if v.checkState == false {
target.DrawImage(v.Image, opts)
func (v Checkbox) Render(target *d2surface.Surface) {
target.PushCompositeMode(ebiten.CompositeModeSourceAtop)
target.PushTranslation(v.x, v.y)
target.PushFilter(ebiten.FilterNearest)
defer target.PopN(3)
if v.checkState {
target.Render(v.checkedImage)
} else {
target.DrawImage(v.checkedImage, opts)
target.Render(v.Image)
}
}
func (v Checkbox) GetEnabled() bool {

View File

@ -8,8 +8,7 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"encoding/binary"
@ -106,7 +105,7 @@ func (v *Font) GetTextMetrics(text string) (width, height int) {
}
// Render draws the font on the target surface
func (v *Font) Render(x, y int, text string, color color.Color, target *ebiten.Image) {
func (v *Font) Render(x, y int, text string, color color.Color, target *d2surface.Surface) {
v.fontSprite.SetColorMod(color)
v.fontSprite.SetBlend(false)
@ -115,7 +114,7 @@ func (v *Font) Render(x, y int, text string, color color.Color, target *ebiten.I
maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height))
}
targetWidth, _ := target.Size()
targetWidth, _ := target.GetSize()
lines := strings.Split(text, "\n")
for lineIdx, line := range lines {
lineWidth, _ := v.GetTextMetrics(line)

View File

@ -3,6 +3,7 @@ package d2ui
import (
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -42,23 +43,25 @@ func CreateLabel(fontPath, palettePath string) Label {
}
// Render draws the label on the screen
func (v *Label) Render(target *ebiten.Image) {
func (v *Label) Render(target *d2surface.Surface) {
if len(v.text) == 0 {
return
}
v.cacheImage()
opts := &ebiten.DrawImageOptions{}
x, y := v.X, v.Y
if v.Alignment == LabelAlignCenter {
opts.GeoM.Translate(float64(v.X-int(v.Width/2)), float64(v.Y))
x, y = v.X-int(v.Width/2), v.Y
} else if v.Alignment == LabelAlignRight {
opts.GeoM.Translate(float64(v.X-int(v.Width)), float64(v.Y))
} else {
opts.GeoM.Translate(float64(v.X), float64(v.Y))
x, y = v.X-int(v.Width), v.Y
}
opts.CompositeMode = ebiten.CompositeModeSourceAtop
opts.Filter = ebiten.FilterNearest
target.DrawImage(v.imageData, opts)
target.PushFilter(ebiten.FilterNearest)
target.PushCompositeMode(ebiten.CompositeModeSourceAtop)
target.PushTranslation(x, y)
defer target.PopN(3)
target.Render(v.imageData)
}
// SetPosition moves the label to the specified location
@ -79,7 +82,8 @@ func (v *Label) cacheImage() {
v.Width = width
v.Height = height
v.imageData, _ = ebiten.NewImage(int(width), int(height), ebiten.FilterNearest)
v.font.Render(0, 0, v.text, v.Color, v.imageData)
surface := d2surface.CreateSurface(v.imageData)
v.font.Render(0, 0, v.text, v.Color, surface)
}
// SetText sets the label's text

View File

@ -4,6 +4,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2audio"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -58,17 +59,16 @@ func (v *Manager) WaitForMouseRelease() {
}
// Render renders all of the UI elements
func (v *Manager) Render(screen *ebiten.Image) {
func (v *Manager) Render(target *d2surface.Surface) {
for _, widget := range v.widgets {
if !widget.GetVisible() {
continue
if widget.GetVisible() {
widget.Render(target)
}
widget.Render(screen)
}
cx, cy := ebiten.CursorPosition()
v.cursorSprite.SetPosition(cx, cy)
v.cursorSprite.Render(screen)
v.cursorSprite.Render(target)
}
// Update updates all of the UI elements

View File

@ -8,6 +8,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/hajimehoshi/ebiten"
)
@ -51,7 +52,7 @@ func repeatingKeyPressed(key ebiten.Key) bool {
return false
}
func (v TextBox) Render(target *ebiten.Image) {
func (v TextBox) Render(target *d2surface.Surface) {
if !v.visible {
return
}

View File

@ -5,8 +5,7 @@ import (
"github.com/OpenDiablo2/D2Shared/d2helper"
"github.com/OpenDiablo2/OpenDiablo2/d2asset"
"github.com/hajimehoshi/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
)
type Sprite struct {
@ -34,21 +33,19 @@ func MustLoadSprite(animationPath, palettePath string) *Sprite {
return sprite
}
func (s *Sprite) Render(target *ebiten.Image) error {
func (s *Sprite) Render(target *d2surface.Surface) error {
if err := s.advance(); err != nil {
return err
}
_, frameHeight := s.animation.GetCurrentFrameSize()
if err := s.animation.Render(target, s.x, s.y-frameHeight); err != nil {
return err
}
return nil
target.PushTranslation(s.x, s.y-frameHeight)
defer target.Pop()
return s.animation.Render(target)
}
func (s *Sprite) RenderSegmented(target *ebiten.Image, segmentsX, segmentsY, frameOffset int) error {
func (s *Sprite) RenderSegmented(target *d2surface.Surface, segmentsX, segmentsY, frameOffset int) error {
if err := s.advance(); err != nil {
return err
}
@ -62,7 +59,10 @@ func (s *Sprite) RenderSegmented(target *ebiten.Image, segmentsX, segmentsY, fra
return err
}
if err := s.animation.Render(target, s.x+currentX, s.y+currentY); err != nil {
target.PushTranslation(s.x+currentX, s.y+currentY)
err := s.animation.Render(target)
target.Pop()
if err != nil {
return err
}

11
main.go
View File

@ -5,6 +5,7 @@ import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2scene"
"github.com/OpenDiablo2/OpenDiablo2/d2render/d2surface"
"github.com/OpenDiablo2/OpenDiablo2/d2term"
"github.com/hajimehoshi/ebiten/ebitenutil"
@ -67,9 +68,13 @@ func main() {
func update(screen *ebiten.Image) error {
d2Engine.Update()
if ebiten.IsDrawingSkipped() {
return nil
if !ebiten.IsDrawingSkipped() {
surface := d2surface.CreateSurface(screen)
d2Engine.Draw(surface)
if surface.GetDepth() > 0 {
panic("detected surface stack leak")
}
}
d2Engine.Draw(screen)
return nil
}