Browse Source

Refactor Render Texture-Cache Interface

Since SDL2 is using in-memory bitmaps the same as Canvas engine, the
function names of the render.Engine interface have been cleaned up:

* NewTexture(filename, image) -> StoreTexture(name, image)
  Create a new cached texture with a given name.
* NewBitmap(filename) -> LoadTexture(name)
  Recall a stored texture with a given name.
* level.Chunk.ToBitmap uses simpler names for the textures instead of
  userdir.CacheFilename file-like paths.
master
Noah Petherbridge 2 years ago
parent
commit
981b2b98e0
4 changed files with 100 additions and 96 deletions
  1. +0
    -87
      canvas/engine.go
  2. +91
    -0
      canvas/texture.go
  3. +2
    -2
      interface.go
  4. +7
    -7
      sdl/texture.go

+ 0
- 87
canvas/engine.go View File

@@ -1,16 +1,10 @@
package canvas

import (
"bytes"
"encoding/base64"
"errors"
"image"
"image/png"
"syscall/js"
"time"

"git.kirsle.net/apps/doodle/lib/events"
"git.kirsle.net/apps/doodle/lib/render"
)

// Engine implements a rendering engine targeting an HTML canvas for
@@ -79,87 +73,6 @@ func (e *Engine) Present() error {
return nil
}

// Texture can hold on to cached image textures.
type Texture struct {
data string // data:image/png URI
image js.Value // DOM image element
canvas js.Value // Warmed up canvas element
ctx2d js.Value // 2D drawing context for the canvas.
width int
height int
}

// NewTexture caches a texture from a bitmap.
func (e *Engine) NewTexture(filename string, img image.Image) (render.Texturer, error) {
var (
fh = bytes.NewBuffer([]byte{})
imageSize = img.Bounds().Size()
width = imageSize.X
height = imageSize.Y
)

// Encode to PNG format.
if err := png.Encode(fh, img); err != nil {
return nil, err
}

var dataURI = "data:image/png;base64," + base64.StdEncoding.EncodeToString(fh.Bytes())

tex := &Texture{
data: dataURI,
width: width,
height: height,
}

// Preheat a cached Canvas object.
canvas := js.Global().Get("document").Call("createElement", "canvas")
canvas.Set("width", width)
canvas.Set("height", height)
tex.canvas = canvas

ctx2d := canvas.Call("getContext", "2d")
tex.ctx2d = ctx2d

// Load as a JS Image object.
image := js.Global().Call("eval", "new Image()")
image.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
ctx2d.Call("drawImage", image, 0, 0)
return nil
}))
image.Set("src", tex.data)
tex.image = image

// Cache the texture in memory.
e.textures[filename] = tex

return tex, nil
}

// Size returns the dimensions of the texture.
func (t *Texture) Size() render.Rect {
return render.NewRect(int32(t.width), int32(t.height))
}

// NewBitmap initializes a texture from a bitmap image. The image is stored
// in HTML5 Session Storage.
func (e *Engine) NewBitmap(filename string) (render.Texturer, error) {
if tex, ok := e.textures[filename]; ok {
return tex, nil
}

panic("no bitmap for " + filename)
return nil, errors.New("no bitmap data stored for " + filename)
}

// Copy a texturer bitmap onto the canvas.
func (e *Engine) Copy(t render.Texturer, src, dist render.Rect) {
tex := t.(*Texture)

// e.canvas.ctx2d.Call("drawImage", tex.image, dist.X, dist.Y)
e.canvas.ctx2d.Call("drawImage", tex.canvas, dist.X, dist.Y)

}

