Removed render singleton. Updated refs.

This commit is contained in:
Tim Sarbin 2020-07-03 14:00:56 -04:00
parent 7ce01ab694
commit 5bfec3ccb0
33 changed files with 358 additions and 391 deletions

View File

@ -29,8 +29,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
"github.com/OpenDiablo2/OpenDiablo2/d2game/d2gamescreen"
@ -54,6 +52,7 @@ type App struct {
gitCommit string
terminal d2interface.Terminal
audio d2interface.AudioProvider
renderer d2interface.Renderer
tAllocSamples *ring.Ring
}
@ -68,12 +67,16 @@ const bytesToMegabyte = 1024 * 1024
const nSamplesTAlloc = 100
// Create creates a new instance of the application
func Create(gitBranch, gitCommit string, terminal d2interface.Terminal, audio d2interface.AudioProvider) *App {
func Create(gitBranch, gitCommit string,
terminal d2interface.Terminal,
audio d2interface.AudioProvider,
renderer d2interface.Renderer) *App {
result := &App{
gitBranch: gitBranch,
gitCommit: gitCommit,
terminal: terminal,
audio: audio,
renderer: renderer,
tAllocSamples: createZeroedRing(nSamplesTAlloc),
}
@ -94,8 +97,8 @@ func (p *App) Run() {
windowTitle := fmt.Sprintf("OpenDiablo2 (%s)", p.gitBranch)
// If we fail to initialize, we will show the error screen
if err := p.initialize(p.audio, p.terminal); err != nil {
if gameErr := d2render.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
if err := p.initialize(); err != nil {
if gameErr := p.renderer.Run(updateInitError, 800, 600, windowTitle); gameErr != nil {
log.Fatal(gameErr)
}
@ -104,7 +107,7 @@ func (p *App) Run() {
return
}
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(p.audio, p.terminal))
d2screen.SetNextScreen(d2gamescreen.CreateMainMenu(p.renderer, p.audio, p.terminal))
if p.gitBranch == "" {
p.gitBranch = "Local Build"
@ -112,12 +115,12 @@ func (p *App) Run() {
d2common.SetBuildInfo(p.gitBranch, p.gitCommit)
if err := d2render.Run(p.update, 800, 600, windowTitle); err != nil {
if err := p.renderer.Run(p.update, 800, 600, windowTitle); err != nil {
log.Panic(err)
}
}
func (p *App) initialize(audioProvider d2interface.AudioProvider, term d2interface.Terminal) error {
func (p *App) initialize() error {
p.timeScale = 1.0
p.lastTime = d2common.Now()
p.lastScreenAdvance = p.lastTime
@ -129,17 +132,8 @@ func (p *App) initialize(audioProvider d2interface.AudioProvider, term d2interfa
config := d2config.Get()
d2resource.LanguageCode = config.Language
renderer, err := ebiten.CreateRenderer()
if err != nil {
return err
}
if err := d2render.Initialize(renderer); err != nil {
return err
}
d2render.SetWindowIcon("d2logo.png")
term.BindLogger()
p.renderer.SetWindowIcon("d2logo.png")
p.terminal.BindLogger()
terminalActions := [...]bindTerminalEntry{
{"dumpheap", "dumps the heap to pprof/heap.pprof", p.dumpHeap},
@ -157,12 +151,12 @@ func (p *App) initialize(audioProvider d2interface.AudioProvider, term d2interfa
for idx := range terminalActions {
action := &terminalActions[idx]
if err := term.BindAction(action.name, action.description, action.action); err != nil {
if err := p.terminal.BindAction(action.name, action.description, action.action); err != nil {
log.Fatal(err)
}
}
if err := d2asset.Initialize(term); err != nil {
if err := d2asset.Initialize(p.renderer, p.terminal); err != nil {
return err
}
@ -170,7 +164,7 @@ func (p *App) initialize(audioProvider d2interface.AudioProvider, term d2interfa
return err
}
audioProvider.SetVolumes(config.BgmVolume, config.SfxVolume)
p.audio.SetVolumes(config.BgmVolume, config.SfxVolume)
if err := p.loadDataDict(); err != nil {
return err
@ -182,7 +176,7 @@ func (p *App) initialize(audioProvider d2interface.AudioProvider, term d2interfa
d2inventory.LoadHeroObjects()
d2ui.Initialize(audioProvider)
d2ui.Initialize(p.audio)
d2script.CreateScriptEngine()
@ -263,9 +257,9 @@ func (p *App) renderDebug(target d2interface.Surface) error {
return nil
}
vsyncEnabled := d2render.GetVSyncEnabled()
fps := d2render.CurrentFPS()
cx, cy := d2render.GetCursorPos()
vsyncEnabled := p.renderer.GetVSyncEnabled()
fps := p.renderer.CurrentFPS()
cx, cy := p.renderer.GetCursorPos()
target.PushTranslation(5, 565)
target.DrawText("vsync:" + strconv.FormatBool(vsyncEnabled) + "\nFPS:" + strconv.Itoa(int(fps)))
@ -481,8 +475,8 @@ func (p *App) dumpHeap() {
}
func (p *App) toggleFullScreen() {
fullscreen := !d2render.IsFullScreen()
d2render.SetFullScreen(fullscreen)
fullscreen := !p.renderer.IsFullScreen()
p.renderer.SetFullScreen(fullscreen)
p.terminal.OutputInfof("fullscreen is now: %v", fullscreen)
}
@ -503,8 +497,8 @@ func (p *App) stopAnimationCapture() {
}
func (p *App) toggleVsync() {
vsync := !d2render.GetVSyncEnabled()
d2render.SetVSyncEnabled(vsync)
vsync := !p.renderer.GetVSyncEnabled()
p.renderer.SetVSyncEnabled(vsync)
p.terminal.OutputInfof("vsync is now: %v", vsync)
}
@ -527,7 +521,7 @@ func (p *App) quitGame() {
}
func (p *App) enterGuiPlayground() {
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain())
d2screen.SetNextScreen(d2gamescreen.CreateGuiTestMain(p.renderer))
}
func createZeroedRing(n int) *ring.Ring {
@ -584,7 +578,8 @@ func enableProfiler(profileOption string) interface{ Stop() } {
}
func updateInitError(target d2interface.Surface) error {
target.Clear(colornames.Darkred)
_ = target.Clear(colornames.Darkred)
width, height := target.GetSize()
target.PushTranslation(width/5, height/2)

View File

@ -14,8 +14,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dc6"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dcc"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type playMode int
@ -62,7 +60,8 @@ type Animation struct {
}
// CreateAnimationFromDCC creates an animation from d2dcc.DCC and d2dat.DATPalette
func CreateAnimationFromDCC(dcc *d2dcc.DCC, palette *d2dat.DATPalette, transparency int) (*Animation, error) {
func CreateAnimationFromDCC(renderer d2interface.Renderer, dcc *d2dcc.DCC, palette *d2dat.DATPalette,
transparency int) (*Animation, error) {
animation := &Animation{
playLength: defaultPlayLength,
playLoop: true,
@ -99,7 +98,7 @@ func CreateAnimationFromDCC(dcc *d2dcc.DCC, palette *d2dat.DATPalette, transpare
}
}
sfc, err := d2render.NewSurface(frameWidth, frameHeight, d2interface.FilterNearest)
sfc, err := renderer.NewSurface(frameWidth, frameHeight, d2interface.FilterNearest)
if err != nil {
return nil, err
}
@ -127,7 +126,7 @@ func CreateAnimationFromDCC(dcc *d2dcc.DCC, palette *d2dat.DATPalette, transpare
}
// CreateAnimationFromDC6 creates an Animation from d2dc6.DC6 and d2dat.DATPalette
func CreateAnimationFromDC6(dc6 *d2dc6.DC6, palette *d2dat.DATPalette) (*Animation, error) {
func CreateAnimationFromDC6(renderer d2interface.Renderer, dc6 *d2dc6.DC6, palette *d2dat.DATPalette) (*Animation, error) {
animation := &Animation{
playLength: defaultPlayLength,
playLoop: true,
@ -135,7 +134,7 @@ func CreateAnimationFromDC6(dc6 *d2dc6.DC6, palette *d2dat.DATPalette) (*Animati
}
for frameIndex, dc6Frame := range dc6.Frames {
sfc, err := d2render.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height), d2interface.FilterNearest)
sfc, err := renderer.NewSurface(int(dc6Frame.Width), int(dc6Frame.Height), d2interface.FilterNearest)
if err != nil {
return nil, err
}
@ -396,7 +395,7 @@ func (a *Animation) SetCurrentFrame(frameIndex int) error {
// Rewind animation to beginning
func (a *Animation) Rewind() {
a.SetCurrentFrame(0)
_ = a.SetCurrentFrame(0)
}
// PlayForward plays animation forward

View File

@ -5,6 +5,8 @@ import (
"path/filepath"
"strings"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
)
@ -13,11 +15,15 @@ const (
)
type animationManager struct {
cache *d2common.Cache
cache *d2common.Cache
renderer d2interface.Renderer
}
func createAnimationManager() *animationManager {
return &animationManager{d2common.CreateCache(animationBudget)}
func createAnimationManager(renderer d2interface.Renderer) *animationManager {
return &animationManager{
renderer: renderer,
cache: d2common.CreateCache(animationBudget),
}
}
func (am *animationManager) loadAnimation(animationPath, palettePath string, transparency int) (*Animation, error) {
@ -41,7 +47,7 @@ func (am *animationManager) loadAnimation(animationPath, palettePath string, tra
return nil, err
}
animation, err = CreateAnimationFromDC6(dc6, palette)
animation, err = CreateAnimationFromDC6(am.renderer, dc6, palette)
if err != nil {
return nil, err
}
@ -56,7 +62,7 @@ func (am *animationManager) loadAnimation(animationPath, palettePath string, tra
return nil, err
}
animation, err = CreateAnimationFromDCC(dcc, palette, transparency)
animation, err = CreateAnimationFromDCC(am.renderer, dcc, palette, transparency)
if err != nil {
return nil, err
}

View File

@ -17,14 +17,14 @@ import (
var singleton *assetManager
// Initialize creates and assigns all necessary dependencies for the assetManager top-level functions to work correctly
func Initialize(term d2interface.Terminal) error {
func Initialize(renderer d2interface.Renderer, term d2interface.Terminal) error {
var (
config = d2config.Get()
archiveManager = createArchiveManager(&config)
fileManager = createFileManager(&config, archiveManager)
paletteManager = createPaletteManager()
paletteTransformManager = createPaletteTransformManager()
animationManager = createAnimationManager()
animationManager = createAnimationManager(renderer)
fontManager = createFontManager()
)

View File

@ -23,6 +23,7 @@ func getDefaultConfig() *Configuration {
SfxVolume: defaultSfxVolume,
BgmVolume: defaultBgmVolume,
MpqPath: "C:/Program Files (x86)/Diablo II",
Backend: "Ebiten",
MpqLoadOrder: []string{
"Patch_D2.mpq",
"d2exp.mpq",

View File

@ -16,6 +16,7 @@ type Configuration struct {
FullScreen bool
RunInBackground bool
VsyncEnabled bool
Backend string
}
var singleton = getDefaultConfig()
@ -27,8 +28,10 @@ func Load() error {
}
var loaded bool
for _, configPath := range configPaths {
log.Printf("loading configuration file from %s...", configPath)
if err := load(configPath); err == nil {
loaded = true
break
@ -37,6 +40,7 @@ func Load() error {
if !loaded {
log.Println("failed to load configuration file, saving default configuration...")
if err := Save(); err != nil {
return err
}

View File

@ -8,7 +8,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2input"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type buttonState int
@ -29,7 +28,7 @@ type Button struct {
surfaces []d2interface.Surface
}
func createButton(text string, buttonStyle ButtonStyle) (*Button, error) {
func createButton(renderer d2interface.Renderer, text string, buttonStyle ButtonStyle) (*Button, error) {
config, ok := buttonStyleConfigs[buttonStyle]
if !ok {
return nil, errors.New("invalid button style")
@ -73,7 +72,7 @@ func createButton(text string, buttonStyle ButtonStyle) (*Button, error) {
surfaceCount := animation.GetFrameCount() / (config.segmentsX * config.segmentsY)
surfaces := make([]d2interface.Surface, surfaceCount)
for i := 0; i < surfaceCount; i++ {
surface, err := d2render.NewSurface(buttonWidth, buttonHeight, d2interface.FilterNearest)
surface, err := renderer.NewSurface(buttonWidth, buttonHeight, d2interface.FilterNearest)
if err != nil {
return nil, err
}
@ -108,17 +107,17 @@ func createButton(text string, buttonStyle ButtonStyle) (*Button, error) {
return button, nil
}
func (b *Button) onMouseButtonDown(event d2input.MouseEvent) bool {
func (b *Button) onMouseButtonDown(_ d2input.MouseEvent) bool {
b.state = buttonStatePressed
return false
}
func (b *Button) onMouseButtonUp(event d2input.MouseEvent) bool {
func (b *Button) onMouseButtonUp(_ d2input.MouseEvent) bool {
b.state = buttonStateDefault
return false
}
func (b *Button) onMouseLeave(event d2input.MouseMoveEvent) bool {
func (b *Button) onMouseLeave(_ d2input.MouseMoveEvent) bool {
b.state = buttonStateDefault
return false
}

View File

@ -34,9 +34,9 @@ func Advance(elapsed float64) error {
return singleton.advance(elapsed)
}
func CreateLayout(positionType PositionType) *Layout {
func CreateLayout(renderer d2interface.Renderer, positionType PositionType) *Layout {
verifyWasInit()
return createLayout(positionType)
return createLayout(renderer, positionType)
}
func SetLayout(layout *Layout) {

View File

@ -3,25 +3,29 @@ package d2gui
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type Label struct {
widgetBase
text string
font *d2asset.Font
surface d2interface.Surface
renderer d2interface.Renderer
text string
font *d2asset.Font
surface d2interface.Surface
}
func createLabel(text string, fontStyle FontStyle) (*Label, error) {
func createLabel(renderer d2interface.Renderer, text string, fontStyle FontStyle) (*Label, error) {
font, err := loadFont(fontStyle)
if err != nil {
return nil, err
}
label := &Label{font: font}
label.setText(text)
label := &Label{
font: font,
renderer: renderer,
}
_ = label.setText(text)
label.SetVisible(true)
return label, nil
@ -48,7 +52,7 @@ func (l *Label) SetText(text string) error {
func (l *Label) setText(text string) error {
width, height := l.font.GetTextMetrics(text)
surface, err := d2render.NewSurface(width, height, d2interface.FilterNearest)
surface, err := l.renderer.NewSurface(width, height, d2interface.FilterNearest)
if err != nil {
return err
}

View File

@ -48,6 +48,8 @@ const (
type Layout struct {
widgetBase
renderer d2interface.Renderer
width int
height int
verticalAlign VerticalAlign
@ -56,8 +58,12 @@ type Layout struct {
entries []*layoutEntry
}
func createLayout(positionType PositionType) *Layout {
layout := &Layout{positionType: positionType}
func createLayout(renderer d2interface.Renderer, positionType PositionType) *Layout {
layout := &Layout{
renderer: renderer,
positionType: positionType,
}
layout.SetVisible(true)
return layout
@ -77,7 +83,7 @@ func (l *Layout) SetHorizontalAlign(horizontalAlign HorizontalAlign) {
}
func (l *Layout) AddLayout(positionType PositionType) *Layout {
layout := createLayout(positionType)
layout := createLayout(l.renderer, positionType)
l.entries = append(l.entries, &layoutEntry{widget: layout})
return layout
}
@ -115,7 +121,7 @@ func (l *Layout) AddAnimatedSprite(imagePath, palettePath string, direction Anim
}
func (l *Layout) AddLabel(text string, fontStyle FontStyle) (*Label, error) {
label, err := createLabel(text, fontStyle)
label, err := createLabel(l.renderer, text, fontStyle)
if err != nil {
return nil, err
}
@ -125,7 +131,7 @@ func (l *Layout) AddLabel(text string, fontStyle FontStyle) (*Label, error) {
}
func (l *Layout) AddButton(text string, buttonStyle ButtonStyle) (*Button, error) {
button, err := createButton(text, buttonStyle)
button, err := createButton(l.renderer, text, buttonStyle)
if err != nil {
return nil, err
}

View File

@ -1,22 +1,19 @@
package d2mapentity
import (
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
// Object represents a composite of animations that can be projected onto the map.
type Object struct {
mapEntity
composite *d2asset.Composite
direction int
highlight bool
nameLabel d2ui.Label
composite *d2asset.Composite
direction int
highlight bool
// nameLabel d2ui.Label
objectLookup *d2datadict.ObjectLookupRecord
objectRecord *d2datadict.ObjectRecord
objectType *d2datadict.ObjectTypeRecord
@ -28,7 +25,7 @@ func CreateObject(x, y int, objectRec *d2datadict.ObjectRecord, palettePath stri
mapEntity: createMapEntity(x, y),
objectRecord: objectRec,
objectType: &d2datadict.ObjectTypes[objectRec.Index],
nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
// nameLabel: d2ui.CreateLabel(renderer, d2resource.FontFormal11, d2resource.PaletteStatic),
}
object := &d2datadict.ObjectLookupRecord{
@ -118,9 +115,9 @@ func (ob *Object) Render(target d2interface.Surface) {
)
if ob.highlight {
ob.nameLabel.SetText(d2common.TranslateString(ob.objectRecord.Name))
ob.nameLabel.SetPosition(-50, -50)
ob.nameLabel.Render(target)
// ob.nameLabel.SetText(d2common.TranslateString(ob.objectRecord.Name))
// ob.nameLabel.SetPosition(-50, -50)
// ob.nameLabel.Render(target)
target.PushBrightness(2)
defer target.Pop()
}

View File

@ -1,8 +1,6 @@
package d2mapentity
import (
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
@ -11,19 +9,18 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2inventory"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
type Player struct {
mapEntity
composite *d2asset.Composite
Equipment d2inventory.CharacterEquipment
Stats d2hero.HeroStatsState
Class d2enum.Hero
Id string
direction int
name string
nameLabel d2ui.Label
composite *d2asset.Composite
Equipment d2inventory.CharacterEquipment
Stats d2hero.HeroStatsState
Class d2enum.Hero
Id string
direction int
name string
// nameLabel d2ui.Label
lastPathSize int
isInTown bool
animationMode string
@ -62,24 +59,24 @@ func CreatePlayer(id, name string, x, y int, direction int, heroType d2enum.Hero
stats.Stamina = stats.MaxStamina
result := &Player{
Id: id,
mapEntity: createMapEntity(x, y),
composite: composite,
Equipment: equipment,
Stats: stats,
direction: direction,
name: name,
Class: heroType,
nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
Id: id,
mapEntity: createMapEntity(x, y),
composite: composite,
Equipment: equipment,
Stats: stats,
direction: direction,
name: name,
Class: heroType,
//nameLabel: d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic),
isRunToggled: true,
isInTown: true,
isRunning: true,
}
result.SetSpeed(baseRunSpeed)
result.mapEntity.directioner = result.rotate
result.nameLabel.Alignment = d2ui.LabelAlignCenter
result.nameLabel.SetText(name)
result.nameLabel.Color = color.White
//result.nameLabel.Alignment = d2ui.LabelAlignCenter
//result.nameLabel.SetText(name)
//result.nameLabel.Color = color.White
err = result.SetMode(d2enum.AnimationModePlayerTownNeutral.String(), equipment.RightHand.GetWeaponClass(), direction)
if err != nil {
panic(err)

View File

@ -6,19 +6,18 @@ import (
"log"
"math"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dat"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2map/d2mapengine"
)
// The map renderer, used to render the map
type MapRenderer struct {
renderer d2interface.Renderer // The renderer to use for drawing operations
mapEngine *d2mapengine.MapEngine // The map engine that is being rendered
palette *d2dat.DATPalette // The palette used for this map
viewport *Viewport // The viewport for the map renderer (used for rendering offsets)
@ -29,8 +28,9 @@ type MapRenderer struct {
}
// Creates an instance of the map renderer
func CreateMapRenderer(mapEngine *d2mapengine.MapEngine, term d2interface.Terminal) *MapRenderer {
func CreateMapRenderer(renderer d2interface.Renderer, mapEngine *d2mapengine.MapEngine, term d2interface.Terminal) *MapRenderer {
result := &MapRenderer{
renderer: renderer,
mapEngine: mapEngine,
viewport: NewViewport(0, 0, 800, 600),
}

View File

@ -3,14 +3,11 @@ package d2maprenderer
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
func (mr *MapRenderer) generateTileCache() {
@ -76,10 +73,10 @@ func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX,
}
tileYOffset := d2common.AbsInt32(tileYMinimum)
tileHeight := d2common.AbsInt32(tileData[i].Height)
image, _ := d2render.NewSurface(int(tileData[i].Width), int(tileHeight), d2interface.FilterNearest)
image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2interface.FilterNearest)
pixels := make([]byte, 4*tileData[i].Width*tileHeight)
mr.decodeTileGfxData(tileData[i].Blocks, &pixels, tileYOffset, tileData[i].Width)
image.ReplacePixels(pixels)
_ = image.ReplacePixels(pixels)
mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image)
}
}
@ -115,10 +112,10 @@ func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX,
return
}
image, _ := d2render.NewSurface(int(tileData.Width), tileHeight, d2interface.FilterNearest)
image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2interface.FilterNearest)
pixels := make([]byte, 4*tileData.Width*int32(tileHeight))
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, tileData.Width)
image.ReplacePixels(pixels)
_ = image.ReplacePixels(pixels)
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex, image)
}
@ -176,8 +173,9 @@ func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY in
return
}
image, _ := d2render.NewSurface(160, int(realHeight), d2interface.FilterNearest)
image, _ := mr.renderer.NewSurface(160, int(realHeight), d2interface.FilterNearest)
pixels := make([]byte, 4*160*realHeight)
mr.decodeTileGfxData(tileData.Blocks, &pixels, tileYOffset, 160)
if newTileData != nil {

View File

@ -139,7 +139,8 @@ func (mr *Stamp) Entities(tileOffsetX, tileOffsetY int) []d2mapentity.MapEntity
objectRecord := d2datadict.Objects[lookup.ObjectsTxtId]
if objectRecord != nil {
entity, err := d2mapentity.CreateObject((tileOffsetX*5)+object.X, (tileOffsetY*5)+object.Y, objectRecord, d2resource.PaletteUnits)
entity, err := d2mapentity.CreateObject((tileOffsetX*5)+object.X,
(tileOffsetY*5)+object.Y, objectRecord, d2resource.PaletteUnits)
if err != nil {
panic(err)

View File

@ -1,106 +0,0 @@
package d2render
import (
"errors"
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
)
var (
// ErrWasInit holding an error instance for initialized rendering system
ErrWasInit = errors.New("rendering system is already initialized")
// ErrNotInit holding an error instance for non-initialized rendering system
ErrNotInit = errors.New("rendering system has not been initialized")
// ErrInvalidRenderer holding an error instance for invalid rendering system specification
ErrInvalidRenderer = errors.New("invalid rendering system specified")
)
var singleton d2interface.Renderer
// Initialize the renderer
func Initialize(rend d2interface.Renderer) error {
verifyNotInit()
singleton = rend
log.Printf("Initialized the %s renderer...", singleton.GetRendererName())
return nil
}
// SetWindowIcon sets the window icon by a given file name as string
func SetWindowIcon(fileName string) {
verifyWasInit()
singleton.SetWindowIcon(fileName)
}
// Run will run the renderer
func Run(f func(d2interface.Surface) error, width, height int, title string) error {
verifyWasInit()
singleton.Run(f, width, height, title)
return nil
}
// IsDrawingSkipped checks whether the drawing is skipped
func IsDrawingSkipped() bool {
verifyWasInit()
return singleton.IsDrawingSkipped()
}
// CreateSurface creates a new surface, which returns the newly created surface or error
func CreateSurface(surface d2interface.Surface) (d2interface.Surface, error) {
verifyWasInit()
return singleton.CreateSurface(surface)
}
// NewSurface adds a new surface, and returns the new surface or error
func NewSurface(width, height int, filter d2interface.Filter) (d2interface.Surface, error) {
verifyWasInit()
return singleton.NewSurface(width, height, filter)
}
// IsFullScreen checks whether the window is on full screen
func IsFullScreen() bool {
verifyWasInit()
return singleton.IsFullScreen()
}
// SetFullScreen sets the window in fullscreen or windowed mode depending on the fullScreen flag
func SetFullScreen(fullScreen bool) {
verifyWasInit()
singleton.SetFullScreen(fullScreen)
}
// SetVSyncEnabled sets or unsets the VSync depending on the given vsync parameter flag
func SetVSyncEnabled(vsync bool) {
verifyWasInit()
singleton.SetVSyncEnabled(vsync)
}
// GetVSyncEnabled checks whether the VSync is enabled or not
func GetVSyncEnabled() bool {
verifyWasInit()
return singleton.GetVSyncEnabled()
}
// GetCursorPos returns the exact current position of the cursor
func GetCursorPos() (int, int) {
verifyWasInit()
return singleton.GetCursorPos()
}
// CurrentFPS returns the current frames per second
func CurrentFPS() float64 {
verifyWasInit()
return singleton.CurrentFPS()
}
func verifyWasInit() {
if singleton == nil {
panic(ErrNotInit)
}
}
func verifyNotInit() {
if singleton != nil {
panic(ErrWasInit)
}
}

View File

@ -5,14 +5,9 @@ import (
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
)
// ButtonType defines the type of button
@ -107,7 +102,7 @@ type Button struct {
}
// CreateButton creates an instance of Button
func CreateButton(buttonType ButtonType, text string) Button {
func CreateButton(renderer d2interface.Renderer, buttonType ButtonType, text string) Button {
result := Button{
width: 0,
height: 0,
@ -131,7 +126,7 @@ func CreateButton(buttonType ButtonType, text string) Button {
result.height += h
}
result.normalSurface, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.normalSurface, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
_, fontHeight := font.GetTextMetrics(text)
textY := (result.height / 2) - (fontHeight / 2) + buttonLayout.TextOffset
@ -141,22 +136,22 @@ func CreateButton(buttonType ButtonType, text string) Button {
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.normalSurface)
if buttonLayout.AllowFrameChange {
if totalButtonTypes > 1 {
result.pressedSurface, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.pressedSurface, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
buttonSprite.RenderSegmented(result.pressedSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+1)
font.Render(-2, textY+2, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.pressedSurface)
}
if totalButtonTypes > 2 {
result.toggledSurface, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.toggledSurface, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
buttonSprite.RenderSegmented(result.toggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+2)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.toggledSurface)
}
if totalButtonTypes > 3 {
result.pressedToggledSurface, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.pressedToggledSurface, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
buttonSprite.RenderSegmented(result.pressedToggledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.BaseFrame+3)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.pressedToggledSurface)
}
if buttonLayout.DisabledFrame != -1 {
result.disabledSurface, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.disabledSurface, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
buttonSprite.RenderSegmented(result.disabledSurface, buttonLayout.XSegments, buttonLayout.YSegments, buttonLayout.DisabledFrame)
font.Render(0, textY, text, color.RGBA{R: 100, G: 100, B: 100, A: 255}, result.disabledSurface)
}

View File

@ -5,7 +5,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
type Checkbox struct {
@ -19,7 +18,7 @@ type Checkbox struct {
enabled bool
}
func CreateCheckbox(checkState bool) Checkbox {
func CreateCheckbox(renderer d2interface.Renderer, checkState bool) Checkbox {
result := Checkbox{
checkState: checkState,
visible: true,
@ -33,11 +32,13 @@ func CreateCheckbox(checkState bool) Checkbox {
result.width, result.height, _ = checkboxSprite.GetFrameSize(0)
checkboxSprite.SetPosition(0, 0)
result.Image, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
checkboxSprite.RenderSegmented(result.Image, 1, 1, 0)
result.Image, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
result.checkedImage, _ = d2render.NewSurface(result.width, result.height, d2interface.FilterNearest)
checkboxSprite.RenderSegmented(result.checkedImage, 1, 1, 1)
_ = checkboxSprite.RenderSegmented(result.Image, 1, 1, 0)
result.checkedImage, _ = renderer.NewSurface(result.width, result.height, d2interface.FilterNearest)
_ = checkboxSprite.RenderSegmented(result.checkedImage, 1, 1, 1)
return result
}
@ -48,9 +49,9 @@ func (v *Checkbox) Render(target d2interface.Surface) {
defer target.PopN(3)
if v.checkState {
target.Render(v.checkedImage)
_ = target.Render(v.checkedImage)
} else {
target.Render(v.Image)
_ = target.Render(v.Image)
}
}
@ -66,7 +67,7 @@ func (v *Checkbox) SetEnabled(enabled bool) {
v.enabled = enabled
}
func (v *Checkbox) SetPressed(pressed bool) {
func (v *Checkbox) SetPressed(_ bool) {
}
func (v *Checkbox) SetCheckState(checkState bool) {

View File

@ -4,10 +4,7 @@ import (
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
)
// LabelAlignment represents a label's alignment
@ -25,6 +22,7 @@ const (
// Label represents a user interface label
type Label struct {
text string
renderer d2interface.Renderer
X int
Y int
Width int
@ -36,8 +34,9 @@ type Label struct {
}
// CreateLabel creates a new instance of a UI label
func CreateLabel(fontPath, palettePath string) Label {
func CreateLabel(renderer d2interface.Renderer, fontPath, palettePath string) Label {
result := Label{
renderer: renderer,
Alignment: LabelAlignLeft,
Color: color.White,
font: GetFont(fontPath, palettePath),
@ -66,7 +65,7 @@ func (v *Label) Render(target d2interface.Surface) {
target.PushTranslation(x, y)
defer target.PopN(3)
target.Render(v.imageData[v.text])
_ = target.Render(v.imageData[v.text])
}
// SetPosition moves the label to the specified location
@ -86,8 +85,8 @@ func (v *Label) cacheImage() {
width, height := v.font.GetTextMetrics(v.text)
v.Width = width
v.Height = height
v.imageData[v.text], _ = d2render.NewSurface(width, height, d2interface.FilterNearest)
surface, _ := d2render.CreateSurface(v.imageData[v.text])
v.imageData[v.text], _ = v.renderer.NewSurface(width, height, d2interface.FilterNearest)
surface, _ := v.renderer.CreateSurface(v.imageData[v.text])
v.font.Render(0, 0, v.text, v.Color, surface)
}

View File

@ -27,14 +27,14 @@ type TextBox struct {
filter string
}
func CreateTextbox() TextBox {
func CreateTextbox(renderer d2interface.Renderer) TextBox {
animation, _ := d2asset.LoadAnimation(d2resource.TextBox2, d2resource.PaletteUnits)
bgSprite, _ := LoadSprite(animation)
tb := TextBox{
filter: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
bgSprite: bgSprite,
textLabel: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
lineBar: CreateLabel(d2resource.FontFormal11, d2resource.PaletteUnits),
textLabel: CreateLabel(renderer, d2resource.FontFormal11, d2resource.PaletteUnits),
lineBar: CreateLabel(renderer, d2resource.FontFormal11, d2resource.PaletteUnits),
enabled: true,
visible: true,
}

View File

@ -49,16 +49,19 @@ type CharacterSelect struct {
connectionHost string
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
renderer d2interface.Renderer
}
// CreateCharacterSelect creates the character select screen and returns a pointer to it
func CreateCharacterSelect(
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string, term d2interface.Terminal,
) *CharacterSelect {
return &CharacterSelect{
selectedCharacter: -1,
renderer: renderer,
connectionType: connectionType,
connectionHost: connectionHost,
audioProvider: audioProvider,
@ -82,13 +85,13 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
v.createButtons(loading)
v.d2HeroTitle = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.d2HeroTitle = d2ui.CreateLabel(v.renderer, d2resource.Font42, d2resource.PaletteUnits)
v.d2HeroTitle.SetPosition(320, 23)
v.d2HeroTitle.Alignment = d2ui.LabelAlignCenter
loading.Progress(0.3)
v.deleteCharConfirmLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.deleteCharConfirmLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
lines := d2common.SplitIntoLinesWithMaxWidth(
"Are you sure that you want to delete this character? Take note: this will delete all versions of this Character.",
29,
@ -116,12 +119,12 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
xOffset = 385
}
v.characterNameLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterNameLabel[i] = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.characterNameLabel[i].Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.characterNameLabel[i].SetPosition(xOffset, 100+((i/2)*95))
v.characterStatsLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i] = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.characterStatsLabel[i].SetPosition(xOffset, 115+((i/2)*95))
v.characterExpLabel[i] = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteStatic)
v.characterExpLabel[i] = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteStatic)
v.characterExpLabel[i].Color = color.RGBA{R: 24, G: 255, A: 255}
v.characterExpLabel[i].SetPosition(xOffset, 130+((i/2)*95))
}
@ -130,6 +133,7 @@ func (v *CharacterSelect) OnLoad(loading d2screen.LoadingState) {
func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
v.newCharButton = d2ui.CreateButton(
v.renderer,
d2ui.ButtonTypeTall,
d2common.CombineStrings(d2common.SplitIntoLinesWithMaxWidth("CREATE NEW CHARACTER", 15)),
)
@ -138,6 +142,7 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
d2ui.AddWidget(&v.newCharButton)
v.convertCharButton = d2ui.CreateButton(
v.renderer,
d2ui.ButtonTypeTall,
d2common.CombineStrings(d2common.SplitIntoLinesWithMaxWidth("CONVERT TO EXPANSION", 15)),
)
@ -146,6 +151,7 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
d2ui.AddWidget(&v.convertCharButton)
v.deleteCharButton = d2ui.CreateButton(
v.renderer,
d2ui.ButtonTypeTall,
d2common.CombineStrings(d2common.SplitIntoLinesWithMaxWidth("DELETE CHARACTER", 15)),
)
@ -153,25 +159,25 @@ func (v *CharacterSelect) createButtons(loading d2screen.LoadingState) {
v.deleteCharButton.SetPosition(433, 468)
d2ui.AddWidget(&v.deleteCharButton)
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, "EXIT")
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
loading.Progress(0.2)
v.deleteCharCancelButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, "NO")
v.deleteCharCancelButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "NO")
v.deleteCharCancelButton.SetPosition(282, 308)
v.deleteCharCancelButton.SetVisible(false)
v.deleteCharCancelButton.OnActivated(func() { v.onDeleteCharacterCancelClicked() })
d2ui.AddWidget(&v.deleteCharCancelButton)
v.deleteCharOkButton = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, "YES")
v.deleteCharOkButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "YES")
v.deleteCharOkButton.SetPosition(422, 308)
v.deleteCharOkButton.SetVisible(false)
v.deleteCharOkButton.OnActivated(func() { v.onDeleteCharacterConfirmClicked() })
d2ui.AddWidget(&v.deleteCharOkButton)
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, "OK")
v.okButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "OK")
v.okButton.SetPosition(625, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
d2ui.AddWidget(&v.okButton)
@ -209,11 +215,11 @@ func (v *CharacterSelect) updateCharacterBoxes() {
}
func (v *CharacterSelect) onNewCharButtonClicked() {
d2screen.SetNextScreen(CreateSelectHeroClass(v.audioProvider, v.connectionType, v.connectionHost, v.terminal))
d2screen.SetNextScreen(CreateSelectHeroClass(v.renderer, v.audioProvider, v.connectionType, v.connectionHost, v.terminal))
}
func (v *CharacterSelect) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.audioProvider, v.terminal)
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}
@ -371,5 +377,5 @@ func (v *CharacterSelect) onOkButtonClicked() {
fmt.Printf("can not connect to the host: %s", host)
}
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient, v.terminal))
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal))
}

View File

@ -34,17 +34,19 @@ type Credits struct {
cycleTime float64
cyclesTillNextLine int
doneWithCredits bool
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateCredits creates an instance of the credits screen
func CreateCredits(audioProvider d2interface.AudioProvider) *Credits {
func CreateCredits(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider) *Credits {
result := &Credits{
labels: make([]*labelItem, 0),
cycleTime: 0,
doneWithCredits: false,
cyclesTillNextLine: 0,
renderer: renderer,
audioProvider: audioProvider,
}
@ -83,7 +85,7 @@ func (v *Credits) OnLoad(loading d2screen.LoadingState) {
v.creditsBackground.SetPosition(0, 0)
loading.Progress(0.2)
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, "EXIT")
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 543)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
@ -157,7 +159,7 @@ func (v *Credits) Advance(tickTime float64) error {
}
func (v *Credits) onExitButtonClicked() {
mainMenu := CreateMainMenu(v.audioProvider, v.terminal)
mainMenu := CreateMainMenu(v.renderer, v.audioProvider, v.terminal)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)
}
@ -254,7 +256,7 @@ func (v *Credits) getNewFontLabel(isHeading bool) *d2ui.Label {
newLabelItem := &labelItem{
Available: false,
IsHeading: isHeading,
Label: d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteSky),
Label: d2ui.CreateLabel(v.renderer, d2resource.FontFormal10, d2resource.PaletteSky),
}
if isHeading {

View File

@ -64,9 +64,11 @@ type EscapeMenu struct {
currentLayout layoutID
// leftPent and rightPent are generated once and shared between the layouts
leftPent *d2gui.AnimatedSprite
rightPent *d2gui.AnimatedSprite
layouts []*layout
leftPent *d2gui.AnimatedSprite
rightPent *d2gui.AnimatedSprite
layouts []*layout
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
@ -122,10 +124,11 @@ type actionableElement interface {
}
// NewEscapeMenu creates a new escape menu
func NewEscapeMenu(audioProvider d2interface.AudioProvider, term d2interface.Terminal) *EscapeMenu {
func NewEscapeMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal) *EscapeMenu {
m := &EscapeMenu{
audioProvider: audioProvider,
terminal: term,
renderer: renderer,
}
m.layouts = []*layout{
@ -204,7 +207,7 @@ func (m *EscapeMenu) newConfigureControlsLayout() *layout {
}
func (m *EscapeMenu) wrapLayout(fn func(*layout)) *layout {
wrapper := d2gui.CreateLayout(d2gui.PositionTypeHorizontal)
wrapper := d2gui.CreateLayout(m.renderer, d2gui.PositionTypeHorizontal)
wrapper.SetVerticalAlign(d2gui.VerticalAlignMiddle)
wrapper.AddSpacerDynamic()
@ -365,7 +368,7 @@ func (m *EscapeMenu) showLayout(id layoutID) {
}
if id == saveLayoutID {
mainMenu := CreateMainMenu(m.audioProvider, m.terminal)
mainMenu := CreateMainMenu(m.renderer, m.audioProvider, m.terminal)
mainMenu.setScreenMode(screenModeMainMenu)
d2screen.SetNextScreen(mainMenu)

View File

@ -25,38 +25,42 @@ type Game struct {
gameControls *d2player.GameControls // TODO: Hack
localPlayer *d2mapentity.Player
lastRegionType d2enum.RegionIdType
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
ticksSinceLevelCheck float64
escapeMenu *EscapeMenu
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
func CreateGame(audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient, term d2interface.Terminal) *Game {
func CreateGame(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, gameClient *d2client.GameClient,
term d2interface.Terminal) *Game {
result := &Game{
gameClient: gameClient,
gameControls: nil,
localPlayer: nil,
lastRegionType: d2enum.RegionNone,
ticksSinceLevelCheck: 0,
mapRenderer: d2maprenderer.CreateMapRenderer(gameClient.MapEngine, term),
escapeMenu: NewEscapeMenu(audioProvider, term),
mapRenderer: d2maprenderer.CreateMapRenderer(renderer, gameClient.MapEngine, term),
escapeMenu: NewEscapeMenu(renderer, audioProvider, term),
audioProvider: audioProvider,
renderer: renderer,
terminal: term,
}
result.escapeMenu.onLoad()
d2input.BindHandler(result.escapeMenu)
_ = d2input.BindHandler(result.escapeMenu)
return result
}
func (v *Game) OnLoad(loading d2screen.LoadingState) {
func (v *Game) OnLoad(_ d2screen.LoadingState) {
v.audioProvider.PlayBGM("")
}
func (v *Game) OnUnload() error {
d2input.UnbindHandler(v.gameControls) // TODO: hack
d2input.UnbindHandler(v.escapeMenu) // TODO: hack
v.gameClient.Close()
_ = d2input.UnbindHandler(v.gameControls) // TODO: hack
_ = d2input.UnbindHandler(v.escapeMenu) // TODO: hack
_ = v.gameClient.Close()
return nil
}
@ -67,7 +71,7 @@ func (v *Game) Render(screen d2interface.Surface) error {
v.mapRenderer.RegenerateTileCache()
}
screen.Clear(color.Black)
_ = screen.Clear(color.Black)
v.mapRenderer.Render(screen)
if v.gameControls != nil {
@ -85,7 +89,7 @@ func (v *Game) Advance(tickTime float64) error {
}
if v.gameControls != nil {
v.gameControls.Advance(tickTime)
_ = v.gameControls.Advance(tickTime)
}
v.ticksSinceLevelCheck += tickTime
@ -118,9 +122,9 @@ func (v *Game) Advance(tickTime float64) error {
}
v.localPlayer = player
v.gameControls = d2player.NewGameControls(player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal)
v.gameControls = d2player.NewGameControls(v.renderer, player, v.gameClient.MapEngine, v.mapRenderer, v, v.terminal)
v.gameControls.Load()
d2input.BindHandler(v.gameControls)
_ = d2input.BindHandler(v.gameControls)
break
}
@ -138,9 +142,9 @@ func (v *Game) Advance(tickTime float64) error {
func (v *Game) OnPlayerMove(x, y float64) {
heroPosX := v.localPlayer.LocationX / 5.0
heroPosY := v.localPlayer.LocationY / 5.0
v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y))
_ = v.gameClient.SendPacketToServer(d2netpacket.CreateMovePlayerPacket(v.gameClient.PlayerId, heroPosX, heroPosY, x, y))
}
func (v *Game) OnPlayerCast(missleID int, targetX, targetY float64) {
v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerId, missleID, targetX, targetY))
_ = v.gameClient.SendPacketToServer(d2netpacket.CreateCastPacket(v.gameClient.PlayerId, missleID, targetX, targetY))
}

View File

@ -6,47 +6,51 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2screen"
)
type GuiTestMain struct{}
type GuiTestMain struct {
renderer d2interface.Renderer
}
func CreateGuiTestMain() *GuiTestMain {
return &GuiTestMain{}
func CreateGuiTestMain(renderer d2interface.Renderer) *GuiTestMain {
return &GuiTestMain{
renderer: renderer,
}
}
func (g *GuiTestMain) OnLoad(loading d2screen.LoadingState) {
layout := d2gui.CreateLayout(d2gui.PositionTypeHorizontal)
layout := d2gui.CreateLayout(g.renderer, d2gui.PositionTypeHorizontal)
loading.Progress(0.3)
//
layoutLeft := layout.AddLayout(d2gui.PositionTypeVertical)
layoutLeft.SetHorizontalAlign(d2gui.HorizontalAlignCenter)
layoutLeft.AddLabel("FontStyle16Units", d2gui.FontStyle16Units)
_, _ = layoutLeft.AddLabel("FontStyle16Units", d2gui.FontStyle16Units)
layoutLeft.AddSpacerStatic(0, 100)
layoutLeft.AddLabel("FontStyle30Units", d2gui.FontStyle30Units)
layoutLeft.AddLabel("FontStyle42Units", d2gui.FontStyle42Units)
layoutLeft.AddLabel("FontStyleFormal10Static", d2gui.FontStyleFormal10Static)
layoutLeft.AddLabel("FontStyleFormal11Units", d2gui.FontStyleFormal11Units)
layoutLeft.AddLabel("FontStyleFormal12Static", d2gui.FontStyleFormal12Static)
_, _ = layoutLeft.AddLabel("FontStyle30Units", d2gui.FontStyle30Units)
_, _ = layoutLeft.AddLabel("FontStyle42Units", d2gui.FontStyle42Units)
_, _ = layoutLeft.AddLabel("FontStyleFormal10Static", d2gui.FontStyleFormal10Static)
_, _ = layoutLeft.AddLabel("FontStyleFormal11Units", d2gui.FontStyleFormal11Units)
_, _ = layoutLeft.AddLabel("FontStyleFormal12Static", d2gui.FontStyleFormal12Static)
loading.Progress(0.6)
layout.AddSpacerDynamic()
layoutRight := layout.AddLayout(d2gui.PositionTypeVertical)
layoutRight.SetHorizontalAlign(d2gui.HorizontalAlignRight)
layoutRight.AddButton("Medium", d2gui.ButtonStyleMedium)
layoutRight.AddButton("Narrow", d2gui.ButtonStyleNarrow)
layoutRight.AddButton("OkCancel", d2gui.ButtonStyleOkCancel)
layoutRight.AddButton("Short", d2gui.ButtonStyleShort)
layoutRight.AddButton("Wide", d2gui.ButtonStyleWide)
_, _ = layoutRight.AddButton("Medium", d2gui.ButtonStyleMedium)
_, _ = layoutRight.AddButton("Narrow", d2gui.ButtonStyleNarrow)
_, _ = layoutRight.AddButton("OkCancel", d2gui.ButtonStyleOkCancel)
_, _ = layoutRight.AddButton("Short", d2gui.ButtonStyleShort)
_, _ = layoutRight.AddButton("Wide", d2gui.ButtonStyleWide)
loading.Progress(0.9)
layout.SetVerticalAlign(d2gui.VerticalAlignMiddle)
d2gui.SetLayout(layout)
}
func (g *GuiTestMain) Render(screen d2interface.Surface) error {
func (g *GuiTestMain) Render(_ d2interface.Surface) error {
return nil
}
func (g *GuiTestMain) Advance(tickTime float64) error {
func (g *GuiTestMain) Advance(_ float64) error {
return nil
}

View File

@ -69,15 +69,17 @@ type MainMenu struct {
tcpJoinGameEntry d2ui.TextBox
screenMode mainMenuScreenMode
leftButtonHeld bool
renderer d2interface.Renderer
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
}
// CreateMainMenu creates an instance of MainMenu
func CreateMainMenu(audioProvider d2interface.AudioProvider, term d2interface.Terminal) *MainMenu {
func CreateMainMenu(renderer d2interface.Renderer, audioProvider d2interface.AudioProvider, term d2interface.Terminal) *MainMenu {
return &MainMenu{
screenMode: screenModeUnknown,
leftButtonHeld: true,
renderer: renderer,
audioProvider: audioProvider,
terminal: term,
}
@ -93,7 +95,7 @@ func (v *MainMenu) OnLoad(loading d2screen.LoadingState) {
v.createLogos(loading)
v.createButtons(loading)
v.tcpJoinGameEntry = d2ui.CreateTextbox()
v.tcpJoinGameEntry = d2ui.CreateTextbox(v.renderer)
v.tcpJoinGameEntry.SetPosition(318, 245)
v.tcpJoinGameEntry.SetFilter("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890._:")
d2ui.AddWidget(&v.tcpJoinGameEntry)
@ -129,44 +131,44 @@ func (v *MainMenu) loadBackgroundSprites() {
}
func (v *MainMenu) createLabels(loading d2screen.LoadingState) {
v.versionLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel = d2ui.CreateLabel(v.renderer, d2resource.FontFormal12, d2resource.PaletteStatic)
v.versionLabel.Alignment = d2ui.LabelAlignRight
v.versionLabel.SetText("OpenDiablo2 - " + d2common.BuildInfo.Branch)
v.versionLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.versionLabel.SetPosition(795, -10)
v.commitLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel = d2ui.CreateLabel(v.renderer, d2resource.FontFormal10, d2resource.PaletteStatic)
v.commitLabel.Alignment = d2ui.LabelAlignLeft
v.commitLabel.SetText(d2common.BuildInfo.Commit)
v.commitLabel.Color = color.RGBA{R: 255, G: 255, B: 255, A: 255}
v.commitLabel.SetPosition(2, 2)
v.copyrightLabel = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel = d2ui.CreateLabel(v.renderer, d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel.SetText("Diablo 2 is © Copyright 2000-2016 Blizzard Entertainment")
v.copyrightLabel.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel.SetPosition(400, 500)
loading.Progress(0.3)
v.copyrightLabel2 = d2ui.CreateLabel(d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2 = d2ui.CreateLabel(v.renderer, d2resource.FontFormal12, d2resource.PaletteStatic)
v.copyrightLabel2.Alignment = d2ui.LabelAlignCenter
v.copyrightLabel2.SetText("All Rights Reserved.")
v.copyrightLabel2.Color = color.RGBA{R: 188, G: 168, B: 140, A: 255}
v.copyrightLabel2.SetPosition(400, 525)
v.openDiabloLabel = d2ui.CreateLabel(d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel = d2ui.CreateLabel(v.renderer, d2resource.FontFormal10, d2resource.PaletteStatic)
v.openDiabloLabel.Alignment = d2ui.LabelAlignCenter
v.openDiabloLabel.SetText("OpenDiablo2 is neither developed by, nor endorsed by Blizzard or its parent company Activision")
v.openDiabloLabel.Color = color.RGBA{R: 255, G: 255, B: 140, A: 255}
v.openDiabloLabel.SetPosition(400, 580)
loading.Progress(0.5)
v.tcpIPOptionsLabel = d2ui.CreateLabel(d2resource.Font42, d2resource.PaletteUnits)
v.tcpIPOptionsLabel = d2ui.CreateLabel(v.renderer, d2resource.Font42, d2resource.PaletteUnits)
v.tcpIPOptionsLabel.SetPosition(400, 23)
v.tcpIPOptionsLabel.Alignment = d2ui.LabelAlignCenter
v.tcpIPOptionsLabel.SetText("TCP/IP Options")
v.tcpJoinGameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.tcpJoinGameLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.tcpJoinGameLabel.Alignment = d2ui.LabelAlignCenter
v.tcpJoinGameLabel.SetText(d2common.CombineStrings(
d2common.SplitIntoLinesWithMaxWidth("Enter Host IP Address to Join Game", 23)))
@ -199,47 +201,47 @@ func (v *MainMenu) createLogos(loading d2screen.LoadingState) {
}
func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
v.exitDiabloButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "EXIT DIABLO II")
v.exitDiabloButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "EXIT DIABLO II")
v.exitDiabloButton.SetPosition(264, 535)
v.exitDiabloButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitDiabloButton)
v.creditsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, "CREDITS")
v.creditsButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeShort, "CREDITS")
v.creditsButton.SetPosition(264, 505)
v.creditsButton.OnActivated(func() { v.onCreditsButtonClicked() })
d2ui.AddWidget(&v.creditsButton)
v.cinematicsButton = d2ui.CreateButton(d2ui.ButtonTypeShort, "CINEMATICS")
v.cinematicsButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeShort, "CINEMATICS")
v.cinematicsButton.SetPosition(401, 505)
d2ui.AddWidget(&v.cinematicsButton)
loading.Progress(0.7)
v.singlePlayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "SINGLE PLAYER")
v.singlePlayerButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "SINGLE PLAYER")
v.singlePlayerButton.SetPosition(264, 290)
v.singlePlayerButton.OnActivated(func() { v.onSinglePlayerClicked() })
d2ui.AddWidget(&v.singlePlayerButton)
v.githubButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "PROJECT WEBSITE")
v.githubButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "PROJECT WEBSITE")
v.githubButton.SetPosition(264, 400)
v.githubButton.OnActivated(func() { v.onGithubButtonClicked() })
d2ui.AddWidget(&v.githubButton)
v.mapTestButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MAP ENGINE TEST")
v.mapTestButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "MAP ENGINE TEST")
v.mapTestButton.SetPosition(264, 440)
v.mapTestButton.OnActivated(func() { v.onMapTestClicked() })
d2ui.AddWidget(&v.mapTestButton)
v.btnTCPIPCancel = d2ui.CreateButton(d2ui.ButtonTypeMedium, d2common.TranslateString("cancel"))
v.btnTCPIPCancel = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, d2common.TranslateString("cancel"))
v.btnTCPIPCancel.SetPosition(33, 543)
v.btnTCPIPCancel.OnActivated(func() { v.onTCPIPCancelClicked() })
d2ui.AddWidget(&v.btnTCPIPCancel)
v.btnServerIPCancel = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, "CANCEL")
v.btnServerIPCancel = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "CANCEL")
v.btnServerIPCancel.SetPosition(285, 305)
v.btnServerIPCancel.OnActivated(func() { v.onBtnTCPIPCancelClicked() })
d2ui.AddWidget(&v.btnServerIPCancel)
v.btnServerIPOk = d2ui.CreateButton(d2ui.ButtonTypeOkCancel, "OK")
v.btnServerIPOk = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeOkCancel, "OK")
v.btnServerIPOk.SetPosition(420, 305)
v.btnServerIPOk.OnActivated(func() { v.onBtnTCPIPOkClicked() })
d2ui.AddWidget(&v.btnServerIPOk)
@ -249,44 +251,46 @@ func (v *MainMenu) createButtons(loading d2screen.LoadingState) {
}
func (v *MainMenu) createMultiplayerMenuButtons() {
v.multiplayerButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "MULTIPLAYER")
v.multiplayerButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "MULTIPLAYER")
v.multiplayerButton.SetPosition(264, 330)
v.multiplayerButton.OnActivated(func() { v.onMultiplayerClicked() })
d2ui.AddWidget(&v.multiplayerButton)
v.networkTCPIPButton = d2ui.CreateButton(d2ui.ButtonTypeWide, "TCP/IP GAME")
v.networkTCPIPButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "TCP/IP GAME")
v.networkTCPIPButton.SetPosition(264, 280)
v.networkTCPIPButton.OnActivated(func() { v.onNetworkTCPIPClicked() })
d2ui.AddWidget(&v.networkTCPIPButton)
v.networkCancelButton = d2ui.CreateButton(d2ui.ButtonTypeWide, d2common.TranslateString("cancel"))
v.networkCancelButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, d2common.TranslateString("cancel"))
v.networkCancelButton.SetPosition(264, 540)
v.networkCancelButton.OnActivated(func() { v.onNetworkCancelClicked() })
d2ui.AddWidget(&v.networkCancelButton)
v.btnTCPIPHostGame = d2ui.CreateButton(d2ui.ButtonTypeWide, "HOST GAME")
v.btnTCPIPHostGame = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "HOST GAME")
v.btnTCPIPHostGame.SetPosition(264, 280)
v.btnTCPIPHostGame.OnActivated(func() { v.onTCPIPHostGameClicked() })
d2ui.AddWidget(&v.btnTCPIPHostGame)
v.btnTCPIPJoinGame = d2ui.CreateButton(d2ui.ButtonTypeWide, "JOIN GAME")
v.btnTCPIPJoinGame = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeWide, "JOIN GAME")
v.btnTCPIPJoinGame.SetPosition(264, 320)
v.btnTCPIPJoinGame.OnActivated(func() { v.onTCPIPJoinGameClicked() })
d2ui.AddWidget(&v.btnTCPIPJoinGame)
}
func (v *MainMenu) onMapTestClicked() {
d2screen.SetNextScreen(CreateMapEngineTest(0, 1, v.terminal))
d2screen.SetNextScreen(CreateMapEngineTest(0, 1, v.terminal, v.renderer))
}
func (v *MainMenu) onSinglePlayerClicked() {
// Go here only if existing characters are available to select
if d2player.HasGameStates() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal))
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider, d2clientconnectiontype.Local,
v.tcpJoinGameEntry.GetText(), v.terminal))
return
}
d2screen.SetNextScreen(CreateSelectHeroClass(v.audioProvider, d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal))
d2screen.SetNextScreen(CreateSelectHeroClass(v.renderer, v.audioProvider,
d2clientconnectiontype.Local, v.tcpJoinGameEntry.GetText(), v.terminal))
}
func (v *MainMenu) onGithubButtonClicked() {
@ -315,7 +319,7 @@ func (v *MainMenu) onExitButtonClicked() {
}
func (v *MainMenu) onCreditsButtonClicked() {
d2screen.SetNextScreen(CreateCredits(v.audioProvider))
d2screen.SetNextScreen(CreateCredits(v.renderer, v.audioProvider))
}
// Render renders the main menu
@ -480,7 +484,8 @@ func (v *MainMenu) onTCPIPCancelClicked() {
}
func (v *MainMenu) onTCPIPHostGameClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANServer, "", v.terminal))
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider,
d2clientconnectiontype.LANServer, "", v.terminal))
}
func (v *MainMenu) onTCPIPJoinGameClicked() {
@ -492,5 +497,6 @@ func (v *MainMenu) onBtnTCPIPCancelClicked() {
}
func (v *MainMenu) onBtnTCPIPOkClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText(), v.terminal))
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider,
d2clientconnectiontype.LANClient, v.tcpJoinGameEntry.GetText(), v.terminal))
}

View File

@ -84,6 +84,7 @@ type MapEngineTest struct {
mapEngine *d2mapengine.MapEngine
mapRenderer *d2maprenderer.MapRenderer
terminal d2interface.Terminal
renderer d2interface.Renderer
//TODO: this is region specific properties, should be refactored for multi-region rendering
currentRegion int
@ -95,7 +96,7 @@ type MapEngineTest struct {
}
// CreateMapEngineTest creates the Map Engine Test screen and returns a pointer to it
func CreateMapEngineTest(currentRegion, levelPreset int, term d2interface.Terminal) *MapEngineTest {
func CreateMapEngineTest(currentRegion, levelPreset int, term d2interface.Terminal, renderer d2interface.Renderer) *MapEngineTest {
result := &MapEngineTest{
currentRegion: currentRegion,
levelPreset: levelPreset,
@ -103,6 +104,7 @@ func CreateMapEngineTest(currentRegion, levelPreset int, term d2interface.Termin
regionSpec: regionSpec{},
filesCount: 0,
terminal: term,
renderer: renderer,
}
result.gameState = d2player.CreateTestGameState()
@ -165,7 +167,7 @@ func (met *MapEngineTest) OnLoad(loading d2screen.LoadingState) {
loading.Progress(0.5)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.mapEngine, met.terminal)
met.mapRenderer = d2maprenderer.CreateMapRenderer(met.renderer, met.mapEngine, met.terminal)
loading.Progress(0.7)
met.loadRegionByIndex(met.currentRegion, met.levelPreset, met.fileIndex)

View File

@ -69,9 +69,11 @@ type SelectHeroClass struct {
connectionHost string
audioProvider d2interface.AudioProvider
terminal d2interface.Terminal
renderer d2interface.Renderer
}
func CreateSelectHeroClass(
renderer d2interface.Renderer,
audioProvider d2interface.AudioProvider,
connectionType d2clientconnectiontype.ClientConnectionType,
connectionHost string,
@ -84,6 +86,7 @@ func CreateSelectHeroClass(
connectionHost: connectionHost,
audioProvider: audioProvider,
terminal: terminal,
renderer: renderer,
}
return result
@ -96,26 +99,26 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) {
v.bgImage = loadSprite(d2resource.CharacterSelectBackground, d2resource.PaletteFechar)
v.bgImage.SetPosition(0, 0)
v.headingLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
v.headingLabel = d2ui.CreateLabel(v.renderer, d2resource.Font30, d2resource.PaletteUnits)
fontWidth, _ := v.headingLabel.GetSize()
v.headingLabel.SetPosition(400-fontWidth/2, 17)
v.headingLabel.SetText("Select Hero Class")
v.headingLabel.Alignment = d2ui.LabelAlignCenter
v.heroClassLabel = d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel = d2ui.CreateLabel(v.renderer, d2resource.Font30, d2resource.PaletteUnits)
v.heroClassLabel.Alignment = d2ui.LabelAlignCenter
v.heroClassLabel.SetPosition(400, 65)
v.heroDesc1Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc1Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc1Label.SetPosition(400, 100)
loading.Progress(0.3)
v.heroDesc2Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc2Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc2Label.SetPosition(400, 115)
v.heroDesc3Label = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc3Label = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.heroDesc3Label.Alignment = d2ui.LabelAlignCenter
v.heroDesc3Label.SetPosition(400, 130)
@ -124,47 +127,47 @@ func (v *SelectHeroClass) OnLoad(loading d2screen.LoadingState) {
v.campfire.PlayForward()
v.campfire.SetBlend(true)
v.exitButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, "EXIT")
v.exitButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "EXIT")
v.exitButton.SetPosition(33, 537)
v.exitButton.OnActivated(func() { v.onExitButtonClicked() })
d2ui.AddWidget(&v.exitButton)
v.okButton = d2ui.CreateButton(d2ui.ButtonTypeMedium, "OK")
v.okButton = d2ui.CreateButton(v.renderer, d2ui.ButtonTypeMedium, "OK")
v.okButton.SetPosition(630, 537)
v.okButton.OnActivated(func() { v.onOkButtonClicked() })
v.okButton.SetVisible(false)
v.okButton.SetEnabled(false)
d2ui.AddWidget(&v.okButton)
v.heroNameLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.heroNameLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.heroNameLabel.Alignment = d2ui.LabelAlignLeft
v.heroNameLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.heroNameLabel.SetText("Character Name")
v.heroNameLabel.SetPosition(321, 475)
loading.Progress(0.4)
v.heroNameTextbox = d2ui.CreateTextbox()
v.heroNameTextbox = d2ui.CreateTextbox(v.renderer)
v.heroNameTextbox.SetPosition(318, 493)
v.heroNameTextbox.SetVisible(false)
d2ui.AddWidget(&v.heroNameTextbox)
v.expansionCheckbox = d2ui.CreateCheckbox(true)
v.expansionCheckbox = d2ui.CreateCheckbox(v.renderer, true)
v.expansionCheckbox.SetPosition(318, 526)
v.expansionCheckbox.SetVisible(false)
d2ui.AddWidget(&v.expansionCheckbox)
v.expansionCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.expansionCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.expansionCharLabel.Alignment = d2ui.LabelAlignLeft
v.expansionCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.expansionCharLabel.SetText("EXPANSION CHARACTER")
v.expansionCharLabel.SetPosition(339, 526)
v.hardcoreCheckbox = d2ui.CreateCheckbox(false)
v.hardcoreCheckbox = d2ui.CreateCheckbox(v.renderer, false)
v.hardcoreCheckbox.SetPosition(318, 548)
v.hardcoreCheckbox.SetVisible(false)
d2ui.AddWidget(&v.hardcoreCheckbox)
v.hardcoreCharLabel = d2ui.CreateLabel(d2resource.Font16, d2resource.PaletteUnits)
v.hardcoreCharLabel = d2ui.CreateLabel(v.renderer, d2resource.Font16, d2resource.PaletteUnits)
v.hardcoreCharLabel.Alignment = d2ui.LabelAlignLeft
v.hardcoreCharLabel.Color = color.RGBA{R: 216, G: 196, B: 128, A: 255}
v.hardcoreCharLabel.SetText("Hardcore")
@ -440,36 +443,46 @@ func (v *SelectHeroClass) OnUnload() error {
}
func (v *SelectHeroClass) onExitButtonClicked() {
d2screen.SetNextScreen(CreateCharacterSelect(v.audioProvider, v.connectionType, v.connectionHost, v.terminal))
d2screen.SetNextScreen(CreateCharacterSelect(v.renderer, v.audioProvider, v.connectionType,
v.connectionHost, v.terminal))
}
func (v *SelectHeroClass) onOkButtonClicked() {
gameState := d2player.CreatePlayerState(v.heroNameTextbox.GetText(), v.selectedHero, d2datadict.CharStats[v.selectedHero], v.hardcoreCheckbox.GetCheckState())
gameState := d2player.CreatePlayerState(v.heroNameTextbox.GetText(), v.selectedHero,
d2datadict.CharStats[v.selectedHero], v.hardcoreCheckbox.GetCheckState())
gameClient, _ := d2client.Create(d2clientconnectiontype.Local)
gameClient.Open(v.connectionHost, gameState.FilePath)
d2screen.SetNextScreen(CreateGame(v.audioProvider, gameClient, v.terminal))
_ = gameClient.Open(v.connectionHost, gameState.FilePath)
d2screen.SetNextScreen(CreateGame(v.renderer, v.audioProvider, gameClient, v.terminal))
}
func (v *SelectHeroClass) Render(screen d2interface.Surface) error {
v.bgImage.RenderSegmented(screen, 4, 3, 0)
_ = v.bgImage.RenderSegmented(screen, 4, 3, 0)
v.headingLabel.Render(screen)
if v.selectedHero != d2enum.HeroNone {
v.heroClassLabel.Render(screen)
v.heroDesc1Label.Render(screen)
v.heroDesc2Label.Render(screen)
v.heroDesc3Label.Render(screen)
}
for heroClass, heroInfo := range v.heroRenderInfo {
if heroInfo.Stance == d2enum.HeroStanceIdle || heroInfo.Stance == d2enum.HeroStanceIdleSelected {
v.renderHero(screen, heroClass)
}
}
for heroClass, heroInfo := range v.heroRenderInfo {
if heroInfo.Stance != d2enum.HeroStanceIdle && heroInfo.Stance != d2enum.HeroStanceIdleSelected {
v.renderHero(screen, heroClass)
}
}
v.campfire.Render(screen)
if err := v.campfire.Render(screen); err != nil {
return err
}
if v.heroNameTextbox.GetVisible() {
v.heroNameLabel.Render(screen)
v.expansionCharLabel.Render(screen)
@ -481,17 +494,26 @@ func (v *SelectHeroClass) Render(screen d2interface.Surface) error {
func (v *SelectHeroClass) Advance(tickTime float64) error {
canSelect := true
v.campfire.Advance(tickTime)
for _, info := range v.heroRenderInfo {
info.Advance(tickTime)
if info.Stance != d2enum.HeroStanceIdle && info.Stance != d2enum.HeroStanceIdleSelected && info.Stance != d2enum.HeroStanceSelected {
if err := v.campfire.Advance(tickTime); err != nil {
return err
}
for infoIdx := range v.heroRenderInfo {
v.heroRenderInfo[infoIdx].Advance(tickTime)
if v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdle &&
v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceIdleSelected &&
v.heroRenderInfo[infoIdx].Stance != d2enum.HeroStanceSelected {
canSelect = false
}
}
for heroType, _ := range v.heroRenderInfo {
v.updateHeroSelectionHover(heroType, canSelect)
for heroTypeIdx := range v.heroRenderInfo {
v.updateHeroSelectionHover(heroTypeIdx, canSelect)
}
v.okButton.SetEnabled(len(v.heroNameTextbox.GetText()) >= 2 && v.selectedHero != d2enum.HeroNone)
return nil
}
@ -548,10 +570,12 @@ func (v *SelectHeroClass) updateHeroSelectionHover(hero d2enum.Hero, canSelect b
}
if mouseHover && renderInfo.Stance != d2enum.HeroStanceIdleSelected {
renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame())
_ = renderInfo.IdleSelectedSprite.SetCurrentFrame(renderInfo.IdleSprite.GetCurrentFrame())
renderInfo.Stance = d2enum.HeroStanceIdleSelected
} else if !mouseHover && renderInfo.Stance != d2enum.HeroStanceIdle {
renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame())
_ = renderInfo.IdleSprite.SetCurrentFrame(renderInfo.IdleSelectedSprite.GetCurrentFrame())
renderInfo.Stance = d2enum.HeroStanceIdle
}
@ -652,13 +676,13 @@ func setSpriteToFirstFrame(sprite *d2ui.Sprite) {
func drawSprite(sprite *d2ui.Sprite, target d2interface.Surface) {
if sprite != nil {
sprite.Render(target)
_ = sprite.Render(target)
}
}
func advanceSprite(sprite *d2ui.Sprite, elapsed float64) {
if sprite != nil {
sprite.Advance(elapsed)
_ = sprite.Advance(elapsed)
}
}

View File

@ -39,15 +39,16 @@ var rightMenuRect = d2common.Rectangle{Left: 400, Top: 0, Width: 400, Height: 60
var bottomMenuRect = d2common.Rectangle{Left: 0, Top: 550, Width: 800, Height: 50}
type GameControls struct {
hero *d2mapentity.Player
mapEngine *d2mapengine.MapEngine
mapRenderer *d2maprenderer.MapRenderer
inventory *Inventory
heroStatsPanel *HeroStatsPanel
inputListener InputCallbackListener
FreeCam bool
lastMouseX int
lastMouseY int
renderer d2interface.Renderer // TODO: This shouldn't be a dependency
hero *d2mapentity.Player
mapEngine *d2mapengine.MapEngine
mapRenderer *d2maprenderer.MapRenderer
inventory *Inventory
heroStatsPanel *HeroStatsPanel
inputListener InputCallbackListener
FreeCam bool
lastMouseX int
lastMouseY int
// UI
globeSprite *d2ui.Sprite
@ -80,27 +81,29 @@ const (
rightSkill = ActionableType(iota)
)
func NewGameControls(hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine, mapRenderer *d2maprenderer.MapRenderer, inputListener InputCallbackListener, term d2interface.Terminal) *GameControls {
func NewGameControls(renderer d2interface.Renderer, hero *d2mapentity.Player, mapEngine *d2mapengine.MapEngine,
mapRenderer *d2maprenderer.MapRenderer, inputListener InputCallbackListener, term d2interface.Terminal) *GameControls {
term.BindAction("setmissile", "set missile id to summon on right click", func(id int) {
missileID = id
})
zoneLabel := d2ui.CreateLabel(d2resource.Font30, d2resource.PaletteUnits)
zoneLabel := d2ui.CreateLabel(renderer, d2resource.Font30, d2resource.PaletteUnits)
zoneLabel.Color = color.RGBA{R: 255, G: 88, B: 82, A: 255}
zoneLabel.Alignment = d2ui.LabelAlignCenter
nameLabel := d2ui.CreateLabel(d2resource.FontFormal11, d2resource.PaletteStatic)
nameLabel := d2ui.CreateLabel(renderer, d2resource.FontFormal11, d2resource.PaletteStatic)
nameLabel.Alignment = d2ui.LabelAlignCenter
nameLabel.SetText("")
nameLabel.Color = color.White
gc := &GameControls{
renderer: renderer,
hero: hero,
mapEngine: mapEngine,
inputListener: inputListener,
mapRenderer: mapRenderer,
inventory: NewInventory(),
heroStatsPanel: NewHeroStatsPanel(hero.Name(), hero.Class, hero.Stats),
heroStatsPanel: NewHeroStatsPanel(renderer, hero.Name(), hero.Class, hero.Stats),
nameLabel: &nameLabel,
zoneChangeText: &zoneLabel,
actionableRegions: []ActionableRegion{
@ -269,7 +272,7 @@ func (g *GameControls) Load() {
func (g *GameControls) loadUIButtons() {
// Run button
g.runButton = d2ui.CreateButton(d2ui.ButtonTypeRun, "")
g.runButton = d2ui.CreateButton(g.renderer, d2ui.ButtonTypeRun, "")
g.runButton.SetPosition(255, 570)
g.runButton.OnActivated(func() { g.onToggleRunButton() })
if g.hero.IsRunToggled() {

View File

@ -9,7 +9,6 @@ import (
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2hero"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
@ -74,6 +73,7 @@ type HeroStatsPanel struct {
heroState *d2hero.HeroStatsState
heroName string
heroClass d2enum.Hero
renderer d2interface.Renderer
staticMenuImageCache *d2interface.Surface
labels *StatsPanelLabels
@ -82,11 +82,13 @@ type HeroStatsPanel struct {
isOpen bool
}
func NewHeroStatsPanel(heroName string, heroClass d2enum.Hero, heroState d2hero.HeroStatsState) *HeroStatsPanel {
func NewHeroStatsPanel(renderer d2interface.Renderer, heroName string, heroClass d2enum.Hero,
heroState d2hero.HeroStatsState) *HeroStatsPanel {
originX := 0
originY := 0
return &HeroStatsPanel{
renderer: renderer,
originX: originX,
originY: originY,
heroState: &heroState,
@ -128,7 +130,7 @@ func (s *HeroStatsPanel) Render(target d2interface.Surface) {
if s.staticMenuImageCache == nil {
frameWidth, frameHeight := s.frame.GetFrameBounds()
framesCount := s.frame.GetFrameCount()
surface, err := d2render.NewSurface(frameWidth*framesCount, frameHeight*framesCount, d2interface.FilterNearest)
surface, err := s.renderer.NewSurface(frameWidth*framesCount, frameHeight*framesCount, d2interface.FilterNearest)
if err != nil {
return
@ -274,7 +276,7 @@ func (s *HeroStatsPanel) createStatValueLabel(stat int, x int, y int) d2ui.Label
}
func (s *HeroStatsPanel) createTextLabel(element PanelText) d2ui.Label {
label := d2ui.CreateLabel(element.Font, d2resource.PaletteStatic)
label := d2ui.CreateLabel(s.renderer, element.Font, d2resource.PaletteStatic)
if element.AlignCenter {
label.Alignment = d2ui.LabelAlignCenter
}

3
go.mod
View File

@ -7,11 +7,12 @@ require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 // indirect
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d // indirect
github.com/go-restruct/restruct v0.0.0-20191227155143-5734170a48a1
github.com/hajimehoshi/ebiten v1.12.0-alpha.6.0.20200629133528-780465b702ce
github.com/hajimehoshi/ebiten v1.12.0-alpha.7.0.20200703165837-6c33ed107f28
github.com/pkg/profile v1.5.0
github.com/robertkrimen/otto v0.0.0-20191219234010-c382bd3c16ff
github.com/satori/go.uuid v1.2.0
github.com/stretchr/testify v1.4.0
github.com/veandco/go-sdl2 v0.4.4 // indirect
golang.org/x/image v0.0.0-20200119044424-58c23975cae1
gopkg.in/alecthomas/kingpin.v2 v2.2.6
gopkg.in/sourcemap.v1 v1.0.5 // indirect

6
go.sum
View File

@ -23,6 +23,8 @@ github.com/hajimehoshi/ebiten v1.12.0-alpha.5.0.20200627174955-aea4630b5f84 h1:B
github.com/hajimehoshi/ebiten v1.12.0-alpha.5.0.20200627174955-aea4630b5f84/go.mod h1:8vzUI4e0fBkbONYOY4WJN/qikY2zv/VG6kFTzJ0B//o=
github.com/hajimehoshi/ebiten v1.12.0-alpha.6.0.20200629133528-780465b702ce h1:cEKWqbtxFremkIRhJxz0Z80wXqNNe8ZNk6ra8XASC1I=
github.com/hajimehoshi/ebiten v1.12.0-alpha.6.0.20200629133528-780465b702ce/go.mod h1:8vzUI4e0fBkbONYOY4WJN/qikY2zv/VG6kFTzJ0B//o=
github.com/hajimehoshi/ebiten v1.12.0-alpha.7.0.20200703165837-6c33ed107f28 h1:su0k5pB/7j3FCoLsXGoPNWMJW7phujO0GC8sViJ07ow=
github.com/hajimehoshi/ebiten v1.12.0-alpha.7.0.20200703165837-6c33ed107f28/go.mod h1:vDl2Rhoz8i09Red8XR3B+/Jw+IubfG+V9SDBgQOEI8I=
github.com/hajimehoshi/go-mp3 v0.2.1/go.mod h1:Rr+2P46iH6PwTPVgSsEwBkon0CK5DxCAeX/Rp65DCTE=
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/oto v0.3.4/go.mod h1:PgjqsBJff0efqL2nlMJidJgVJywLn6M4y8PI4TfeWfA=
@ -54,6 +56,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/veandco/go-sdl2 v0.4.4 h1:coOJGftOdvNvGoUIZmm4XD+ZRQF4mg9ZVHmH3/42zFQ=
github.com/veandco/go-sdl2 v0.4.4/go.mod h1:FB+kTpX9YTE+urhYiClnRzpOXbiWgaU3+5F2AB78DPg=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@ -74,6 +78,8 @@ golang.org/x/mobile v0.0.0-20200222142934-3c8601c510d0 h1:nZASbxDuz7CO3227BWCCf0
golang.org/x/mobile v0.0.0-20200222142934-3c8601c510d0/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007 h1:JxsyO7zPDWn1rBZW8FV5RFwCKqYeXnyaS/VQPLpXu6I=
golang.org/x/mobile v0.0.0-20200329125638-4c31acba0007/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mobile v0.0.0-20200629153529-33b80540585f h1:9MxnlCHwn6IfUTinHBBzcBhmrX4OXfRmi954tWGKq+M=
golang.org/x/mobile v0.0.0-20200629153529-33b80540585f/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=

10
main.go
View File

@ -3,6 +3,8 @@ package main
import (
"log"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2render/ebiten"
"github.com/OpenDiablo2/OpenDiablo2/d2app"
ebiten_input "github.com/OpenDiablo2/OpenDiablo2/d2core/d2input/ebiten"
@ -26,18 +28,24 @@ func main() {
log.Println("OpenDiablo2 - Open source Diablo 2 engine")
// Initialize our providers
renderer, err := ebiten.CreateRenderer()
if err != nil {
panic(err)
}
audio, err := ebiten2.CreateAudio()
if err != nil {
panic(err)
}
d2input.Initialize(ebiten_input.InputService{}) // TODO d2input singleton must be init before d2term
term, err := d2term.Initialize()
if err != nil {
log.Fatal(err)
}
app := d2app.Create(GitBranch, GitCommit, term, audio)
app := d2app.Create(GitBranch, GitCommit, term, audio, renderer)
app.Run()
}