Noah Petherbridge
af67b20d9b
* Initial WebAssembly build target for Doodle in the wasm/ folder. * Add a new render.Engine implementation, lib/render/canvas that uses the HTML 5 Canvas API instead of SDL2 for the WebAssembly target. * Ported the basic DrawLine(), DrawBox() etc. functions from SDL2 to Canvas context2d API. * Fonts are handled with CSS embedded fonts named after the font filename and defined in wasm/index.html * `make wasm` builds the WASM program, and `make wasm-serve` runs a dev Go server that hosts the WASM file for development. The server also watches the dev tree for *.go files and rebuilds the WASM binary automatically on change. * This build "basically" runs the game. UI and fonts all work and mouse movements and clicks are detected. No wallpaper support yet or texture caching (which will crash the game as soon as you click and draw a pixel in your map!)
158 lines
3.6 KiB
Go
158 lines
3.6 KiB
Go
package wallpaper
|
|
|
|
import (
|
|
"image"
|
|
"image/draw"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"git.kirsle.net/apps/doodle/lib/render"
|
|
)
|
|
|
|
// Wallpaper is a repeatable background image to go behind levels.
|
|
type Wallpaper struct {
|
|
Name string
|
|
Format string // image file format
|
|
Image *image.RGBA
|
|
|
|
// Ready status is set to true if the wallpaper loaded itself properly.
|
|
// Notably in WASM, wallpapers don't load currently.
|
|
ready bool
|
|
|
|
// Parsed values.
|
|
quarterWidth int
|
|
quarterHeight int
|
|
|
|
// The four parsed images.
|
|
corner *image.RGBA // Top Left corner
|
|
top *image.RGBA // Top repeating
|
|
left *image.RGBA // Left repeating
|
|
repeat *image.RGBA // Main repeating
|
|
|
|
// Cached textures.
|
|
tex struct {
|
|
corner render.Texturer
|
|
top render.Texturer
|
|
left render.Texturer
|
|
repeat render.Texturer
|
|
}
|
|
}
|
|
|
|
// FromImage creates a Wallpaper from an image.Image.
|
|
// If the renger.Engine is nil it will compute images but not pre-cache any
|
|
// textures yet.
|
|
func FromImage(e render.Engine, img *image.RGBA, name string) (*Wallpaper, error) {
|
|
wp := &Wallpaper{
|
|
Name: name,
|
|
Image: img,
|
|
}
|
|
wp.cache(e)
|
|
return wp, nil
|
|
}
|
|
|
|
// FromFile creates a Wallpaper from a file on disk.
|
|
// If the renger.Engine is nil it will compute images but not pre-cache any
|
|
// textures yet.
|
|
func FromFile(e render.Engine, filename string) (*Wallpaper, error) {
|
|
// WASM: no support yet for wallpapers.
|
|
if runtime.GOOS == "js" {
|
|
return &Wallpaper{
|
|
Name: strings.Split(filepath.Base(filename), ".")[0],
|
|
ready: false,
|
|
}, nil
|
|
}
|
|
|
|
fh, err := os.Open(filename)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
img, format, err := image.Decode(fh)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Ugly hack: make it an image.RGBA because the thing we get tends to be
|
|
// an image.Paletted, UGH!
|
|
var b = img.Bounds()
|
|
rgba := image.NewRGBA(b)
|
|
for x := b.Min.X; x < b.Max.X; x++ {
|
|
for y := b.Min.Y; y < b.Max.Y; y++ {
|
|
rgba.Set(x, y, img.At(x, y))
|
|
}
|
|
}
|
|
|
|
wp := &Wallpaper{
|
|
Name: strings.Split(filepath.Base(filename), ".")[0],
|
|
Format: format,
|
|
Image: rgba,
|
|
ready: true,
|
|
}
|
|
wp.cache(e)
|
|
return wp, nil
|
|
}
|
|
|
|
// cache the bitmap images.
|
|
func (wp *Wallpaper) cache(e render.Engine) {
|
|
// Zero-bound the rect cuz an image.Rect doesn't necessarily contain 0,0
|
|
var rect = wp.Image.Bounds()
|
|
if rect.Min.X < 0 {
|
|
rect.Max.X += rect.Min.X
|
|
rect.Min.X = 0
|
|
}
|
|
if rect.Min.Y < 0 {
|
|
rect.Max.Y += rect.Min.Y
|
|
rect.Min.Y = 0
|
|
}
|
|
|
|
// Our quarter rect size.
|
|
wp.quarterWidth = int(float64((rect.Max.X - rect.Min.X) / 2))
|
|
wp.quarterHeight = int(float64((rect.Max.Y - rect.Min.Y) / 2))
|
|
quarter := image.Rect(0, 0, wp.quarterWidth, wp.quarterHeight)
|
|
|
|
// Slice the image into the four corners.
|
|
slice := func(dx, dy int) *image.RGBA {
|
|
slice := image.NewRGBA(quarter)
|
|
draw.Draw(
|
|
slice,
|
|
image.Rect(0, 0, wp.quarterWidth, wp.quarterHeight),
|
|
wp.Image,
|
|
image.Point{dx, dy},
|
|
draw.Over,
|
|
)
|
|
return slice
|
|
}
|
|
wp.corner = slice(0, 0)
|
|
wp.top = slice(wp.quarterWidth, 0)
|
|
wp.left = slice(0, wp.quarterHeight)
|
|
wp.repeat = slice(wp.quarterWidth, wp.quarterHeight)
|
|
|
|
}
|
|
|
|
// QuarterSize returns the width and height of the quarter images.
|
|
func (wp *Wallpaper) QuarterSize() (int, int) {
|
|
return wp.quarterWidth, wp.quarterHeight
|
|
}
|
|
|
|
// Corner returns the top left corner image.
|
|
func (wp *Wallpaper) Corner() *image.RGBA {
|
|
return wp.corner
|
|
}
|
|
|
|
// Top returns the top repeating image.
|
|
func (wp *Wallpaper) Top() *image.RGBA {
|
|
return wp.top
|
|
}
|
|
|
|
// Left returns the left repeating image.
|
|
func (wp *Wallpaper) Left() *image.RGBA {
|
|
return wp.left
|
|
}
|
|
|
|
// Repeat returns the main repeating image.
|
|
func (wp *Wallpaper) Repeat() *image.RGBA {
|
|
return wp.repeat
|
|
}
|