// Delay for a moment.
func (e *Engine) Delay(delay uint32) {
time.Sleep(time.Duration(delay) * time.Millisecond)


+ 91
- 0
canvas/texture.go View File

@@ -0,0 +1,91 @@
package canvas

import (
"bytes"
"encoding/base64"
"errors"
"image"
"image/png"
"syscall/js"

"git.kirsle.net/apps/doodle/lib/render"
)

// Texture can hold on to cached image textures.
type Texture struct {
data string // data:image/png URI
image js.Value // DOM image element
canvas js.Value // Warmed up canvas element
ctx2d js.Value // 2D drawing context for the canvas.
width int
height int
}

// StoreTexture caches a texture from a bitmap.
func (e *Engine) StoreTexture(name string, img image.Image) (render.Texturer, error) {
var (
fh = bytes.NewBuffer([]byte{})
imageSize = img.Bounds().Size()
width = imageSize.X
height = imageSize.Y
)

// Encode to PNG format.
if err := png.Encode(fh, img); err != nil {
return nil, err
}

var dataURI = "data:image/png;base64," + base64.StdEncoding.EncodeToString(fh.Bytes())

tex := &Texture{
data: dataURI,
width: width,
height: height,
}

// Preheat a cached Canvas object.
canvas := js.Global().Get("document").Call("createElement", "canvas")
canvas.Set("width", width)
canvas.Set("height", height)
tex.canvas = canvas

ctx2d := canvas.Call("getContext", "2d")
tex.ctx2d = ctx2d

// Load as a JS Image object.
image := js.Global().Call("eval", "new Image()")
image.Call("addEventListener", "load", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
ctx2d.Call("drawImage", image, 0, 0)
return nil
}))
image.Set("src", tex.data)
tex.image = image

// Cache the texture in memory.
e.textures[name] = tex

return tex, nil
}

// Size returns the dimensions of the texture.
func (t *Texture) Size() render.Rect {
return render.NewRect(int32(t.width), int32(t.height))
}

// LoadTexture recalls a cached texture image.
func (e *Engine) LoadTexture(name string) (render.Texturer, error) {
if tex, ok := e.textures[name]; ok {
return tex, nil
}

return nil, errors.New("no bitmap data stored for " + name)
}

// Copy a texturer bitmap onto the canvas.
func (e *Engine) Copy(t render.Texturer, src, dist render.Rect) {
tex := t.(*Texture)

// e.canvas.ctx2d.Call("drawImage", tex.image, dist.X, dist.Y)
e.canvas.ctx2d.Call("drawImage", tex.canvas, dist.X, dist.Y)

}

+ 2
- 2
interface.go View File

@@ -32,8 +32,8 @@ type Engine interface {
ComputeTextRect(Text) (Rect, error)

// Texture caching.
NewBitmap(filename string) (Texturer, error)
NewTexture(filename string, img image.Image) (Texturer, error)
StoreTexture(name string, img image.Image) (Texturer, error)
LoadTexture(name string) (Texturer, error)
Copy(t Texturer, src, dst Rect)

// Delay for a moment using the render engine's delay method,


+ 7
- 7
sdl/texture.go View File

@@ -28,8 +28,8 @@ type Texture struct {
height int32
}

// NewTexture caches an SDL texture from a bitmap.
func (r *Renderer) NewTexture(filename string, img image.Image) (render.Texturer, error) {
// StoreTexture caches an SDL texture from a bitmap.
func (r *Renderer) StoreTexture(name string, img image.Image) (render.Texturer, error) {
var (
fh = bytes.NewBuffer([]byte{})
)
@@ -65,7 +65,7 @@ func (r *Renderer) NewTexture(filename string, img image.Image) (render.Texturer
height: surface.H,
tex: texture,
}
r.textures[filename] = tex
r.textures[name] = tex

return tex, nil
}
@@ -75,10 +75,10 @@ func (t *Texture) Size() render.Rect {
return render.NewRect(t.width, t.height)
}

// NewBitmap initializes a texture from a bitmap image.
func (r *Renderer) NewBitmap(filename string) (render.Texturer, error) {
if tex, ok := r.textures[filename]; ok {
// LoadTexture initializes a texture from a bitmap image.
func (r *Renderer) LoadTexture(name string) (render.Texturer, error) {
if tex, ok := r.textures[name]; ok {
return tex, nil
}
return nil, fmt.Errorf("NewBitmap(%s): not found in texture cache", filename)
return nil, fmt.Errorf("LoadTexture(%s): not found in texture cache", name)
}

Loading…
Cancel
Save