allow efficiently drawing one Canvas onto another
This commit is contained in:
parent
f65ea40e19
commit
3d13e52add
|
@ -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 (
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue