SDL: Support textures regenerating when flushed
* We store a Go image.Image copy of all textures in the SDL2 renderer. * When the underlying SDL2 textures are freed, regenerate them when needed from the underlying Go Image.
This commit is contained in:
parent
129a24300d
commit
a8da853de0
|
@ -14,15 +14,21 @@ import (
|
||||||
func (r *Renderer) Copy(t render.Texturer, src, dst render.Rect) {
|
func (r *Renderer) Copy(t render.Texturer, src, dst render.Rect) {
|
||||||
if tex, ok := t.(*Texture); ok {
|
if tex, ok := t.(*Texture); ok {
|
||||||
var (
|
var (
|
||||||
a = RectToSDL(src)
|
a = RectToSDL(src)
|
||||||
b = RectToSDL(dst)
|
b = RectToSDL(dst)
|
||||||
|
texture, err = tex.getTexture()
|
||||||
)
|
)
|
||||||
r.renderer.Copy(tex.tex, &a, &b)
|
if err == nil {
|
||||||
|
r.renderer.Copy(texture, &a, &b)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Renderer.Copy: texture %s could not be created: %s\n", tex.name, err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texture can hold on to SDL textures for caching and optimization.
|
// Texture can hold on to SDL textures for caching and optimization.
|
||||||
type Texture struct {
|
type Texture struct {
|
||||||
|
name string
|
||||||
render *Renderer // backref to free them up thoroughly
|
render *Renderer // backref to free them up thoroughly
|
||||||
tex *sdl.Texture
|
tex *sdl.Texture
|
||||||
image image.Image
|
image image.Image
|
||||||
|
@ -30,13 +36,16 @@ type Texture struct {
|
||||||
height int32
|
height int32
|
||||||
}
|
}
|
||||||
|
|
||||||
// StoreTexture caches an SDL texture from a bitmap.
|
// Render the SDL2 Texture from the base Image if the texture is not ready.
|
||||||
func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer, error) {
|
func (t *Texture) getTexture() (*sdl.Texture, error) {
|
||||||
var (
|
if t.tex != nil {
|
||||||
fh = bytes.NewBuffer([]byte{})
|
return t.tex, nil
|
||||||
)
|
}
|
||||||
|
|
||||||
err := bmp.Encode(fh, img)
|
var (
|
||||||
|
fh = bytes.NewBuffer([]byte{})
|
||||||
|
err = bmp.Encode(fh, t.image)
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewTexture: bmp.Encode: %s", err)
|
return nil, fmt.Errorf("NewTexture: bmp.Encode: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -57,19 +66,30 @@ func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer,
|
||||||
key := sdl.MapRGB(surface.Format, 255, 255, 255)
|
key := sdl.MapRGB(surface.Format, 255, 255, 255)
|
||||||
surface.SetColorKey(true, key)
|
surface.SetColorKey(true, key)
|
||||||
|
|
||||||
texture, err := r.renderer.CreateTextureFromSurface(surface)
|
texture, err := t.render.renderer.CreateTextureFromSurface(surface)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("NewBitmap: create texture: %s", err)
|
return nil, fmt.Errorf("NewBitmap: create texture: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.tex = texture
|
||||||
|
t.width = surface.W
|
||||||
|
t.height = surface.H
|
||||||
|
return t.tex, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// StoreTexture caches an SDL texture from a bitmap.
|
||||||
|
func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer, error) {
|
||||||
tex := &Texture{
|
tex := &Texture{
|
||||||
|
name: name,
|
||||||
render: r,
|
render: r,
|
||||||
width: surface.W,
|
|
||||||
height: surface.H,
|
|
||||||
tex: texture,
|
|
||||||
image: img,
|
image: img,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_, err := tex.getTexture()
|
||||||
|
if err != nil {
|
||||||
|
return tex, err
|
||||||
|
}
|
||||||
|
|
||||||
r.textureMu.Lock()
|
r.textureMu.Lock()
|
||||||
r.textures[name] = tex
|
r.textures[name] = tex
|
||||||
r.textureMu.Unlock()
|
r.textureMu.Unlock()
|
||||||
|
@ -120,14 +140,6 @@ func (t *Texture) Free() error {
|
||||||
t.tex = nil
|
t.tex = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free up the cached texture too to garbage collect the image.Image cache etc.
|
|
||||||
for name, tex := range t.render.textures {
|
|
||||||
if tex == t {
|
|
||||||
delete(t.render.textures, name)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +151,10 @@ func (r *Renderer) LoadTexture(name string) (render.Texturer, error) {
|
||||||
if tex, ok := r.textures[name]; ok {
|
if tex, ok := r.textures[name]; ok {
|
||||||
// If the SDL2 texture had been freed, recreate it.
|
// If the SDL2 texture had been freed, recreate it.
|
||||||
if tex.tex == nil {
|
if tex.tex == nil {
|
||||||
return r.StoreTexture(name, tex.image)
|
_, err := tex.getTexture()
|
||||||
|
if err != nil {
|
||||||
|
return tex, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return tex, nil
|
return tex, nil
|
||||||
}
|
}
|
||||||
|
@ -153,8 +168,11 @@ func (r *Renderer) FreeTextures() int {
|
||||||
|
|
||||||
var num = len(r.textures)
|
var num = len(r.textures)
|
||||||
for name, tex := range r.textures {
|
for name, tex := range r.textures {
|
||||||
|
if tex.tex != nil {
|
||||||
|
tex.tex.Destroy()
|
||||||
|
tex.tex = nil
|
||||||
|
}
|
||||||
delete(r.textures, name)
|
delete(r.textures, name)
|
||||||
tex.tex.Destroy()
|
|
||||||
}
|
}
|
||||||
return num
|
return num
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user