allow efficiently drawing one Canvas onto another

This commit is contained in:
faiface 2017-03-07 20:33:07 +01:00
parent f65ea40e19
commit 3d13e52add
2 changed files with 70 additions and 26 deletions

View File

@ -73,12 +73,26 @@ func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
// //
// PictureColor is supported. // PictureColor is supported.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture { func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
// short paths
if cp, ok := p.(*canvasPicture); ok { if cp, ok := p.(*canvasPicture); ok {
tp := new(canvasPicture) tp := new(canvasPicture)
*tp = *cp *tp = *cp
tp.c = c tp.dst = c
return tp return tp
} }
if ccp, ok := p.(*canvasCanvasPicture); ok {
tp := new(canvasCanvasPicture)
*tp = *ccp
tp.dst = c
return tp
}
if canvas, ok := p.(*Canvas); ok {
return &canvasCanvasPicture{
src: canvas,
dst: c,
bounds: c.bounds,
}
}
bounds := p.Bounds() bounds := p.Bounds()
bx, by, bw, bh := intBounds(bounds) bx, by, bw, bh := intBounds(bounds)
@ -112,7 +126,7 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
float64(bw), float64(bh), float64(bw), float64(bh),
), ),
bounds: bounds, bounds: bounds,
c: c, dst: c,
} }
cp.orig = cp cp.orig = cp
return cp return cp
@ -239,9 +253,10 @@ func (c *Canvas) Original() pixel.Picture {
func (c *Canvas) Color(at pixel.Vec) pixel.NRGBA { func (c *Canvas) Color(at pixel.Vec) pixel.NRGBA {
if c.orig.dirty { if c.orig.dirty {
mainthread.Call(func() { mainthread.Call(func() {
c.f.Texture.Begin() tex := c.f.Texture()
c.orig.pixels = c.f.Texture.Pixels(0, 0, c.f.Texture.Width(), c.f.Texture.Height()) tex.Begin()
c.f.Texture.End() c.orig.pixels = tex.Pixels(0, 0, tex.Width(), tex.Height())
tex.End()
}) })
c.orig.dirty = false c.orig.dirty = false
} }
@ -265,7 +280,7 @@ type canvasTriangles struct {
c *Canvas c *Canvas
} }
func (ct *canvasTriangles) draw(cp *canvasPicture) { func (ct *canvasTriangles) draw(tex *glhf.Texture, borders, bounds pixel.Rect) {
ct.c.orig.dirty = true ct.c.orig.dirty = true
// save the current state vars to avoid race condition // save the current state vars to avoid race condition
@ -286,35 +301,35 @@ func (ct *canvasTriangles) draw(cp *canvasPicture) {
ct.c.s.SetUniformAttr(canvasTransform, mat) ct.c.s.SetUniformAttr(canvasTransform, mat)
ct.c.s.SetUniformAttr(canvasColorMask, col) ct.c.s.SetUniformAttr(canvasColorMask, col)
if cp == nil { if tex == nil {
ct.vs.Begin() ct.vs.Begin()
ct.vs.Draw() ct.vs.Draw()
ct.vs.End() ct.vs.End()
} else { } else {
cp.tex.Begin() tex.Begin()
ct.c.s.SetUniformAttr(canvasTexBorders, mgl32.Vec4{ ct.c.s.SetUniformAttr(canvasTexBorders, mgl32.Vec4{
float32(cp.borders.X()), float32(borders.X()),
float32(cp.borders.Y()), float32(borders.Y()),
float32(cp.borders.W()), float32(borders.W()),
float32(cp.borders.H()), float32(borders.H()),
}) })
ct.c.s.SetUniformAttr(canvasTexBounds, mgl32.Vec4{ ct.c.s.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
float32(cp.bounds.X()), float32(bounds.X()),
float32(cp.bounds.Y()), float32(bounds.Y()),
float32(cp.bounds.W()), float32(bounds.W()),
float32(cp.bounds.H()), float32(bounds.H()),
}) })
if cp.tex.Smooth() != ct.c.smooth { if tex.Smooth() != ct.c.smooth {
cp.tex.SetSmooth(ct.c.smooth) tex.SetSmooth(ct.c.smooth)
} }
ct.vs.Begin() ct.vs.Begin()
ct.vs.Draw() ct.vs.Draw()
ct.vs.End() ct.vs.End()
cp.tex.End() tex.End()
} }
ct.c.s.End() ct.c.s.End()
@ -323,7 +338,7 @@ func (ct *canvasTriangles) draw(cp *canvasPicture) {
} }
func (ct *canvasTriangles) Draw() { func (ct *canvasTriangles) Draw() {
ct.draw(nil) ct.draw(nil, pixel.Rect{}, pixel.Rect{})
} }
type canvasPicture struct { type canvasPicture struct {
@ -332,7 +347,7 @@ type canvasPicture struct {
bounds pixel.Rect bounds pixel.Rect
orig *canvasPicture orig *canvasPicture
c *Canvas dst *Canvas
} }
func (cp *canvasPicture) Bounds() pixel.Rect { func (cp *canvasPicture) Bounds() pixel.Rect {
@ -352,10 +367,39 @@ func (cp *canvasPicture) Original() pixel.Picture {
func (cp *canvasPicture) Draw(t pixel.TargetTriangles) { func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
ct := t.(*canvasTriangles) ct := t.(*canvasTriangles)
if cp.c != ct.c { if cp.dst != ct.c {
panic(fmt.Errorf("%T.Draw: TargetTriangles generated by different Canvas", cp)) panic(fmt.Errorf("%T.Draw: TargetTriangles generated by different Canvas", cp))
} }
ct.draw(cp) ct.draw(cp.tex, cp.borders, cp.bounds)
}
type canvasCanvasPicture struct {
src, dst *Canvas
bounds pixel.Rect
orig *canvasCanvasPicture
}
func (ccp *canvasCanvasPicture) Bounds() pixel.Rect {
return ccp.bounds
}
func (ccp *canvasCanvasPicture) Slice(r pixel.Rect) pixel.Picture {
sp := new(canvasCanvasPicture)
*sp = *ccp
sp.bounds = r
return sp
}
func (ccp *canvasCanvasPicture) Original() pixel.Picture {
return ccp.orig
}
func (ccp *canvasCanvasPicture) Draw(t pixel.TargetTriangles) {
ct := t.(*canvasTriangles)
if ccp.dst != ct.c {
panic(fmt.Errorf("%T.Draw: TargetTriangles generated by different Canvas", ccp))
}
ct.draw(ccp.src.f.Texture(), ccp.src.orig.bounds, ccp.bounds)
} }
const ( const (

View File

@ -166,14 +166,14 @@ func (w *Window) Update() {
mainthread.Call(func() { mainthread.Call(func() {
w.begin() w.begin()
glhf.Bounds(0, 0, w.canvas.f.Texture.Width(), w.canvas.f.Texture.Height()) glhf.Bounds(0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height())
glhf.Clear(0, 0, 0, 0) glhf.Clear(0, 0, 0, 0)
w.canvas.f.Begin() w.canvas.f.Begin()
w.canvas.f.Blit( w.canvas.f.Blit(
nil, nil,
0, 0, w.canvas.f.Texture.Width(), w.canvas.f.Texture.Height(), 0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height(),
0, 0, w.canvas.f.Texture.Width(), w.canvas.f.Texture.Height(), 0, 0, w.canvas.f.Texture().Width(), w.canvas.f.Texture().Height(),
) )
w.canvas.f.End() w.canvas.f.End()