From 5a9235aaf9a757d4f6bed09d2eafcb79674cd49f Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 26 Jul 2018 11:37:27 +0900 Subject: [PATCH] graphics: Embed color matrices values to vertices (#655) Fixes #531 --- image.go | 4 +- internal/affine/colorm.go | 42 --------------- internal/graphics/command.go | 30 +++++------ internal/graphics/image.go | 5 +- internal/graphics/program.go | 61 +++++++++++----------- internal/graphics/shader.go | 15 ++++-- internal/graphicsutil/vertices.go | 60 ++++++++++++++-------- internal/restorable/image.go | 17 +++---- internal/restorable/images_test.go | 76 ++++++++++++++-------------- internal/shareable/shareable.go | 16 +++--- internal/shareable/shareable_test.go | 16 +++--- 11 files changed, 158 insertions(+), 184 deletions(-) diff --git a/image.go b/image.go index f9ecba6c2..fabab019c 100644 --- a/image.go +++ b/image.go @@ -238,9 +238,9 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { } a, b, c, d, tx, ty := geom.elements() - vs := img.shareableImage.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty) + vs := img.shareableImage.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, options.ColorM.impl) is := graphicsutil.QuadIndices() - i.shareableImage.DrawImage(img.shareableImage, vs, is, options.ColorM.impl, mode, filter) + i.shareableImage.DrawImage(img.shareableImage, vs, is, mode, filter) return nil } diff --git a/internal/affine/colorm.go b/internal/affine/colorm.go index 81d506d74..460b7a675 100644 --- a/internal/affine/colorm.go +++ b/internal/affine/colorm.go @@ -139,48 +139,6 @@ func (c *ColorM) SetElement(i, j int, element float32) *ColorM { return newC } -func (c *ColorM) Equals(other *ColorM) bool { - if !c.isInited() && !other.isInited() { - return true - } - - lhsb := colorMIdentityBody - lhst := colorMIdentityTranslate - rhsb := colorMIdentityBody - rhst := colorMIdentityTranslate - if other.isInited() { - if other.body != nil { - lhsb = other.body - } - if other.translate != nil { - lhst = other.translate - } - } - if c.isInited() { - if c.body != nil { - rhsb = c.body - } - if c.translate != nil { - rhst = c.translate - } - } - if &lhsb == &rhsb && &lhst == &rhst { - return true - } - - for i := range lhsb { - if lhsb[i] != rhsb[i] { - return false - } - } - for i := range lhst { - if lhst[i] != rhst[i] { - return false - } - } - return true -} - // Concat multiplies a color matrix with the other color matrix. // This is same as muptiplying the matrix other and the matrix c in this order. func (c *ColorM) Concat(other *ColorM) *ColorM { diff --git a/internal/graphics/command.go b/internal/graphics/command.go index 8ad670462..eaceab81a 100644 --- a/internal/graphics/command.go +++ b/internal/graphics/command.go @@ -17,7 +17,6 @@ package graphics import ( "fmt" - "github.com/hajimehoshi/ebiten/internal/affine" emath "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -34,7 +33,7 @@ type command interface { NumIndices() int AddNumVertices(n int) AddNumIndices(n int) - CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool + CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool } // commandQueue is a command queue for drawing commands. @@ -86,12 +85,12 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) { q.nindices += len(indices) } -func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, color *affine.ColorM, mode opengl.CompositeMode, filter Filter, forceNewCommand bool) { +func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, mode opengl.CompositeMode, filter Filter, forceNewCommand bool) { if nindices > indicesNum { panic("not implemented for too many indices") } if !forceNewCommand && 0 < len(q.commands) { - if last := q.commands[len(q.commands)-1]; last.CanMerge(dst, src, color, mode, filter) { + if last := q.commands[len(q.commands)-1]; last.CanMerge(dst, src, mode, filter) { last.AddNumVertices(nvertices) last.AddNumIndices(nindices) return @@ -102,7 +101,6 @@ func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nin src: src, nvertices: nvertices, nindices: nindices, - color: color, mode: mode, filter: filter, } @@ -110,7 +108,7 @@ func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nin } // EnqueueDrawImageCommand enqueues a drawing-image command. -func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) { +func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter Filter) { if len(indices) > indicesNum { panic("not reached") } @@ -127,7 +125,7 @@ func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float q.nextIndex += len(vertices) * opengl.Float.SizeInBytes() / VertexSizeInBytes() q.tmpNumIndices += len(indices) - q.doEnqueueDrawImageCommand(dst, src, len(vertices), len(indices), color, mode, filter, split) + q.doEnqueueDrawImageCommand(dst, src, len(vertices), len(indices), mode, filter, split) } // Enqueue enqueues a drawing command other than a draw-image command. @@ -211,7 +209,6 @@ type drawImageCommand struct { src *Image nvertices int nindices int - color *affine.ColorM mode opengl.CompositeMode filter Filter } @@ -235,7 +232,7 @@ func (c *drawImageCommand) Exec(indexOffsetInBytes int) error { return nil } proj := f.projectionMatrix() - theOpenGLState.useProgram(proj, c.src.texture.native, c.dst, c.src, c.color, c.filter) + theOpenGLState.useProgram(proj, c.src.texture.native, c.dst, c.src, c.filter) opengl.GetContext().DrawElements(opengl.Triangles, c.nindices, indexOffsetInBytes) // glFlush() might be necessary at least on MacBook Pro (a smilar problem at #419), @@ -263,16 +260,13 @@ func (c *drawImageCommand) AddNumIndices(n int) { // CanMerge returns a boolean value indicating whether the other drawImageCommand can be merged // with the drawImageCommand c. -func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *drawImageCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { if c.dst != dst { return false } if c.src != src { return false } - if !c.color.Equals(color) { - return false - } if c.mode != mode { return false } @@ -316,7 +310,7 @@ func (c *replacePixelsCommand) AddNumVertices(n int) { func (c *replacePixelsCommand) AddNumIndices(n int) { } -func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *replacePixelsCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -353,7 +347,7 @@ func (c *pixelsCommand) AddNumVertices(n int) { func (c *pixelsCommand) AddNumIndices(n int) { } -func (c *pixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *pixelsCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -388,7 +382,7 @@ func (c *disposeCommand) AddNumVertices(n int) { func (c *disposeCommand) AddNumIndices(n int) { } -func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *disposeCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -444,7 +438,7 @@ func (c *newImageCommand) AddNumVertices(n int) { func (c *newImageCommand) AddNumIndices(n int) { } -func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *newImageCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -479,6 +473,6 @@ func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) { func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) { } -func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { +func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { return false } diff --git a/internal/graphics/image.go b/internal/graphics/image.go index 5f5bdefe9..00ba9cc66 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -15,7 +15,6 @@ package graphics import ( - "github.com/hajimehoshi/ebiten/internal/affine" "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -86,8 +85,8 @@ func (i *Image) Size() (int, int) { return i.width, i.height } -func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, clr *affine.ColorM, mode opengl.CompositeMode, filter Filter) { - theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, clr, mode, filter) +func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter Filter) { + theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, mode, filter) } // Pixels returns the image's pixels. diff --git a/internal/graphics/program.go b/internal/graphics/program.go index 330d2c5e6..9008c8628 100644 --- a/internal/graphics/program.go +++ b/internal/graphics/program.go @@ -17,7 +17,6 @@ package graphics import ( "fmt" - "github.com/hajimehoshi/ebiten/internal/affine" emath "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/web" @@ -94,6 +93,31 @@ var ( dataType: opengl.Float, num: 4, }, + { + name: "color_body0", + dataType: opengl.Float, + num: 4, + }, + { + name: "color_body1", + dataType: opengl.Float, + num: 4, + }, + { + name: "color_body2", + dataType: opengl.Float, + num: 4, + }, + { + name: "color_body3", + dataType: opengl.Float, + num: 4, + }, + { + name: "color_translate", + dataType: opengl.Float, + num: 4, + }, }, } ) @@ -114,12 +138,10 @@ type openGLState struct { programScreen opengl.Program - lastProgram opengl.Program - lastProjectionMatrix []float32 - lastColorMatrix []float32 - lastColorMatrixTranslation []float32 - lastSourceWidth int - lastSourceHeight int + lastProgram opengl.Program + lastProjectionMatrix []float32 + lastSourceWidth int + lastSourceHeight int } var ( @@ -149,8 +171,6 @@ func (s *openGLState) reset() error { s.lastProgram = zeroProgram s.lastProjectionMatrix = nil - s.lastColorMatrix = nil - s.lastColorMatrixTranslation = nil s.lastSourceWidth = 0 s.lastSourceHeight = 0 @@ -250,7 +270,7 @@ func areSameFloat32Array(a, b []float32) bool { } // useProgram uses the program (programTexture). -func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, src *Image, colorM *affine.ColorM, filter Filter) { +func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, src *Image, filter Filter) { c := opengl.GetContext() var program opengl.Program @@ -280,8 +300,6 @@ func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, sr s.lastProgram = program s.lastProjectionMatrix = nil - s.lastColorMatrix = nil - s.lastColorMatrixTranslation = nil s.lastSourceWidth = 0 s.lastSourceHeight = 0 } @@ -296,25 +314,6 @@ func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, sr s.lastProjectionMatrix = proj } - esBody, esTranslate := colorM.UnsafeElements() - - if !areSameFloat32Array(s.lastColorMatrix, esBody) { - c.UniformFloats(program, "color_matrix_body", esBody) - if s.lastColorMatrix == nil { - s.lastColorMatrix = make([]float32, 16) - } - // ColorM's elements are immutable. It's OK to hold the reference without copying. - s.lastColorMatrix = esBody - } - if !areSameFloat32Array(s.lastColorMatrixTranslation, esTranslate) { - c.UniformFloats(program, "color_matrix_translation", esTranslate) - if s.lastColorMatrixTranslation == nil { - s.lastColorMatrixTranslation = make([]float32, 4) - } - // ColorM's elements are immutable. It's OK to hold the reference without copying. - s.lastColorMatrixTranslation = esTranslate - } - sw, sh := src.Size() sw = emath.NextPowerOf2Int(sw) sh = emath.NextPowerOf2Int(sh) diff --git a/internal/graphics/shader.go b/internal/graphics/shader.go index 2fd0efa4a..0580a63f8 100644 --- a/internal/graphics/shader.go +++ b/internal/graphics/shader.go @@ -50,15 +50,24 @@ const ( uniform mat4 projection_matrix; attribute vec2 vertex; attribute vec4 tex_coord; +attribute vec4 color_body0; +attribute vec4 color_body1; +attribute vec4 color_body2; +attribute vec4 color_body3; +attribute vec4 color_translate; varying vec2 varying_tex_coord; varying vec2 varying_tex_coord_min; varying vec2 varying_tex_coord_max; +varying mat4 varying_color_body; +varying vec4 varying_color_translate; void main(void) { varying_tex_coord = vec2(tex_coord[0], tex_coord[1]); varying_tex_coord_min = vec2(min(tex_coord[0], tex_coord[2]), min(tex_coord[1], tex_coord[3])); varying_tex_coord_max = vec2(max(tex_coord[0], tex_coord[2]), max(tex_coord[1], tex_coord[3])); gl_Position = projection_matrix * vec4(vertex, 0, 1); + varying_color_body = mat4(color_body0, color_body1, color_body2, color_body3); + varying_color_translate = color_translate; } ` shaderStrFragment = ` @@ -73,8 +82,6 @@ precision mediump float; {{Definitions}} uniform sampler2D texture; -uniform mat4 color_matrix_body; -uniform vec4 color_matrix_translation; uniform highp vec2 source_size; @@ -85,6 +92,8 @@ uniform highp float scale; varying highp vec2 varying_tex_coord; varying highp vec2 varying_tex_coord_min; varying highp vec2 varying_tex_coord_max; +varying highp mat4 varying_color_body; +varying highp vec4 varying_color_translate; void main(void) { highp vec2 pos = varying_tex_coord; @@ -148,7 +157,7 @@ void main(void) { color.rgb /= color.a; } // Apply the color matrix - color = (color_matrix_body * color) + color_matrix_translation; + color = (varying_color_body * color) + varying_color_translate; color = clamp(color, 0.0, 1.0); // Premultiply alpha color.rgb *= color.a; diff --git a/internal/graphicsutil/vertices.go b/internal/graphicsutil/vertices.go index 9eb8e5744..5cadc446f 100644 --- a/internal/graphicsutil/vertices.go +++ b/internal/graphicsutil/vertices.go @@ -15,6 +15,7 @@ package graphicsutil import ( + "github.com/hajimehoshi/ebiten/internal/affine" "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -47,7 +48,7 @@ func isPowerOf2(x int) bool { return (x & (x - 1)) == 0 } -func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32) []float32 { +func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, colorm *affine.ColorM) []float32 { if !isPowerOf2(width) { panic("not reached") } @@ -65,15 +66,16 @@ func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty wf := float32(width) hf := float32(height) u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf - return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty) + return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty, colorm) } -func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32) []float32 { +func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32, colorm *affine.ColorM) []float32 { // Specifying a range explicitly here is redundant but this helps optimization // to eliminate boundry checks. - vs := theVerticesBackend.sliceForOneQuad()[0:24] + vs := theVerticesBackend.sliceForOneQuad()[0:104] ax, by, cx, dy := a*x, b*y, c*x, d*y + cbody, ctranslate := colorm.UnsafeElements() // Vertex coordinates vs[0] = tx @@ -88,26 +90,40 @@ func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32) []float3 vs[5] = v1 // and the same for the other three coordinates - vs[6] = ax + tx - vs[7] = cx + ty - vs[8] = u1 - vs[9] = v0 - vs[10] = u0 - vs[11] = v1 + vs[26] = ax + tx + vs[27] = cx + ty + vs[28] = u1 + vs[29] = v0 + vs[30] = u0 + vs[31] = v1 - vs[12] = by + tx - vs[13] = dy + ty - vs[14] = u0 - vs[15] = v1 - vs[16] = u1 - vs[17] = v0 + vs[52] = by + tx + vs[53] = dy + ty + vs[54] = u0 + vs[55] = v1 + vs[56] = u1 + vs[57] = v0 - vs[18] = ax + by + tx - vs[19] = cx + dy + ty - vs[20] = u1 - vs[21] = v1 - vs[22] = u0 - vs[23] = v0 + vs[78] = ax + by + tx + vs[79] = cx + dy + ty + vs[80] = u1 + vs[81] = v1 + vs[82] = u0 + vs[83] = v0 + + // Use for loop since subslicing is heavy on GopherJS. + for i := 0; i < 16; i++ { + vs[6+i] = cbody[i] + vs[32+i] = cbody[i] + vs[58+i] = cbody[i] + vs[84+i] = cbody[i] + } + for i := 0; i < 4; i++ { + vs[22+i] = ctranslate[i] + vs[48+i] = ctranslate[i] + vs[74+i] = ctranslate[i] + vs[100+i] = ctranslate[i] + } return vs } diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 906dbc3f9..a2625dd28 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -31,7 +31,6 @@ type drawImageHistoryItem struct { image *Image vertices []float32 indices []uint16 - colorm *affine.ColorM mode opengl.CompositeMode filter graphics.Filter } @@ -159,9 +158,10 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) { colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0) vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, float32(width)/float32(w), 0, 0, float32(height)/float32(h), - float32(x), float32(y)) + float32(x), float32(y), + colorm) is := graphicsutil.QuadIndices() - i.image.DrawImage(dummyImage.image, vs, is, colorm, opengl.CompositeModeCopy, graphics.FilterNearest) + i.image.DrawImage(dummyImage.image, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) } if x == 0 && y == 0 && width == w && height == h { @@ -198,7 +198,7 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) { } // DrawImage draws a given image img to the image. -func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter graphics.Filter) { if len(vertices) == 0 { return } @@ -207,13 +207,13 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo if img.stale || img.volatile || i.screen || !IsRestoringEnabled() { i.makeStale() } else { - i.appendDrawImageHistory(img, vertices, indices, colorm, mode, filter) + i.appendDrawImageHistory(img, vertices, indices, mode, filter) } - i.image.DrawImage(img.image, vertices, indices, colorm, mode, filter) + i.image.DrawImage(img.image, vertices, indices, mode, filter) } // appendDrawImageHistory appends a draw-image history item to the image. -func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter graphics.Filter) { if i.stale || i.volatile || i.screen { return } @@ -228,7 +228,6 @@ func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices image: image, vertices: vertices, indices: indices, - colorm: colorm, mode: mode, filter: filter, } @@ -359,7 +358,7 @@ func (i *Image) restore() error { if c.image.hasDependency() { panic("not reached") } - gimg.DrawImage(c.image.image, c.vertices, c.indices, c.colorm, c.mode, c.filter) + gimg.DrawImage(c.image.image, c.vertices, c.indices, c.mode, c.filter) } i.image = gimg diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index 4aefae02c..84ea721e5 100644 --- a/internal/restorable/images_test.go +++ b/internal/restorable/images_test.go @@ -116,9 +116,9 @@ func TestRestoreChain(t *testing.T) { fill(imgs[0], clr.R, clr.G, clr.B, clr.A) for i := 0; i < num-1; i++ { w, h := imgs[i].Size() - vs := graphicsutil.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - imgs[i+1].DrawImage(imgs[i], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[i+1].DrawImage(imgs[i], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) } ResolveStaleImages() if err := Restore(); err != nil { @@ -158,12 +158,12 @@ func TestRestoreChain2(t *testing.T) { clr8 := color.RGBA{0x00, 0x00, 0xff, 0xff} fill(imgs[8], clr8.R, clr8.G, clr8.B, clr8.A) - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - imgs[8].DrawImage(imgs[7], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) - imgs[9].DrawImage(imgs[8], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[8].DrawImage(imgs[7], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[9].DrawImage(imgs[8], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) for i := 0; i < 7; i++ { - imgs[i+1].DrawImage(imgs[i], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[i+1].DrawImage(imgs[i], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) } ResolveStaleImages() @@ -204,12 +204,12 @@ func TestRestoreOverrideSource(t *testing.T) { clr0 := color.RGBA{0x00, 0x00, 0x00, 0xff} clr1 := color.RGBA{0x00, 0x00, 0x01, 0xff} fill(img1, clr0.R, clr0.G, clr0.B, clr0.A) - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img2.DrawImage(img1, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - img3.DrawImage(img2, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img2.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img3.DrawImage(img2, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) fill(img0, clr1.R, clr1.G, clr1.B, clr1.A) - img1.DrawImage(img0, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) ResolveStaleImages() if err := Restore(); err != nil { t.Fatal(err) @@ -289,25 +289,25 @@ func TestRestoreComplexGraph(t *testing.T) { img1.Dispose() img0.Dispose() }() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img3.DrawImage(img0, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) - img3.DrawImage(img1, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) - img4.DrawImage(img1, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0) - img4.DrawImage(img2, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) - img5.DrawImage(img3, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) - img6.DrawImage(img3, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) - img6.DrawImage(img4, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) - img7.DrawImage(img2, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0) - img7.DrawImage(img3, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img3.DrawImage(img0, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, nil) + img3.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, nil) + img4.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, nil) + img4.DrawImage(img2, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) + img5.DrawImage(img3, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) + img6.DrawImage(img3, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, nil) + img6.DrawImage(img4, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) + img7.DrawImage(img2, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + vs = graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 2, 0, nil) + img7.DrawImage(img3, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) ResolveStaleImages() if err := Restore(); err != nil { t.Fatal(err) @@ -397,10 +397,10 @@ func TestRestoreRecursive(t *testing.T) { img1.Dispose() img0.Dispose() }() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0, nil) is := graphicsutil.QuadIndices() - img1.DrawImage(img0, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) - img0.DrawImage(img1, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) ResolveStaleImages() if err := Restore(); err != nil { t.Fatal(err) @@ -485,9 +485,9 @@ func TestDrawImageAndReplacePixels(t *testing.T) { img1 := NewImage(2, 1, false) defer img1.Dispose() - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img1.DrawImage(img0, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) img1.ReplacePixels([]byte{0xff, 0xff, 0xff, 0xff}, 1, 0, 1, 1) ResolveStaleImages() @@ -517,10 +517,10 @@ func TestDispose(t *testing.T) { img2 := newImageFromImage(base2) defer img2.Dispose() - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img1.DrawImage(img2, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) - img0.DrawImage(img1, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) img1.Dispose() ResolveStaleImages() @@ -545,9 +545,9 @@ func TestDoubleResolve(t *testing.T) { base.Pix[3] = 0xff img1 := newImageFromImage(base) - vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img0.DrawImage(img1, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) img0.ReplacePixels([]uint8{0x00, 0xff, 0x00, 0xff}, 1, 1, 1, 1) // Now img0 is stale. ResolveStaleImages() diff --git a/internal/shareable/shareable.go b/internal/shareable/shareable.go index 6a0156f6a..c62a939ee 100644 --- a/internal/shareable/shareable.go +++ b/internal/shareable/shareable.go @@ -63,9 +63,9 @@ func (b *backend) TryAlloc(width, height int) (*packing.Node, bool) { newImg := restorable.NewImage(s, s, false) oldImg := b.restorable w, h := oldImg.Size() - vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - newImg.DrawImage(oldImg, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + newImg.DrawImage(oldImg, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) oldImg.Dispose() b.restorable = newImg @@ -129,9 +129,9 @@ func (i *Image) ensureNotShared() { x, y, w, h := i.region() newImg := restorable.NewImage(w, h, false) vw, vh := i.backend.restorable.Size() - vs := graphicsutil.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0) + vs := graphicsutil.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - newImg.DrawImage(i.backend.restorable, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + newImg.DrawImage(i.backend.restorable, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) i.dispose(false) i.backend = &backend{ @@ -184,18 +184,18 @@ func (i *Image) Size() (width, height int) { return i.width, i.height } -func (i *Image) QuadVertices(sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32) []float32 { +func (i *Image) QuadVertices(sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32, colorm *affine.ColorM) []float32 { if i.backend == nil { i.allocate(true) } dx, dy, _, _ := i.region() w, h := i.backend.restorable.SizePowerOf2() - return graphicsutil.QuadVertices(w, h, sx0+dx, sy0+dy, sx1+dx, sy1+dy, a, b, c, d, tx, ty) + return graphicsutil.QuadVertices(w, h, sx0+dx, sy0+dy, sx1+dx, sy1+dy, a, b, c, d, tx, ty, colorm) } const MaxCountForShare = 10 -func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter graphics.Filter) { backendsM.Lock() defer backendsM.Unlock() @@ -217,7 +217,7 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colo panic("shareable: Image.DrawImage: img must be different from the receiver") } - i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, colorm, mode, filter) + i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, mode, filter) i.countForShare = 0 if !img.isShared() && img.shareable() { diff --git a/internal/shareable/shareable_test.go b/internal/shareable/shareable_test.go index 6bf4503f6..e05813e15 100644 --- a/internal/shareable/shareable_test.go +++ b/internal/shareable/shareable_test.go @@ -86,9 +86,9 @@ func TestEnsureNotShared(t *testing.T) { dy1 = size * 3 / 4 ) // img4.ensureNotShared() should be called. - vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4) + vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4, nil) is := graphicsutil.QuadIndices() - img4.DrawImage(img3, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) want := false if got := img4.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want) @@ -110,7 +110,7 @@ func TestEnsureNotShared(t *testing.T) { // Check further drawing doesn't cause panic. // This bug was fixed by 03dcd948. - img4.DrawImage(img3, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) } func TestReshared(t *testing.T) { @@ -150,9 +150,9 @@ func TestReshared(t *testing.T) { } // Use img1 as a render target. - vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0) + vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0, nil) is := graphicsutil.QuadIndices() - img1.DrawImage(img2, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) want = false if got := img1.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want) @@ -160,7 +160,7 @@ func TestReshared(t *testing.T) { // Use img1 as a render source. for i := 0; i < MaxCountForShare-1; i++ { - img0.DrawImage(img1, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) want := false if got := img1.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want) @@ -177,7 +177,7 @@ func TestReshared(t *testing.T) { } } - img0.DrawImage(img1, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) want = true if got := img1.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want) @@ -195,7 +195,7 @@ func TestReshared(t *testing.T) { // Use img3 as a render source. img3 never uses a shared texture. for i := 0; i < MaxCountForShare*2; i++ { - img0.DrawImage(img3, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) want := false if got := img3.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want)