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.
func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
// short paths
if cp, ok := p.(*canvasPicture); ok {
tp := new(canvasPicture)
*tp = *cp
tp.c = c
tp.dst = c
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()
bx, by, bw, bh := intBounds(bounds)
@ -112,7 +126,7 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
float64(bw), float64(bh),
),
bounds: bounds,
c: c,
dst: c,
}
cp.orig = cp
return cp
@ -239,9 +253,10 @@ func (c *Canvas) Original() pixel.Picture {
func (c *Canvas) Color(at pixel.Vec) pixel.NRGBA {
if c.orig.dirty {
mainthread.Call(func() {
c.f.Texture.Begin()
c.orig.pixels = c.f.Texture.Pixels(0, 0, c.f.Texture.Width(), c.f.Texture.Height())
c.f.Texture.End()
tex := c.f.Texture()
tex.Begin()
c.orig.pixels = tex.Pixels(0, 0, tex.Width(), tex.Height())
tex.End()
})
c.orig.dirty = false
}
@ -265,7 +280,7 @@ type canvasTriangles struct {
c *Canvas
}
func (ct *canvasTriangles) draw(cp *canvasPicture) {
func (ct *canvasTriangles) draw(tex *glhf.Texture, borders, bounds pixel.Rect) {
ct.c.orig.dirty = true
// 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(canvasColorMask, col)
if cp == nil {
if tex == nil {
ct.vs.Begin()
ct.vs.Draw()
ct.vs.End()
} else {
cp.tex.Begin()
tex.Begin()
ct.c.s.SetUniformAttr(canvasTexBorders, mgl32.Vec4{
float32(cp.borders.X()),
float32(cp.borders.Y()),
float32(cp.borders.W()),
float32(cp.borders.H()),
float32(borders.X()),
float32(borders.Y()),
float32(borders.W()),
float32(borders.H()),
})
ct.c.s.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
float32(cp.bounds.X()),
float32(cp.bounds.Y()),
float32(cp.bounds.W()),
float32(cp.bounds.H()),
float32(bounds.X()),
float32(bounds.Y()),
float32(bounds.W()),
float32(bounds.H()),
})
if cp.tex.Smooth() != ct.c.smooth {
cp.tex.SetSmooth(ct.c.smooth)
if tex.Smooth() != ct.c.smooth {
tex.SetSmooth(ct.c.smooth)
}
ct.vs.Begin()
ct.vs.Draw()
ct.vs.End()
cp.tex.End()
tex.End()
}
ct.c.s.End()
@ -323,7 +338,7 @@ func (ct *canvasTriangles) draw(cp *canvasPicture) {
}
func (ct *canvasTriangles) Draw() {
ct.draw(nil)
ct.draw(nil, pixel.Rect{}, pixel.Rect{})
}
type canvasPicture struct {
@ -332,7 +347,7 @@ type canvasPicture struct {
bounds pixel.Rect
orig *canvasPicture
c *Canvas
dst *Canvas
}
func (cp *canvasPicture) Bounds() pixel.Rect {
@ -352,10 +367,39 @@ func (cp *canvasPicture) Original() pixel.Picture {
func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
ct := t.(*canvasTriangles)
if cp.c != ct.c {
if cp.dst != ct.c {
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 (

View File

@ -166,14 +166,14 @@ func (w *Window) Update() {
mainthread.Call(func() {
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)
w.canvas.f.Begin()
w.canvas.f.Blit(
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()