2018-06-21 01:43:14 +00:00
|
|
|
package doodle
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"image"
|
|
|
|
"image/png"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
2018-07-22 00:12:22 +00:00
|
|
|
"git.kirsle.net/apps/doodle/events"
|
2018-06-21 01:43:14 +00:00
|
|
|
"git.kirsle.net/apps/doodle/level"
|
2018-07-22 00:12:22 +00:00
|
|
|
"git.kirsle.net/apps/doodle/render"
|
2018-06-21 01:43:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// EditorScene manages the "Edit Level" game mode.
|
|
|
|
type EditorScene struct {
|
2018-07-24 03:10:53 +00:00
|
|
|
// Configuration for the scene initializer.
|
|
|
|
OpenFile bool
|
|
|
|
Filename string
|
2018-08-11 00:19:47 +00:00
|
|
|
Canvas level.Grid
|
2018-07-24 03:10:53 +00:00
|
|
|
|
2018-08-05 19:54:57 +00:00
|
|
|
UI *EditorUI
|
|
|
|
|
2018-08-11 00:19:47 +00:00
|
|
|
Palette *level.Palette // Full palette of swatches for this level
|
|
|
|
Swatch *level.Swatch // actively selected painting swatch
|
|
|
|
|
2018-06-21 01:43:14 +00:00
|
|
|
// History of all the pixels placed by the user.
|
2018-08-11 00:19:47 +00:00
|
|
|
pixelHistory []*level.Pixel
|
2018-07-25 00:44:32 +00:00
|
|
|
lastPixel *level.Pixel // last pixel placed while mouse down and dragging
|
2018-08-11 00:19:47 +00:00
|
|
|
canvas level.Grid
|
2018-07-22 03:43:01 +00:00
|
|
|
filename string // Last saved filename.
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
// Canvas size
|
|
|
|
width int32
|
|
|
|
height int32
|
|
|
|
}
|
|
|
|
|
2018-06-21 02:00:46 +00:00
|
|
|
// Name of the scene.
|
|
|
|
func (s *EditorScene) Name() string {
|
|
|
|
return "Edit"
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:43:14 +00:00
|
|
|
// Setup the editor scene.
|
2018-07-21 22:11:00 +00:00
|
|
|
func (s *EditorScene) Setup(d *Doodle) error {
|
2018-07-24 03:10:53 +00:00
|
|
|
// Were we given configuration data?
|
|
|
|
if s.Filename != "" {
|
|
|
|
log.Debug("EditorScene: Set filename to %s", s.Filename)
|
|
|
|
s.filename = s.Filename
|
|
|
|
s.Filename = ""
|
|
|
|
if s.OpenFile {
|
|
|
|
log.Debug("EditorScene: Loading map from filename at %s", s.filename)
|
|
|
|
if err := s.LoadLevel(s.filename); err != nil {
|
2018-08-11 00:19:47 +00:00
|
|
|
d.Flash("LoadLevel error: %s", err)
|
2018-07-24 03:10:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if s.Canvas != nil {
|
|
|
|
log.Debug("EditorScene: Received Canvas from caller")
|
|
|
|
s.canvas = s.Canvas
|
|
|
|
s.Canvas = nil
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:19:47 +00:00
|
|
|
s.Palette = level.DefaultPalette()
|
|
|
|
if len(s.Palette.Swatches) > 0 {
|
|
|
|
s.Swatch = s.Palette.Swatches[0]
|
|
|
|
s.Palette.ActiveSwatch = s.Swatch.Name
|
|
|
|
}
|
2018-08-05 19:54:57 +00:00
|
|
|
|
2018-08-11 00:19:47 +00:00
|
|
|
// Initialize the user interface. It references the palette and such so it
|
|
|
|
// must be initialized after those things.
|
|
|
|
s.UI = NewEditorUI(d, s)
|
2018-07-24 03:10:53 +00:00
|
|
|
d.Flash("Editor Mode. Press 'P' to play this map.")
|
|
|
|
|
2018-07-21 22:11:00 +00:00
|
|
|
if s.pixelHistory == nil {
|
2018-08-11 00:19:47 +00:00
|
|
|
s.pixelHistory = []*level.Pixel{}
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
2018-07-21 22:11:00 +00:00
|
|
|
if s.canvas == nil {
|
2018-07-24 03:10:53 +00:00
|
|
|
log.Debug("EditorScene: Setting default canvas to an empty grid")
|
2018-08-11 00:19:47 +00:00
|
|
|
s.canvas = level.Grid{}
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
2018-07-21 22:11:00 +00:00
|
|
|
s.width = d.width // TODO: canvas width = copy the window size
|
|
|
|
s.height = d.height
|
2018-06-21 01:43:14 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop the editor scene.
|
2018-07-22 00:12:22 +00:00
|
|
|
func (s *EditorScene) Loop(d *Doodle, ev *events.State) error {
|
2018-08-05 19:54:57 +00:00
|
|
|
s.UI.Loop(ev)
|
|
|
|
|
2018-06-21 01:43:14 +00:00
|
|
|
// Taking a screenshot?
|
|
|
|
if ev.ScreenshotKey.Pressed() {
|
|
|
|
log.Info("Taking a screenshot")
|
2018-07-21 22:11:00 +00:00
|
|
|
s.Screenshot()
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-24 03:10:53 +00:00
|
|
|
// Switching to Play Mode?
|
|
|
|
if ev.KeyName.Read() == "p" {
|
|
|
|
log.Info("Play Mode, Go!")
|
|
|
|
d.Goto(&PlayScene{
|
|
|
|
Canvas: s.canvas,
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-06-21 01:43:14 +00:00
|
|
|
// Clear the canvas and fill it with white.
|
2018-07-22 00:12:22 +00:00
|
|
|
d.Engine.Clear(render.White)
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
// Clicking? Log all the pixels while doing so.
|
|
|
|
if ev.Button1.Now {
|
2018-07-25 00:44:32 +00:00
|
|
|
// log.Warn("Button1: %+v", ev.Button1)
|
|
|
|
lastPixel := s.lastPixel
|
2018-08-11 00:19:47 +00:00
|
|
|
pixel := &level.Pixel{
|
|
|
|
X: ev.CursorX.Now,
|
|
|
|
Y: ev.CursorY.Now,
|
|
|
|
Palette: s.Palette,
|
|
|
|
Swatch: s.Swatch,
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Append unique new pixels.
|
2018-07-21 22:11:00 +00:00
|
|
|
if len(s.pixelHistory) == 0 || s.pixelHistory[len(s.pixelHistory)-1] != pixel {
|
2018-07-25 00:44:32 +00:00
|
|
|
if lastPixel != nil {
|
|
|
|
// Draw the pixels in between.
|
2018-08-11 00:19:47 +00:00
|
|
|
if lastPixel != pixel {
|
2018-07-25 00:44:32 +00:00
|
|
|
for point := range render.IterLine(lastPixel.X, lastPixel.Y, pixel.X, pixel.Y) {
|
2018-08-11 00:19:47 +00:00
|
|
|
dot := &level.Pixel{
|
2018-07-25 00:44:32 +00:00
|
|
|
X: point.X,
|
|
|
|
Y: point.Y,
|
|
|
|
Palette: lastPixel.Palette,
|
2018-08-11 00:19:47 +00:00
|
|
|
Swatch: lastPixel.Swatch,
|
2018-07-25 00:44:32 +00:00
|
|
|
}
|
|
|
|
s.canvas[dot] = nil
|
|
|
|
}
|
|
|
|
}
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-11 00:19:47 +00:00
|
|
|
s.lastPixel = pixel
|
2018-07-21 22:11:00 +00:00
|
|
|
s.pixelHistory = append(s.pixelHistory, pixel)
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
// Save in the pixel canvas map.
|
2018-07-21 22:11:00 +00:00
|
|
|
s.canvas[pixel] = nil
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
2018-07-25 00:44:32 +00:00
|
|
|
} else {
|
|
|
|
s.lastPixel = nil
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
2018-07-22 03:43:01 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw the current frame.
|
|
|
|
func (s *EditorScene) Draw(d *Doodle) error {
|
2018-07-24 03:10:53 +00:00
|
|
|
s.canvas.Draw(d.Engine)
|
2018-08-05 19:54:57 +00:00
|
|
|
s.UI.Present(d.Engine)
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// LoadLevel loads a level from disk.
|
2018-07-21 22:11:00 +00:00
|
|
|
func (s *EditorScene) LoadLevel(filename string) error {
|
2018-07-22 03:43:01 +00:00
|
|
|
s.filename = filename
|
2018-08-11 00:19:47 +00:00
|
|
|
s.pixelHistory = []*level.Pixel{}
|
|
|
|
s.canvas = level.Grid{}
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
m, err := level.LoadJSON(filename)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-08-11 00:19:47 +00:00
|
|
|
s.Palette = m.Palette
|
|
|
|
if len(s.Palette.Swatches) > 0 {
|
|
|
|
s.Swatch = m.Palette.Swatches[0]
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, pixel := range m.Pixels {
|
2018-07-21 22:11:00 +00:00
|
|
|
s.pixelHistory = append(s.pixelHistory, pixel)
|
|
|
|
s.canvas[pixel] = nil
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SaveLevel saves the level to disk.
|
2018-07-22 03:43:01 +00:00
|
|
|
func (s *EditorScene) SaveLevel(filename string) {
|
|
|
|
s.filename = filename
|
2018-08-11 00:19:47 +00:00
|
|
|
|
|
|
|
m := level.New()
|
|
|
|
m.Title = "Alpha"
|
|
|
|
m.Author = os.Getenv("USER")
|
|
|
|
m.Width = s.width
|
|
|
|
m.Height = s.height
|
|
|
|
m.Palette = s.Palette
|
2018-06-21 01:43:14 +00:00
|
|
|
|
2018-07-21 22:11:00 +00:00
|
|
|
for pixel := range s.canvas {
|
2018-08-11 00:19:47 +00:00
|
|
|
m.Pixels = append(m.Pixels, &level.Pixel{
|
|
|
|
X: pixel.X,
|
|
|
|
Y: pixel.Y,
|
|
|
|
PaletteIndex: int32(pixel.Swatch.Index()),
|
2018-07-25 00:44:32 +00:00
|
|
|
})
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
json, err := m.ToJSON()
|
|
|
|
if err != nil {
|
|
|
|
log.Error("SaveLevel error: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
err = ioutil.WriteFile(filename, json, 0644)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Create map file error: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Screenshot saves the level canvas to disk as a PNG image.
|
2018-07-21 22:11:00 +00:00
|
|
|
func (s *EditorScene) Screenshot() {
|
|
|
|
screenshot := image.NewRGBA(image.Rect(0, 0, int(s.width), int(s.height)))
|
2018-06-21 01:43:14 +00:00
|
|
|
|
|
|
|
// White-out the image.
|
2018-07-21 22:11:00 +00:00
|
|
|
for x := 0; x < int(s.width); x++ {
|
|
|
|
for y := 0; y < int(s.height); y++ {
|
2018-06-21 01:43:14 +00:00
|
|
|
screenshot.Set(x, y, image.White)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fill in the dots we drew.
|
2018-07-21 22:11:00 +00:00
|
|
|
for pixel := range s.canvas {
|
2018-07-25 00:44:32 +00:00
|
|
|
screenshot.Set(int(pixel.X), int(pixel.Y), image.Black)
|
2018-06-21 01:43:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create the screenshot directory.
|
|
|
|
if _, err := os.Stat("./screenshots"); os.IsNotExist(err) {
|
|
|
|
log.Info("Creating directory: ./screenshots")
|
|
|
|
err = os.Mkdir("./screenshots", 0755)
|
|
|
|
if err != nil {
|
|
|
|
log.Error("Can't create ./screenshots: %s", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
filename := fmt.Sprintf("./screenshots/screenshot-%s.png",
|
|
|
|
time.Now().Format("2006-01-02T15-04-05"),
|
|
|
|
)
|
|
|
|
fh, err := os.Create(filename)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer fh.Close()
|
|
|
|
|
|
|
|
if err := png.Encode(fh, screenshot); err != nil {
|
|
|
|
log.Error(err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2018-07-24 03:10:53 +00:00
|
|
|
|
|
|
|
// Destroy the scene.
|
|
|
|
func (s *EditorScene) Destroy() error {
|
|
|
|
return nil
|
|
|
|
}
|