Stabilize Load Screen by Deferring SDL2 Calls
* The loading screen for Edit and Play modes is stable and the risk of game crash is removed. The root cause was the setupAsync() functions running on a background goroutine, and running SDL2 draw functions while NOT on the main thread, which causes problems. * The fix is all SDL2 Texture draws become lazy loaded: when the main thread is presenting, any Wallpaper or ui.Image that has no texture yet gets one created at that time from the cached image.Image. * All internal game logic then uses image.Image types, to cache bitmaps of Level Chunks, Wallpaper images, Sprite icons, etc. and the game is free to prepare these asynchronously; only the main thread ever Presents and the SDL2 textures initialize on first appearance. * Several functions had arguments cleaned up: Canvas.LoadLevel() does not need the render.Engine as (e.g. wallpaper) textures don't render at that stage.
This commit is contained in:
parent
2d1b926e4f
commit
215ed5c847
|
@ -101,7 +101,7 @@ func (s *EditorScene) setupAsync(d *Doodle) error {
|
||||||
"Opening: "+s.Level.Title,
|
"Opening: "+s.Level.Title,
|
||||||
"by "+s.Level.Author,
|
"by "+s.Level.Author,
|
||||||
)
|
)
|
||||||
s.UI.Canvas.LoadLevel(d.Engine, s.Level)
|
s.UI.Canvas.LoadLevel(s.Level)
|
||||||
s.UI.Canvas.InstallActors(s.Level.Actors)
|
s.UI.Canvas.InstallActors(s.Level.Actors)
|
||||||
} else if s.filename != "" && s.OpenFile {
|
} else if s.filename != "" && s.OpenFile {
|
||||||
log.Debug("EditorScene.Setup: Loading map from filename at %s", s.filename)
|
log.Debug("EditorScene.Setup: Loading map from filename at %s", s.filename)
|
||||||
|
@ -132,7 +132,7 @@ func (s *EditorScene) setupAsync(d *Doodle) error {
|
||||||
log.Debug("EditorScene.Setup: initializing a new Level")
|
log.Debug("EditorScene.Setup: initializing a new Level")
|
||||||
s.Level = level.New()
|
s.Level = level.New()
|
||||||
s.Level.Palette = level.DefaultPalette()
|
s.Level.Palette = level.DefaultPalette()
|
||||||
s.UI.Canvas.LoadLevel(d.Engine, s.Level)
|
s.UI.Canvas.LoadLevel(s.Level)
|
||||||
s.UI.Canvas.ScrollTo(render.Origin)
|
s.UI.Canvas.ScrollTo(render.Origin)
|
||||||
s.UI.Canvas.Scrollable = true
|
s.UI.Canvas.Scrollable = true
|
||||||
}
|
}
|
||||||
|
@ -360,7 +360,7 @@ func (s *EditorScene) LoadLevel(filename string) error {
|
||||||
|
|
||||||
s.DrawingType = enum.LevelDrawing
|
s.DrawingType = enum.LevelDrawing
|
||||||
s.Level = level
|
s.Level = level
|
||||||
s.UI.Canvas.LoadLevel(s.d.Engine, s.Level)
|
s.UI.Canvas.LoadLevel(s.Level)
|
||||||
|
|
||||||
log.Info("Installing %d actors into the drawing", len(level.Actors))
|
log.Info("Installing %d actors into the drawing", len(level.Actors))
|
||||||
if err := s.UI.Canvas.InstallActors(level.Actors); err != nil {
|
if err := s.UI.Canvas.InstallActors(level.Actors); err != nil {
|
||||||
|
|
|
@ -131,7 +131,7 @@ func (u *EditorUI) SetupPopups(d *Doodle) {
|
||||||
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
||||||
scene.Level.PageType = pageType
|
scene.Level.PageType = pageType
|
||||||
scene.Level.Wallpaper = wallpaper
|
scene.Level.Wallpaper = wallpaper
|
||||||
u.Canvas.LoadLevel(d.Engine, scene.Level)
|
u.Canvas.LoadLevel(scene.Level)
|
||||||
},
|
},
|
||||||
OnCancel: func() {
|
OnCancel: func() {
|
||||||
u.levelSettingsWindow.Hide()
|
u.levelSettingsWindow.Hide()
|
||||||
|
@ -261,7 +261,7 @@ func (u *EditorUI) SetupPopups(d *Doodle) {
|
||||||
// Reload the level.
|
// Reload the level.
|
||||||
if scene.Level != nil {
|
if scene.Level != nil {
|
||||||
log.Warn("RELOAD LEVEL")
|
log.Warn("RELOAD LEVEL")
|
||||||
u.Canvas.LoadLevel(d.Engine, scene.Level)
|
u.Canvas.LoadLevel(scene.Level)
|
||||||
scene.Level.Chunker.Redraw()
|
scene.Level.Chunker.Redraw()
|
||||||
} else if scene.Doodad != nil {
|
} else if scene.Doodad != nil {
|
||||||
log.Warn("RELOAD DOODAD")
|
log.Warn("RELOAD DOODAD")
|
||||||
|
|
|
@ -244,7 +244,7 @@ func (s *MainScene) SetupDemoLevel(d *Doodle) error {
|
||||||
|
|
||||||
// Title screen level to load.
|
// Title screen level to load.
|
||||||
if lvl, err := level.LoadFile(balance.DemoLevelName); err == nil {
|
if lvl, err := level.LoadFile(balance.DemoLevelName); err == nil {
|
||||||
s.canvas.LoadLevel(d.Engine, lvl)
|
s.canvas.LoadLevel(lvl)
|
||||||
s.canvas.InstallActors(lvl.Actors)
|
s.canvas.InstallActors(lvl.Actors)
|
||||||
|
|
||||||
// Load all actor scripts.
|
// Load all actor scripts.
|
||||||
|
|
|
@ -96,7 +96,7 @@ func (s *MenuScene) Setup(d *Doodle) error {
|
||||||
W: d.width,
|
W: d.width,
|
||||||
H: d.height,
|
H: d.height,
|
||||||
})
|
})
|
||||||
s.canvas.LoadLevel(d.Engine, &level.Level{
|
s.canvas.LoadLevel(&level.Level{
|
||||||
Chunker: level.NewChunker(100),
|
Chunker: level.NewChunker(100),
|
||||||
Palette: level.NewPalette(),
|
Palette: level.NewPalette(),
|
||||||
PageType: level.Bounded,
|
PageType: level.Bounded,
|
||||||
|
@ -135,8 +135,8 @@ func (s *MenuScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
// configureCanvas updates the settings of the background canvas, so a live
|
// configureCanvas updates the settings of the background canvas, so a live
|
||||||
// preview of the wallpaper and wrapping type can be shown.
|
// preview of the wallpaper and wrapping type can be shown.
|
||||||
func (s *MenuScene) configureCanvas(e render.Engine, pageType level.PageType, wallpaper string) {
|
func (s *MenuScene) configureCanvas(pageType level.PageType, wallpaper string) {
|
||||||
s.canvas.LoadLevel(e, &level.Level{
|
s.canvas.LoadLevel(&level.Level{
|
||||||
Chunker: level.NewChunker(100),
|
Chunker: level.NewChunker(100),
|
||||||
Palette: level.NewPalette(),
|
Palette: level.NewPalette(),
|
||||||
PageType: pageType,
|
PageType: pageType,
|
||||||
|
@ -151,7 +151,7 @@ func (s *MenuScene) setupNewWindow(d *Doodle) error {
|
||||||
Engine: d.Engine,
|
Engine: d.Engine,
|
||||||
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
|
OnChangePageTypeAndWallpaper: func(pageType level.PageType, wallpaper string) {
|
||||||
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
log.Info("OnChangePageTypeAndWallpaper called: %+v, %+v", pageType, wallpaper)
|
||||||
s.configureCanvas(d.Engine, pageType, wallpaper)
|
s.configureCanvas(pageType, wallpaper)
|
||||||
},
|
},
|
||||||
OnCreateNewLevel: func(lvl *level.Level) {
|
OnCreateNewLevel: func(lvl *level.Level) {
|
||||||
d.Goto(&EditorScene{
|
d.Goto(&EditorScene{
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"git.kirsle.net/apps/doodle/pkg/balance"
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
||||||
"git.kirsle.net/apps/doodle/pkg/level"
|
"git.kirsle.net/apps/doodle/pkg/level"
|
||||||
|
"git.kirsle.net/apps/doodle/pkg/log"
|
||||||
"git.kirsle.net/apps/doodle/pkg/shmem"
|
"git.kirsle.net/apps/doodle/pkg/shmem"
|
||||||
"git.kirsle.net/apps/doodle/pkg/uix"
|
"git.kirsle.net/apps/doodle/pkg/uix"
|
||||||
"git.kirsle.net/go/render"
|
"git.kirsle.net/go/render"
|
||||||
|
@ -108,7 +109,7 @@ func setup() {
|
||||||
|
|
||||||
// Create the parent container that will stretch full screen.
|
// Create the parent container that will stretch full screen.
|
||||||
window = ui.NewFrame("Loadscreen Window")
|
window = ui.NewFrame("Loadscreen Window")
|
||||||
window.SetBackground(render.RGBA(0, 0, 1, 40))
|
window.SetBackground(render.RGBA(0, 0, 1, 40)) // makes the wallpaper darker? :/
|
||||||
|
|
||||||
// "Loading" text.
|
// "Loading" text.
|
||||||
label := ui.NewLabel(ui.Label{
|
label := ui.NewLabel(ui.Label{
|
||||||
|
@ -167,7 +168,7 @@ func Loop(windowSize render.Rect, e render.Engine) {
|
||||||
// Initialize the wallpaper canvas?
|
// Initialize the wallpaper canvas?
|
||||||
if canvas == nil {
|
if canvas == nil {
|
||||||
canvas = uix.NewCanvas(128, false)
|
canvas = uix.NewCanvas(128, false)
|
||||||
canvas.LoadLevel(e, &level.Level{
|
canvas.LoadLevel(&level.Level{
|
||||||
Chunker: level.NewChunker(100),
|
Chunker: level.NewChunker(100),
|
||||||
Palette: level.NewPalette(),
|
Palette: level.NewPalette(),
|
||||||
PageType: level.Bounded,
|
PageType: level.Bounded,
|
||||||
|
@ -215,8 +216,13 @@ func Loop(windowSize render.Rect, e render.Engine) {
|
||||||
// of chunks vs. chunks remaining to pre-cache bitmaps from.
|
// of chunks vs. chunks remaining to pre-cache bitmaps from.
|
||||||
func PreloadAllChunkBitmaps(chunker *level.Chunker) {
|
func PreloadAllChunkBitmaps(chunker *level.Chunker) {
|
||||||
loadChunksTarget := len(chunker.Chunks)
|
loadChunksTarget := len(chunker.Chunks)
|
||||||
|
// if loadChunksTarget == 0 {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
for {
|
for {
|
||||||
remaining := chunker.PrerenderN(10)
|
remaining := chunker.PrerenderN(10)
|
||||||
|
log.Info("Remain: %d", remaining)
|
||||||
|
|
||||||
// Set the load screen progress % based on number of chunks to render.
|
// Set the load screen progress % based on number of chunks to render.
|
||||||
if loadChunksTarget > 0 {
|
if loadChunksTarget > 0 {
|
||||||
|
|
|
@ -171,7 +171,7 @@ func (s *PlayScene) setupAsync(d *Doodle) error {
|
||||||
// Given a filename or map data to play?
|
// Given a filename or map data to play?
|
||||||
if s.Level != nil {
|
if s.Level != nil {
|
||||||
log.Debug("PlayScene.Setup: received level from scene caller")
|
log.Debug("PlayScene.Setup: received level from scene caller")
|
||||||
s.drawing.LoadLevel(d.Engine, s.Level)
|
s.drawing.LoadLevel(s.Level)
|
||||||
s.drawing.InstallActors(s.Level.Actors)
|
s.drawing.InstallActors(s.Level.Actors)
|
||||||
} else if s.Filename != "" {
|
} else if s.Filename != "" {
|
||||||
loadscreen.SetSubtitle("Opening: " + s.Filename)
|
loadscreen.SetSubtitle("Opening: " + s.Filename)
|
||||||
|
@ -183,7 +183,7 @@ func (s *PlayScene) setupAsync(d *Doodle) error {
|
||||||
if s.Level == nil {
|
if s.Level == nil {
|
||||||
log.Debug("PlayScene.Setup: no grid given, initializing empty grid")
|
log.Debug("PlayScene.Setup: no grid given, initializing empty grid")
|
||||||
s.Level = level.New()
|
s.Level = level.New()
|
||||||
s.drawing.LoadLevel(d.Engine, s.Level)
|
s.drawing.LoadLevel(s.Level)
|
||||||
s.drawing.InstallActors(s.Level.Actors)
|
s.drawing.InstallActors(s.Level.Actors)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,7 +611,7 @@ func (s *PlayScene) LoadLevel(filename string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Level = level
|
s.Level = level
|
||||||
s.drawing.LoadLevel(s.d.Engine, s.Level)
|
s.drawing.LoadLevel(s.Level)
|
||||||
s.drawing.InstallActors(s.Level.Actors)
|
s.drawing.InstallActors(s.Level.Actors)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -29,12 +29,7 @@ func LoadImage(e render.Engine, filename string) (*ui.Image, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tex, err := e.StoreTexture(filename, img)
|
return ui.ImageFromImage(img)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui.ImageFromTexture(tex), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WASM: try the file over HTTP ajax request.
|
// WASM: try the file over HTTP ajax request.
|
||||||
|
@ -49,12 +44,7 @@ func LoadImage(e render.Engine, filename string) (*ui.Image, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tex, err := e.StoreTexture(filename, img)
|
return ui.ImageFromImage(img)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui.ImageFromTexture(tex), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then try the file system.
|
// Then try the file system.
|
||||||
|
@ -71,12 +61,7 @@ func LoadImage(e render.Engine, filename string) (*ui.Image, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tex, err := e.StoreTexture(filename, img)
|
return ui.ImageFromImage(img)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return ui.ImageFromTexture(tex), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, errors.New("no such sprite found")
|
return nil, errors.New("no such sprite found")
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (s *StoryScene) Setup(d *Doodle) error {
|
||||||
// Set up the background wallpaper canvas.
|
// Set up the background wallpaper canvas.
|
||||||
s.canvas = uix.NewCanvas(100, false)
|
s.canvas = uix.NewCanvas(100, false)
|
||||||
s.canvas.Resize(render.NewRect(d.width, d.height))
|
s.canvas.Resize(render.NewRect(d.width, d.height))
|
||||||
s.canvas.LoadLevel(d.Engine, &level.Level{
|
s.canvas.LoadLevel(&level.Level{
|
||||||
Chunker: level.NewChunker(100),
|
Chunker: level.NewChunker(100),
|
||||||
Palette: level.NewPalette(),
|
Palette: level.NewPalette(),
|
||||||
PageType: level.Bounded,
|
PageType: level.Bounded,
|
||||||
|
|
|
@ -145,7 +145,7 @@ func (w *Canvas) Load(p *level.Palette, g *level.Chunker) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadLevel initializes a Canvas from a Level object.
|
// LoadLevel initializes a Canvas from a Level object.
|
||||||
func (w *Canvas) LoadLevel(e render.Engine, level *level.Level) {
|
func (w *Canvas) LoadLevel(level *level.Level) {
|
||||||
w.level = level
|
w.level = level
|
||||||
w.Load(level.Palette, level.Chunker)
|
w.Load(level.Palette, level.Chunker)
|
||||||
|
|
||||||
|
@ -159,14 +159,14 @@ func (w *Canvas) LoadLevel(e render.Engine, level *level.Level) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
wp, err := wallpaper.FromFile(e, filename, level)
|
wp, err := wallpaper.FromFile(filename, level)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("wallpaper FromFile(%s): %s", filename, err)
|
log.Error("wallpaper FromFile(%s): %s", filename, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
w.wallpaper.maxWidth = level.MaxWidth
|
w.wallpaper.maxWidth = level.MaxWidth
|
||||||
w.wallpaper.maxHeight = level.MaxHeight
|
w.wallpaper.maxHeight = level.MaxHeight
|
||||||
err = w.wallpaper.Load(e, level.PageType, wp)
|
err = w.wallpaper.Load(level.PageType, wp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("wallpaper Load: %s", err)
|
log.Error("wallpaper Load: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,15 @@ type Wallpaper struct {
|
||||||
pageType level.PageType
|
pageType level.PageType
|
||||||
maxWidth int64
|
maxWidth int64
|
||||||
maxHeight int64
|
maxHeight int64
|
||||||
corner render.Texturer
|
|
||||||
top render.Texturer
|
// Pointer to the Wallpaper datum.
|
||||||
left render.Texturer
|
WP *wallpaper.Wallpaper
|
||||||
repeat render.Texturer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Valid returns whether the Wallpaper is configured. Only Levels should
|
// Valid returns whether the Wallpaper is configured. Only Levels should
|
||||||
// have wallpapers and Doodads will have nil ones.
|
// have wallpapers and Doodads will have nil ones.
|
||||||
func (wp *Wallpaper) Valid() bool {
|
func (wp *Wallpaper) Valid() bool {
|
||||||
return wp.repeat != nil
|
return wp.WP != nil && wp.WP.Repeat() != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Canvas Loop() task that keeps mobile actors constrained inside the borders
|
// Canvas Loop() task that keeps mobile actors constrained inside the borders
|
||||||
|
@ -76,8 +75,8 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
var (
|
var (
|
||||||
wp = w.wallpaper
|
wp = w.wallpaper
|
||||||
S = w.Size()
|
S = w.Size()
|
||||||
size = wp.corner.Size()
|
size = wp.WP.QuarterRect()
|
||||||
sizeOrig = wp.corner.Size()
|
sizeOrig = wp.WP.QuarterRect()
|
||||||
|
|
||||||
// Get the relative viewport of world coordinates looked at by the canvas.
|
// Get the relative viewport of world coordinates looked at by the canvas.
|
||||||
// The X,Y values are the negative Scroll value
|
// The X,Y values are the negative Scroll value
|
||||||
|
@ -202,7 +201,9 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
src.H = sizeOrig.H
|
src.H = sizeOrig.H
|
||||||
}
|
}
|
||||||
|
|
||||||
e.Copy(wp.repeat, src, dst)
|
if tex, err := wp.WP.RepeatTexture(e); err == nil {
|
||||||
|
e.Copy(tex, src, dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,7 +228,9 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
||||||
e.Copy(wp.left, src, dst)
|
if tex, err := wp.WP.LeftTexture(e); err == nil {
|
||||||
|
e.Copy(tex, src, dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The top edge tiled along the top edge.
|
// The top edge tiled along the top edge.
|
||||||
|
@ -250,7 +253,9 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
||||||
e.Copy(wp.top, src, dst)
|
if tex, err := wp.WP.TopTexture(e); err == nil {
|
||||||
|
e.Copy(tex, src, dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The top left corner for all page types except Unbounded.
|
// The top left corner for all page types except Unbounded.
|
||||||
|
@ -273,38 +278,17 @@ func (w *Canvas) PresentWallpaper(e render.Engine, p render.Point) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
render.TrimBox(&src, &dst, p, S, w.BoxThickness(1))
|
||||||
e.Copy(wp.corner, src, dst)
|
if tex, err := wp.WP.CornerTexture(e); err == nil {
|
||||||
|
e.Copy(tex, src, dst)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the wallpaper settings from a level.
|
// Load the wallpaper settings from a level.
|
||||||
func (wp *Wallpaper) Load(e render.Engine, pageType level.PageType, v *wallpaper.Wallpaper) error {
|
func (wp *Wallpaper) Load(pageType level.PageType, v *wallpaper.Wallpaper) error {
|
||||||
wp.pageType = pageType
|
wp.pageType = pageType
|
||||||
if tex, err := v.CornerTexture(e); err == nil {
|
wp.WP = v
|
||||||
wp.corner = tex
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tex, err := v.TopTexture(e); err == nil {
|
|
||||||
wp.top = tex
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tex, err := v.LeftTexture(e); err == nil {
|
|
||||||
wp.left = tex
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if tex, err := v.RepeatTexture(e); err == nil {
|
|
||||||
wp.repeat = tex
|
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,19 +48,19 @@ type Wallpaper struct {
|
||||||
// FromImage creates a Wallpaper from an image.Image.
|
// FromImage creates a Wallpaper from an image.Image.
|
||||||
// If the renger.Engine is nil it will compute images but not pre-cache any
|
// If the renger.Engine is nil it will compute images but not pre-cache any
|
||||||
// textures yet.
|
// textures yet.
|
||||||
func FromImage(e render.Engine, img *image.RGBA, name string) (*Wallpaper, error) {
|
func FromImage(img *image.RGBA, name string) (*Wallpaper, error) {
|
||||||
wp := &Wallpaper{
|
wp := &Wallpaper{
|
||||||
Name: name,
|
Name: name,
|
||||||
Image: img,
|
Image: img,
|
||||||
}
|
}
|
||||||
wp.cache(e)
|
wp.cache()
|
||||||
return wp, nil
|
return wp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromFile creates a Wallpaper from a file on disk.
|
// FromFile creates a Wallpaper from a file on disk.
|
||||||
// If the renger.Engine is nil it will compute images but not pre-cache any
|
// If the renger.Engine is nil it will compute images but not pre-cache any
|
||||||
// textures yet.
|
// textures yet.
|
||||||
func FromFile(e render.Engine, filename string, embeddable filesystem.Embeddable) (*Wallpaper, error) {
|
func FromFile(filename string, embeddable filesystem.Embeddable) (*Wallpaper, error) {
|
||||||
// Default object to return on errors.
|
// Default object to return on errors.
|
||||||
var defaultWP = &Wallpaper{
|
var defaultWP = &Wallpaper{
|
||||||
Name: strings.Split(filepath.Base(filename), ".")[0],
|
Name: strings.Split(filepath.Base(filename), ".")[0],
|
||||||
|
@ -118,12 +118,12 @@ func FromFile(e render.Engine, filename string, embeddable filesystem.Embeddable
|
||||||
Image: rgba,
|
Image: rgba,
|
||||||
ready: true,
|
ready: true,
|
||||||
}
|
}
|
||||||
wp.cache(e)
|
wp.cache()
|
||||||
return wp, nil
|
return wp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache the bitmap images.
|
// cache the bitmap images.
|
||||||
func (wp *Wallpaper) cache(e render.Engine) {
|
func (wp *Wallpaper) cache() {
|
||||||
// Zero-bound the rect cuz an image.Rect doesn't necessarily contain 0,0
|
// Zero-bound the rect cuz an image.Rect doesn't necessarily contain 0,0
|
||||||
var rect = wp.Image.Bounds()
|
var rect = wp.Image.Bounds()
|
||||||
if rect.Min.X < 0 {
|
if rect.Min.X < 0 {
|
||||||
|
@ -164,6 +164,11 @@ func (wp *Wallpaper) QuarterSize() (int, int) {
|
||||||
return wp.quarterWidth, wp.quarterHeight
|
return wp.quarterWidth, wp.quarterHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuarterRect returns a Rect of the size of the quarter images.
|
||||||
|
func (wp *Wallpaper) QuarterRect() render.Rect {
|
||||||
|
return render.NewRect(wp.QuarterSize())
|
||||||
|
}
|
||||||
|
|
||||||
// Corner returns the top left corner image.
|
// Corner returns the top left corner image.
|
||||||
func (wp *Wallpaper) Corner() *image.RGBA {
|
func (wp *Wallpaper) Corner() *image.RGBA {
|
||||||
return wp.corner
|
return wp.corner
|
||||||
|
|
Loading…
Reference in New Issue
Block a user