Finalize Non-square Doodads
* Fix display bug with rectangular doodads scrolling off screen. * The default Author of new files will be your registration name, if available before using your $USER name.
This commit is contained in:
parent
ddcad27485
commit
31097881ff
|
@ -15,6 +15,7 @@ import (
|
|||
"git.kirsle.net/SketchyMaze/doodle/pkg/doodads"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/level"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
|
||||
"git.kirsle.net/go/render"
|
||||
"github.com/urfave/cli/v2"
|
||||
"golang.org/x/image/bmp"
|
||||
|
@ -104,8 +105,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
|
|||
// Read the source images. Ensure they all have the same boundaries.
|
||||
var (
|
||||
imageBounds image.Point
|
||||
chunkSize uint8 // the square shape for the Doodad chunk size
|
||||
width int // dimensions of the incoming image
|
||||
width int // dimensions of the incoming image
|
||||
height int
|
||||
images []image.Image
|
||||
)
|
||||
|
@ -131,11 +131,8 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
|
|||
// Validate all images are the same size.
|
||||
if i == 0 {
|
||||
imageBounds = imageSize
|
||||
if imageSize.X > imageSize.Y {
|
||||
width = imageSize.X
|
||||
} else {
|
||||
height = imageSize.Y
|
||||
}
|
||||
width = imageSize.X
|
||||
height = imageSize.Y
|
||||
} else if imageSize != imageBounds {
|
||||
return cli.Exit("your source images are not all the same dimensions", 1)
|
||||
}
|
||||
|
@ -152,17 +149,18 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
|
|||
// Generate the output drawing file.
|
||||
switch strings.ToLower(filepath.Ext(outputFile)) {
|
||||
case extDoodad:
|
||||
log.Info("Output is a Doodad file (chunk size %d): %s", chunkSize, outputFile)
|
||||
doodad := doodads.New(width, height)
|
||||
doodad.GameVersion = branding.Version
|
||||
doodad.Title = c.String("title")
|
||||
if doodad.Title == "" {
|
||||
doodad.Title = "Converted Doodad"
|
||||
}
|
||||
doodad.Author = os.Getenv("USER")
|
||||
doodad.Author = native.DefaultAuthor()
|
||||
|
||||
// Write the first layer and gather its palette.
|
||||
log.Info("Converting first layer to drawing and getting the palette")
|
||||
var chunkSize = doodad.ChunkSize8()
|
||||
log.Info("Output is a Doodad file (%dx%d): %s", width, height, outputFile)
|
||||
palette, layer0 := imageToChunker(images[0], chroma, nil, chunkSize)
|
||||
doodad.Palette = palette
|
||||
doodad.Layers[0].Chunker = layer0
|
||||
|
@ -197,7 +195,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou
|
|||
if lvl.Title == "" {
|
||||
lvl.Title = "Converted Level"
|
||||
}
|
||||
lvl.Author = os.Getenv("USER")
|
||||
lvl.Author = native.DefaultAuthor()
|
||||
palette, chunker := imageToChunker(images[0], chroma, nil, lvl.Chunker.Size)
|
||||
lvl.Palette = palette
|
||||
lvl.Chunker = chunker
|
||||
|
|
|
@ -42,23 +42,29 @@ You can give it one or two values for dimensions:
|
|||
func New(dimensions ...int) *Doodad {
|
||||
var (
|
||||
// Defaults
|
||||
size = balance.DoodadSize
|
||||
chunkSize = balance.ChunkSize
|
||||
size int
|
||||
chunkSize uint8
|
||||
width int
|
||||
height int
|
||||
)
|
||||
|
||||
switch len(dimensions) {
|
||||
case 1:
|
||||
size = dimensions[0]
|
||||
width, height = dimensions[0], dimensions[0]
|
||||
case 2:
|
||||
width, height = dimensions[0], dimensions[1]
|
||||
}
|
||||
|
||||
// If no width/height, make it a classic square doodad.
|
||||
if width+height == 0 {
|
||||
width = size
|
||||
height = size
|
||||
// Set the desired chunkSize to be the largest dimension.
|
||||
if width > height {
|
||||
size = width
|
||||
} else {
|
||||
size = height
|
||||
}
|
||||
|
||||
// If no size at all, fall back on the default.
|
||||
if size == 0 {
|
||||
size = int(balance.ChunkSize)
|
||||
}
|
||||
|
||||
// Pick an optimal chunk size - if our doodad size
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package doodads
|
||||
|
||||
import (
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/go/render"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
@ -25,7 +24,6 @@ func NewDrawing(id string, doodad *Doodad) *Drawing {
|
|||
if id == "" {
|
||||
id = uuid.Must(uuid.NewUUID()).String()
|
||||
}
|
||||
log.Warn("NewDraging(%s): doodad.Rect=%s doodad.Size=%s", doodad.Title, doodad.Rect(), doodad.Size)
|
||||
return &Drawing{
|
||||
id: id,
|
||||
Doodad: doodad,
|
||||
|
|
|
@ -6,8 +6,8 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/go/render"
|
||||
)
|
||||
|
||||
// ToZipfile serializes the doodad into zipfile format.
|
||||
|
@ -63,7 +63,7 @@ func (d *Doodad) ToZipfile() ([]byte, error) {
|
|||
// FromZipfile reads a doodad from zipfile format.
|
||||
func FromZipfile(data []byte) (*Doodad, error) {
|
||||
var (
|
||||
doodad = New(balance.DoodadSize)
|
||||
doodad = New(0)
|
||||
err = doodad.populateFromZipfile(data)
|
||||
)
|
||||
return doodad, err
|
||||
|
@ -109,6 +109,13 @@ func (d *Doodad) populateFromZipfile(data []byte) error {
|
|||
// Re-inflate data after saving a new zipfile.
|
||||
d.Inflate()
|
||||
|
||||
// If we are a legacy doodad and don't have a Size (width x height),
|
||||
// set it from the chunk size.
|
||||
if d.Size.IsZero() {
|
||||
var size = d.ChunkSize()
|
||||
d.Size = render.NewRect(size, size)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package doodle
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -19,6 +18,7 @@ import (
|
|||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/modal"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/usercfg"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/userdir"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
|
||||
|
@ -512,7 +512,7 @@ func (s *EditorScene) SaveLevel(filename string) error {
|
|||
m.Title = "Alpha"
|
||||
}
|
||||
if m.Author == "" {
|
||||
m.Author = os.Getenv("USER")
|
||||
m.Author = native.DefaultAuthor()
|
||||
}
|
||||
|
||||
m.Palette = s.UI.Canvas.Palette
|
||||
|
@ -595,7 +595,7 @@ func (s *EditorScene) SaveDoodad(filename string) error {
|
|||
d.Title = "Untitled Doodad"
|
||||
}
|
||||
if d.Author == "" {
|
||||
d.Author = os.Getenv("USER")
|
||||
d.Author = native.DefaultAuthor()
|
||||
}
|
||||
|
||||
// TODO: is this copying necessary?
|
||||
|
|
|
@ -4,12 +4,12 @@ import (
|
|||
"archive/zip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/balance"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/drawtool"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/enum"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/log"
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/native"
|
||||
"git.kirsle.net/go/render"
|
||||
)
|
||||
|
||||
|
@ -83,7 +83,7 @@ func New() *Level {
|
|||
Base: Base{
|
||||
Version: 1,
|
||||
Title: "Untitled",
|
||||
Author: os.Getenv("USER"),
|
||||
Author: native.DefaultAuthor(),
|
||||
Files: NewFileSystem(),
|
||||
},
|
||||
Chunker: NewChunker(balance.ChunkSize),
|
||||
|
|
29
pkg/native/username.go
Normal file
29
pkg/native/username.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package native
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.kirsle.net/SketchyMaze/doodle/pkg/license"
|
||||
)
|
||||
|
||||
var USER string = os.Getenv("USER")
|
||||
|
||||
/*
|
||||
DefaultAuthor will return the local user's name to be the default Author
|
||||
for levels and doodads they create.
|
||||
|
||||
If they have registered the game, use the name from their license JWT token.
|
||||
|
||||
Otherwise fall back to their native operating system user.
|
||||
*/
|
||||
func DefaultAuthor() string {
|
||||
// Are we registered?
|
||||
if license.IsRegistered() {
|
||||
if reg, err := license.GetRegistration(); err == nil {
|
||||
return reg.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Return OS username
|
||||
return os.Getenv("USER")
|
||||
}
|
|
@ -348,6 +348,11 @@ func (s *PlayScene) PlaceResizeCanvas() {
|
|||
})
|
||||
}
|
||||
|
||||
// Canvas returns the main level canvas - useful to call from the debug console as `d.Scene.Canvas()`
|
||||
func (s *PlayScene) Canvas() *uix.Canvas {
|
||||
return s.drawing
|
||||
}
|
||||
|
||||
// SetPlayerCharacter changes the doodad used for the player, by destroying the
|
||||
// current player character and making it from scratch.
|
||||
func (s *PlayScene) SetPlayerCharacter(filename string) {
|
||||
|
|
|
@ -164,7 +164,7 @@ func (a *Actor) SetWet(v bool) {
|
|||
|
||||
// Size returns the size of the actor, from the underlying doodads.Drawing.
|
||||
func (a *Actor) Size() render.Rect {
|
||||
return a.Drawing.Size()
|
||||
return a.Drawing.Doodad.Size
|
||||
}
|
||||
|
||||
// Velocity returns the actor's current velocity vector.
|
||||
|
|
|
@ -36,6 +36,11 @@ type Canvas struct {
|
|||
Scrollable bool // Cursor keys will scroll the viewport of this canvas.
|
||||
Zoom int // Zoom level on the canvas.
|
||||
|
||||
// Set this if your Canvas is a small fixed size (e.g. in doodad dropper),
|
||||
// so that doodads will crop their texture (if chunk size larger than your
|
||||
// Canvas) as to not overflow the canvas bounds. Not needed for Level canvases.
|
||||
CroppedSize bool
|
||||
|
||||
// Toogle for doodad canvases in the Level Editor to show their buttons.
|
||||
ShowDoodadButtons bool
|
||||
doodadButtonFrame ui.Widget // lazy init
|
||||
|
|
|
@ -220,7 +220,7 @@ func (w *Canvas) drawActors(e render.Engine, p render.Point) {
|
|||
// Hitting the left edge. Cap the X coord and shrink the width.
|
||||
delta := p.X - drawAt.X // positive number
|
||||
drawAt.X = p.X
|
||||
// scrollTo.X -= delta // TODO
|
||||
scrollTo.X -= delta
|
||||
resizeTo.W -= delta
|
||||
}
|
||||
|
||||
|
@ -232,6 +232,7 @@ func (w *Canvas) drawActors(e render.Engine, p render.Point) {
|
|||
// Hitting the top edge. Cap the Y coord and shrink the height.
|
||||
delta := p.Y - drawAt.Y
|
||||
drawAt.Y = p.Y
|
||||
scrollTo.Y -= delta
|
||||
resizeTo.H -= delta
|
||||
}
|
||||
|
||||
|
|
26
pkg/uix/canvas_debug.go
Normal file
26
pkg/uix/canvas_debug.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package uix
|
||||
|
||||
import "strings"
|
||||
|
||||
// Some debugging functions for the Canvas reachable via dev console in-game.
|
||||
|
||||
// GetCanvasesByActorName searches a (level) canvas's installed actors and returns any of
|
||||
// them having this Title or Filename, with filename being more precise.
|
||||
func (c *Canvas) GetCanvasesByActorName(filename string) []*Canvas {
|
||||
var (
|
||||
byFilename = []*Canvas{}
|
||||
byTitle = []*Canvas{}
|
||||
lower = strings.ToLower(filename)
|
||||
)
|
||||
|
||||
for _, a := range c.actors {
|
||||
var doodad = a.Doodad()
|
||||
if doodad.Filename == filename {
|
||||
byFilename = append(byFilename, a.Canvas)
|
||||
} else if strings.ToLower(doodad.Title) == lower {
|
||||
byTitle = append(byTitle, a.Canvas)
|
||||
}
|
||||
}
|
||||
|
||||
return append(byFilename, byTitle...)
|
||||
}
|
|
@ -114,11 +114,15 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
|
|||
// into which it will render, cap the source width and height.
|
||||
// This is especially useful for Doodad buttons because the drawing
|
||||
// is bigger than the button.
|
||||
if src.W > S.W {
|
||||
src.W = S.W
|
||||
}
|
||||
if src.H > S.H {
|
||||
src.H = S.H
|
||||
if w.CroppedSize {
|
||||
// NOTE: this is a concern mainly for the Doodad Dropper so that
|
||||
// the doodads won't overflow the button size they appear in.
|
||||
if src.W > S.W {
|
||||
src.W = S.W
|
||||
}
|
||||
if src.H > S.H {
|
||||
src.H = S.H
|
||||
}
|
||||
}
|
||||
|
||||
var size = int(chunk.Size)
|
||||
|
@ -135,62 +139,68 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
|
|||
|
||||
// TODO: all this shit is in TrimBox(), make it DRY
|
||||
|
||||
// If the destination width will cause it to overflow the widget
|
||||
// box, trim off the right edge of the destination rect.
|
||||
//
|
||||
// Keep in mind we're dealing with chunks here, and a chunk is
|
||||
// a small part of the image. Example:
|
||||
// - Canvas is 800x600 (S.W=800 S.H=600)
|
||||
// - Chunk wants to render at 790,0 width 100,100 or whatever
|
||||
// dst={790, 0, 100, 100}
|
||||
// - Chunk box would exceed 800px width (X=790 + W=100 == 890)
|
||||
// - Find the delta how much it exceeds as negative (800 - 890 == -90)
|
||||
// - Lower the Source and Dest rects by that delta size so they
|
||||
// stay proportional and don't scale or anything dumb.
|
||||
if dst.X+src.W > p.X+S.W+w.BoxThickness(1) {
|
||||
// NOTE: delta is a negative number,
|
||||
// so it will subtract from the width.
|
||||
delta := (p.X + S.W - w.BoxThickness(1)) - (dst.W + dst.X)
|
||||
src.W += delta
|
||||
dst.W += delta
|
||||
}
|
||||
if dst.Y+src.H > p.Y+S.H+w.BoxThickness(1) {
|
||||
// NOTE: delta is a negative number
|
||||
delta := (p.Y + S.H - w.BoxThickness(1)) - (dst.H + dst.Y)
|
||||
src.H += delta
|
||||
dst.H += delta
|
||||
}
|
||||
// wtf? don't need all this code anymore??
|
||||
_ = ParentPosition
|
||||
/*
|
||||
|
||||
// The same for the top left edge, so the drawings don't overlap
|
||||
// menu bars or left side toolbars.
|
||||
// - Canvas was placed 80px from the left of the screen.
|
||||
// Canvas.MoveTo(80, 0)
|
||||
// - A texture wants to draw at 60, 0 which would cause it to
|
||||
// overlap 20 pixels into the left toolbar. It needs to be cropped.
|
||||
// - The delta is: p.X=80 - dst.X=60 == 20
|
||||
// - Set destination X to p.X to constrain it there: 20
|
||||
// - Subtract the delta from destination W so we don't scale it.
|
||||
// - Add 20 to X of the source: the left edge of source is not visible
|
||||
//
|
||||
// Note: the +w.BoxThickness works around a bug if the Actor Canvas has
|
||||
// a border on it (e.g. in the Actor/Link Tool mouse-over or debug setting)
|
||||
if dst.X == ParentPosition.X+w.BoxThickness(1) {
|
||||
// NOTE: delta is a positive number,
|
||||
// so it will add to the destination coordinates.
|
||||
delta := texSizeOrig.W - src.W
|
||||
dst.X = p.X + w.BoxThickness(1)
|
||||
src.X += delta
|
||||
}
|
||||
if dst.Y == ParentPosition.Y+w.BoxThickness(1) {
|
||||
delta := texSizeOrig.H - src.H
|
||||
dst.Y = p.Y + w.BoxThickness(1)
|
||||
src.Y += delta
|
||||
}
|
||||
// If the destination width will cause it to overflow the widget
|
||||
// box, trim off the right edge of the destination rect.
|
||||
//
|
||||
// Keep in mind we're dealing with chunks here, and a chunk is
|
||||
// a small part of the image. Example:
|
||||
// - Canvas is 800x600 (S.W=800 S.H=600)
|
||||
// - Chunk wants to render at 790,0 width 100,100 or whatever
|
||||
// dst={790, 0, 100, 100}
|
||||
// - Chunk box would exceed 800px width (X=790 + W=100 == 890)
|
||||
// - Find the delta how much it exceeds as negative (800 - 890 == -90)
|
||||
// - Lower the Source and Dest rects by that delta size so they
|
||||
// stay proportional and don't scale or anything dumb.
|
||||
if dst.X+src.W > p.X+S.W+w.BoxThickness(1) {
|
||||
// NOTE: delta is a negative number,
|
||||
// so it will subtract from the width.
|
||||
delta := (p.X + S.W - w.BoxThickness(1)) - (dst.W + dst.X)
|
||||
src.W += delta
|
||||
dst.W += delta
|
||||
}
|
||||
if dst.Y+src.H > p.Y+S.H+w.BoxThickness(1) {
|
||||
// NOTE: delta is a negative number
|
||||
delta := (p.Y + S.H - w.BoxThickness(1)) - (dst.H + dst.Y)
|
||||
src.H += delta
|
||||
dst.H += delta
|
||||
}
|
||||
|
||||
// Trim the destination width so it doesn't overlap the Canvas border.
|
||||
if dst.W >= S.W-w.BoxThickness(1) {
|
||||
dst.W = S.W - w.BoxThickness(1)
|
||||
}
|
||||
// The same for the top left edge, so the drawings don't overlap
|
||||
// menu bars or left side toolbars.
|
||||
// - Canvas was placed 80px from the left of the screen.
|
||||
// Canvas.MoveTo(80, 0)
|
||||
// - A texture wants to draw at 60, 0 which would cause it to
|
||||
// overlap 20 pixels into the left toolbar. It needs to be cropped.
|
||||
// - The delta is: p.X=80 - dst.X=60 == 20
|
||||
// - Set destination X to p.X to constrain it there: 20
|
||||
// - Subtract the delta from destination W so we don't scale it.
|
||||
// - Add 20 to X of the source: the left edge of source is not visible
|
||||
//
|
||||
// Note: the +w.BoxThickness works around a bug if the Actor Canvas has
|
||||
// a border on it (e.g. in the Actor/Link Tool mouse-over or debug setting)
|
||||
if dst.X == ParentPosition.X+w.BoxThickness(1) {
|
||||
// NOTE: delta is a positive number,
|
||||
// so it will add to the destination coordinates.
|
||||
delta := texSizeOrig.W - src.W
|
||||
dst.X = p.X + w.BoxThickness(1)
|
||||
src.X += delta
|
||||
}
|
||||
if dst.Y == ParentPosition.Y+w.BoxThickness(1) {
|
||||
delta := texSizeOrig.H - src.H
|
||||
dst.Y = p.Y + w.BoxThickness(1)
|
||||
src.Y += delta
|
||||
}
|
||||
|
||||
// Trim the destination width so it doesn't overlap the Canvas border.
|
||||
if dst.W >= S.W-w.BoxThickness(1) {
|
||||
dst.W = S.W - w.BoxThickness(1)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
// When zooming OUT, make sure the source rect is at least the
|
||||
// full size of the chunk texture; otherwise the ZoomMultiplies
|
||||
|
|
|
@ -262,6 +262,7 @@ func makeDoodadTab(config DoodadDropper, frame *ui.Frame, size render.Rect, cate
|
|||
canvases = append(canvases, can)
|
||||
|
||||
btn := ui.NewButton(doodad.Title, can)
|
||||
can.CroppedSize = true
|
||||
btn.Resize(render.NewRect(
|
||||
buttonSize-2, // TODO: without the -2 the button border
|
||||
buttonSize-2, // rests on top of the window border
|
||||
|
|
Loading…
Reference in New Issue
Block a user