WIP Finishing Up Texture Caching System
Apart from putting the cached bitmaps in a better place, this about finishes up the texture caching optimization and IT IS FAST! When I spam drag a lot of pixels around the FPS may drop to the 40's but once the caches are warmed up the FPS returns to 60 and stays there, even if the screen is very busy with pixels. An undocumented debug feature: set the environment variable DEBUG_CHUNK_COLOR='#00FFFF' to set a bitmap background color besides white to be used when caching the chunks. It helps to visualize where on the screen the bitmaps are being used. May go away in the future. Changes: - Found that the old default chunk size of 1000 was slow to generate bitmap images to cache. The 100px test size was fast and 128 sounds like a good middle ground number to pick for now. - Fixed all the problems with scroll behavior and offset by inverting the sign of the scroll behavior. Scrolling to the Right and Down actually subtracts X,Y values instead of adds them.
这个提交包含在:
父节点
279a980106
当前提交
97394f6cdb
26
balance/debug.go
普通文件
26
balance/debug.go
普通文件
|
@ -0,0 +1,26 @@
|
|||
package balance
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"git.kirsle.net/apps/doodle/render"
|
||||
)
|
||||
|
||||
// Debug related variables that can toggle on or off certain features and
|
||||
// overlays within the game.
|
||||
var (
|
||||
/***************
|
||||
* Visualizers *
|
||||
***************/
|
||||
|
||||
// Background color to use when exporting a drawing Chunk as a bitmap image
|
||||
// on disk. Default is white. Setting this to translucent yellow is a great
|
||||
// way to visualize the chunks loaded from cache on your screen.
|
||||
DebugChunkBitmapBackground = render.White // XXX: export $DEBUG_CHUNK_COLOR
|
||||
)
|
||||
|
||||
func init() {
|
||||
if color := os.Getenv("DEBUG_CHUNK_COLOR"); color != "" {
|
||||
DebugChunkBitmapBackground = render.MustHexColor(color)
|
||||
}
|
||||
}
|
|
@ -10,7 +10,7 @@ var (
|
|||
CanvasScrollSpeed int32 = 8
|
||||
|
||||
// Default chunk size for canvases.
|
||||
ChunkSize = 100
|
||||
ChunkSize = 128
|
||||
|
||||
// Default size for a new Doodad.
|
||||
DoodadSize = 100
|
||||
|
|
8
level/base_test.go
普通文件
8
level/base_test.go
普通文件
|
@ -0,0 +1,8 @@
|
|||
package level_test
|
||||
|
||||
import "github.com/kirsle/golog"
|
||||
|
||||
func init() {
|
||||
log := golog.GetLogger("doodle")
|
||||
log.Config.Level = golog.ErrorLevel
|
||||
}
|
|
@ -7,6 +7,7 @@ import (
|
|||
"math"
|
||||
"os"
|
||||
|
||||
"git.kirsle.net/apps/doodle/balance"
|
||||
"git.kirsle.net/apps/doodle/render"
|
||||
"golang.org/x/image/bmp"
|
||||
)
|
||||
|
@ -103,15 +104,15 @@ func (c *Chunk) ToBitmap(filename string) error {
|
|||
// Blank out the pixels.
|
||||
for x := 0; x < img.Bounds().Max.X; x++ {
|
||||
for y := 0; y < img.Bounds().Max.Y; y++ {
|
||||
img.Set(x, y, render.RGBA(255, 255, 0, 153).ToColor())
|
||||
img.Set(x, y, balance.DebugChunkBitmapBackground.ToColor())
|
||||
}
|
||||
}
|
||||
|
||||
// Pixel coordinate offset to map the Chunk World Position to the
|
||||
// smaller image boundaries.
|
||||
pointOffset := render.Point{
|
||||
X: int32(math.Abs(float64(c.Point.X * int32(c.Size)))),
|
||||
Y: int32(math.Abs(float64(c.Point.Y * int32(c.Size)))),
|
||||
X: int32(c.Point.X * int32(c.Size)),
|
||||
Y: int32(c.Point.Y * int32(c.Size)),
|
||||
}
|
||||
|
||||
// Blot all the pixels onto it.
|
||||
|
@ -181,8 +182,6 @@ func (c *Chunk) Rect() render.Rect {
|
|||
func (c *Chunk) SizePositive() render.Rect {
|
||||
S := c.Rect()
|
||||
return render.Rect{
|
||||
X: c.Point.X * int32(c.Size),
|
||||
Y: c.Point.Y * int32(c.Size),
|
||||
W: int32(math.Abs(float64(S.X))) + S.W,
|
||||
H: int32(math.Abs(float64(S.Y))) + S.H,
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ func (c *Chunker) IterViewportChunks(viewport render.Rect) <-chan render.Point {
|
|||
pipe := make(chan render.Point)
|
||||
go func() {
|
||||
sent := make(map[render.Point]interface{})
|
||||
|
||||
for x := viewport.X; x < viewport.W; x += int32(c.Size / 4) {
|
||||
for y := viewport.Y; y < viewport.H; y += int32(c.Size / 4) {
|
||||
|
||||
|
@ -94,27 +95,17 @@ func (c *Chunker) IterViewportChunks(viewport render.Rect) <-chan render.Point {
|
|||
|
||||
// Translate to a chunk coordinate, dedupe and send it.
|
||||
coord := c.ChunkCoordinate(render.NewPoint(x, y))
|
||||
// fmt.Printf("IterViewportChunks: x=%d y=%d chunk=%s\n", x, y, coord)
|
||||
if _, ok := sent[coord]; ok {
|
||||
continue
|
||||
}
|
||||
sent[coord] = nil
|
||||
|
||||
if _, ok := c.GetChunk(coord); ok {
|
||||
fmt.Printf("Iter: send chunk %s for point %s\n", coord, point)
|
||||
pipe <- coord
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for cx := topLeft.X; cx <= bottomRight.X; cx++ {
|
||||
// for cy := topLeft.Y; cy <= bottomRight.Y; cy++ {
|
||||
// pt := render.NewPoint(cx, cy)
|
||||
// if _, ok := c.GetChunk(pt); ok {
|
||||
// pipe <- pt
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
close(pipe)
|
||||
}()
|
||||
return pipe
|
||||
|
|
|
@ -32,8 +32,6 @@ func (t *Texture) Size() render.Rect {
|
|||
|
||||
// NewBitmap initializes a texture from a bitmap image.
|
||||
func (r *Renderer) NewBitmap(filename string) (render.Texturer, error) {
|
||||
log.Debug("NewBitmap: open from file %s", filename)
|
||||
|
||||
surface, err := sdl.LoadBMP(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("NewBitmap: LoadBMP: %s", err)
|
||||
|
@ -45,7 +43,6 @@ func (r *Renderer) NewBitmap(filename string) (render.Texturer, error) {
|
|||
return nil, fmt.Errorf("NewBitmap: create texture: %s", err)
|
||||
}
|
||||
|
||||
log.Debug("Created texture")
|
||||
return &Texture{
|
||||
width: surface.W,
|
||||
height: surface.H,
|
||||
|
|
|
@ -107,14 +107,14 @@ func (w *Canvas) Loop(ev *events.State) error {
|
|||
// Arrow keys to scroll the view.
|
||||
scrollBy := render.Point{}
|
||||
if ev.Right.Now {
|
||||
scrollBy.X += balance.CanvasScrollSpeed
|
||||
} else if ev.Left.Now {
|
||||
scrollBy.X -= balance.CanvasScrollSpeed
|
||||
} else if ev.Left.Now {
|
||||
scrollBy.X += balance.CanvasScrollSpeed
|
||||
}
|
||||
if ev.Down.Now {
|
||||
scrollBy.Y += balance.CanvasScrollSpeed
|
||||
} else if ev.Up.Now {
|
||||
scrollBy.Y -= balance.CanvasScrollSpeed
|
||||
} else if ev.Up.Now {
|
||||
scrollBy.Y += balance.CanvasScrollSpeed
|
||||
}
|
||||
if !scrollBy.IsZero() {
|
||||
w.ScrollBy(scrollBy)
|
||||
|
@ -136,8 +136,8 @@ func (w *Canvas) Loop(ev *events.State) error {
|
|||
if ev.Button1.Now {
|
||||
lastPixel := w.lastPixel
|
||||
cursor := render.Point{
|
||||
X: ev.CursorX.Now - P.X + w.Scroll.X,
|
||||
Y: ev.CursorY.Now - P.Y + w.Scroll.Y,
|
||||
X: ev.CursorX.Now - P.X - w.Scroll.X,
|
||||
Y: ev.CursorY.Now - P.Y - w.Scroll.Y,
|
||||
}
|
||||
pixel := &level.Pixel{
|
||||
X: cursor.X,
|
||||
|
@ -184,10 +184,10 @@ func (w *Canvas) Loop(ev *events.State) error {
|
|||
func (w *Canvas) Viewport() render.Rect {
|
||||
var S = w.Size()
|
||||
return render.Rect{
|
||||
X: w.Scroll.X,
|
||||
Y: w.Scroll.Y,
|
||||
W: S.W - w.BoxThickness(2) + w.Scroll.X,
|
||||
H: S.H - w.BoxThickness(2) + w.Scroll.Y,
|
||||
X: -w.Scroll.X,
|
||||
Y: -w.Scroll.Y,
|
||||
W: S.W - w.Scroll.X,
|
||||
H: S.H - w.Scroll.Y,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -258,13 +258,6 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
|
|||
H: src.H, // - w.Scroll.Y,
|
||||
}
|
||||
|
||||
// log.Warn(
|
||||
// "chunk: %s src: %s dst: %s",
|
||||
// coord,
|
||||
// src,
|
||||
// dst,
|
||||
// )
|
||||
|
||||
// If the destination width will cause it to overflow the widget
|
||||
// box, trim off the right edge of the destination rect.
|
||||
//
|
||||
|
@ -316,12 +309,6 @@ func (w *Canvas) Present(e render.Engine, p render.Point) {
|
|||
src.Y += delta
|
||||
}
|
||||
|
||||
// If the destination rect would overflow our widget bounds, trim
|
||||
// it off.
|
||||
|
||||
// if w.Name == "edit-canvas" {
|
||||
// log.Info("%s: copy %+v -> %+v", w.Name, src, dst)
|
||||
// }
|
||||
e.Copy(tex, src, dst)
|
||||
}
|
||||
}
|
||||
|
|
正在加载...
在新工单中引用
屏蔽一个用户