From 1083ca720d86df71991e565d41a82a6d83e5e0cc Mon Sep 17 00:00:00 2001
From: faiface <faiface@ksp.sk>
Date: Mon, 6 Mar 2017 19:04:57 +0100
Subject: [PATCH] add Picture.Original

---
 data.go           |  9 +++++++++
 drawer.go         |  7 ++++---
 interface.go      |  8 ++++++++
 pixelgl/canvas.go | 32 ++++++++++++++++++++++++++------
 4 files changed, 47 insertions(+), 9 deletions(-)

diff --git a/data.go b/data.go
index 59196f3..3c3fc5f 100644
--- a/data.go
+++ b/data.go
@@ -129,6 +129,7 @@ type PictureData struct {
 	Pix    []NRGBA
 	Stride int
 	Rect   Rect
+	Orig   *PictureData
 }
 
 // MakePictureData creates a zero-initialized PictureData covering the given rectangle.
@@ -140,6 +141,7 @@ func MakePictureData(rect Rect) *PictureData {
 		Rect:   rect,
 	}
 	pd.Pix = make([]NRGBA, w*h)
+	pd.Orig = pd
 	return pd
 }
 
@@ -265,9 +267,16 @@ func (pd *PictureData) Slice(r Rect) Picture {
 		Pix:    pd.Pix[pd.offset(r.Pos):],
 		Stride: pd.Stride,
 		Rect:   r,
+		Orig:   pd.Orig,
 	}
 }
 
+// Original returns the most original PictureData that this PictureData was obtained from using
+// Slice-ing.
+func (pd *PictureData) Original() Picture {
+	return pd.Orig
+}
+
 // Color returns the color located at the given position.
 func (pd *PictureData) Color(at Vec) NRGBA {
 	if !pd.Rect.Contains(at) {
diff --git a/drawer.go b/drawer.go
index d5ec2fe..a1bf9d2 100644
--- a/drawer.go
+++ b/drawer.go
@@ -77,11 +77,12 @@ func (d *Drawer) Draw(t Target) {
 		return
 	}
 
-	pic := d.pics[targetPicturePair{t, d.Picture}]
+	pic := d.pics[targetPicturePair{t, d.Picture.Original()}]
 	if pic == nil {
-		pic = t.MakePicture(d.Picture)
-		d.pics[targetPicturePair{t, d.Picture}] = pic
+		pic = t.MakePicture(d.Picture.Original())
+		d.pics[targetPicturePair{t, d.Picture.Original()}] = pic
 	}
+	pic = pic.Slice(d.Picture.Bounds()).(TargetPicture)
 
 	pic.Draw(tri)
 }
diff --git a/interface.go b/interface.go
index 0cb906b..d58cee7 100644
--- a/interface.go
+++ b/interface.go
@@ -109,6 +109,14 @@ type Picture interface {
 
 	// Slice returns a sub-Picture with specified Bounds.
 	Slice(Rect) Picture
+
+	// Original returns the most original Picture (may be itself) that this Picture was created
+	// from using Slice-ing.
+	//
+	// Since the Original and this Picture should share the underlying data and this Picture can
+	// be obtained just by slicing the Original, this method can be used for more efficient
+	// caching of Pictures.
+	Original() Picture
 }
 
 // TargetPicture is a Picture generated by a Target using MakePicture method. This Picture can be drawn onto
diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go
index ef3e553..16ae1b2 100644
--- a/pixelgl/canvas.go
+++ b/pixelgl/canvas.go
@@ -69,6 +69,17 @@ func (c *Canvas) MakeTriangles(t pixel.Triangles) pixel.TargetTriangles {
 //
 // PictureColor is supported.
 func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
+	if cp, ok := p.(*canvasPicture); ok {
+		return &canvasPicture{
+			tex:      cp.tex,
+			orig:     cp.orig,
+			size:     cp.size,
+			bounds:   cp.bounds,
+			original: cp.original,
+			c:        c,
+		}
+	}
+
 	bounds := p.Bounds()
 	bx, by, bw, bh := discreteBounds(bounds)
 
@@ -94,13 +105,15 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
 		tex = glhf.NewTexture(bw, bh, c.smooth, pixels)
 	})
 
-	return &canvasPicture{
+	cp := &canvasPicture{
 		tex:    tex,
 		orig:   pixel.V(float64(bx), float64(by)),
 		size:   pixel.V(float64(bw), float64(bh)),
 		bounds: bounds,
 		c:      c,
 	}
+	cp.original = cp
+	return cp
 }
 
 // SetTransform sets a set of Transforms that every position in triangles will be put through.
@@ -258,7 +271,8 @@ type canvasPicture struct {
 	orig, size pixel.Vec
 	bounds     pixel.Rect
 
-	c *Canvas
+	original *canvasPicture
+	c        *Canvas
 }
 
 func (cp *canvasPicture) Bounds() pixel.Rect {
@@ -267,13 +281,19 @@ func (cp *canvasPicture) Bounds() pixel.Rect {
 
 func (cp *canvasPicture) Slice(r pixel.Rect) pixel.Picture {
 	return &canvasPicture{
-		orig:   cp.orig,
-		size:   cp.size,
-		bounds: r,
-		c:      cp.c,
+		tex:      cp.tex,
+		orig:     cp.orig,
+		size:     cp.size,
+		bounds:   r,
+		original: cp.original,
+		c:        cp.c,
 	}
 }
 
+func (cp *canvasPicture) Original() pixel.Picture {
+	return cp.original
+}
+
 func (cp *canvasPicture) Draw(t pixel.TargetTriangles) {
 	ct := t.(*canvasTriangles)
 	if cp.c != ct.c {
-- 
GitLab