doodle/pkg/wallpaper/wallpaper.go
Noah Petherbridge af67b20d9b Initial WebAssembly Build Target
* 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!)
2019-06-26 18:40:40 -07:00

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
}