diff --git a/image.go b/image.go index 311eabf85..b0464343f 100644 --- a/image.go +++ b/image.go @@ -297,9 +297,9 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { } else { s = shareable.NewImage(w2, h2) } - vs := src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0, nil) + vs := src.QuadVertices(0, 0, w, h, 0.5, 0, 0, 0.5, 0, 0) is := graphicsutil.QuadIndices() - s.DrawImage(src, vs, is, opengl.CompositeModeCopy, graphics.FilterLinear) + s.DrawImage(src, vs, is, options.ColorM.impl, opengl.CompositeModeCopy, graphics.FilterLinear) img.shareableImages = append(img.shareableImages, s) w = w2 h = h2 @@ -307,9 +307,9 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error { if level < len(img.shareableImages) { src := img.shareableImages[level] - vs := src.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, options.ColorM.impl) + vs := src.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty) is := graphicsutil.QuadIndices() - i.shareableImages[0].DrawImage(src, vs, is, mode, filter) + i.shareableImages[0].DrawImage(src, vs, is, options.ColorM.impl, mode, filter) } i.disposeMipmaps() return nil diff --git a/internal/affine/colorm.go b/internal/affine/colorm.go index 460b7a675..81d506d74 100644 --- a/internal/affine/colorm.go +++ b/internal/affine/colorm.go @@ -139,6 +139,48 @@ 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 eaceab81a..8ad670462 100644 --- a/internal/graphics/command.go +++ b/internal/graphics/command.go @@ -17,6 +17,7 @@ package graphics import ( "fmt" + "github.com/hajimehoshi/ebiten/internal/affine" emath "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -33,7 +34,7 @@ type command interface { NumIndices() int AddNumVertices(n int) AddNumIndices(n int) - CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool + CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool } // commandQueue is a command queue for drawing commands. @@ -85,12 +86,12 @@ func (q *commandQueue) appendIndices(indices []uint16, offset uint16) { q.nindices += len(indices) } -func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, mode opengl.CompositeMode, filter Filter, forceNewCommand bool) { +func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nindices int, color *affine.ColorM, 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, mode, filter) { + if last := q.commands[len(q.commands)-1]; last.CanMerge(dst, src, color, mode, filter) { last.AddNumVertices(nvertices) last.AddNumIndices(nindices) return @@ -101,6 +102,7 @@ func (q *commandQueue) doEnqueueDrawImageCommand(dst, src *Image, nvertices, nin src: src, nvertices: nvertices, nindices: nindices, + color: color, mode: mode, filter: filter, } @@ -108,7 +110,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, mode opengl.CompositeMode, filter Filter) { +func (q *commandQueue) EnqueueDrawImageCommand(dst, src *Image, vertices []float32, indices []uint16, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) { if len(indices) > indicesNum { panic("not reached") } @@ -125,7 +127,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), mode, filter, split) + q.doEnqueueDrawImageCommand(dst, src, len(vertices), len(indices), color, mode, filter, split) } // Enqueue enqueues a drawing command other than a draw-image command. @@ -209,6 +211,7 @@ type drawImageCommand struct { src *Image nvertices int nindices int + color *affine.ColorM mode opengl.CompositeMode filter Filter } @@ -232,7 +235,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.filter) + theOpenGLState.useProgram(proj, c.src.texture.native, c.dst, c.src, c.color, c.filter) opengl.GetContext().DrawElements(opengl.Triangles, c.nindices, indexOffsetInBytes) // glFlush() might be necessary at least on MacBook Pro (a smilar problem at #419), @@ -260,13 +263,16 @@ 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, mode opengl.CompositeMode, filter Filter) bool { +func (c *drawImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, 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 } @@ -310,7 +316,7 @@ func (c *replacePixelsCommand) AddNumVertices(n int) { func (c *replacePixelsCommand) AddNumIndices(n int) { } -func (c *replacePixelsCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { +func (c *replacePixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -347,7 +353,7 @@ func (c *pixelsCommand) AddNumVertices(n int) { func (c *pixelsCommand) AddNumIndices(n int) { } -func (c *pixelsCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { +func (c *pixelsCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -382,7 +388,7 @@ func (c *disposeCommand) AddNumVertices(n int) { func (c *disposeCommand) AddNumIndices(n int) { } -func (c *disposeCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { +func (c *disposeCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -438,7 +444,7 @@ func (c *newImageCommand) AddNumVertices(n int) { func (c *newImageCommand) AddNumIndices(n int) { } -func (c *newImageCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { +func (c *newImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { return false } @@ -473,6 +479,6 @@ func (c *newScreenFramebufferImageCommand) AddNumVertices(n int) { func (c *newScreenFramebufferImageCommand) AddNumIndices(n int) { } -func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, mode opengl.CompositeMode, filter Filter) bool { +func (c *newScreenFramebufferImageCommand) CanMerge(dst, src *Image, color *affine.ColorM, mode opengl.CompositeMode, filter Filter) bool { return false } diff --git a/internal/graphics/image.go b/internal/graphics/image.go index 00ba9cc66..5f5bdefe9 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -15,6 +15,7 @@ package graphics import ( + "github.com/hajimehoshi/ebiten/internal/affine" "github.com/hajimehoshi/ebiten/internal/math" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -85,8 +86,8 @@ func (i *Image) Size() (int, int) { return i.width, i.height } -func (i *Image) DrawImage(src *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter Filter) { - theCommandQueue.EnqueueDrawImageCommand(i, src, vertices, indices, mode, filter) +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) } // Pixels returns the image's pixels. diff --git a/internal/graphics/program.go b/internal/graphics/program.go index 9008c8628..330d2c5e6 100644 --- a/internal/graphics/program.go +++ b/internal/graphics/program.go @@ -17,6 +17,7 @@ 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" @@ -93,31 +94,6 @@ 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, - }, }, } ) @@ -138,10 +114,12 @@ type openGLState struct { programScreen opengl.Program - lastProgram opengl.Program - lastProjectionMatrix []float32 - lastSourceWidth int - lastSourceHeight int + lastProgram opengl.Program + lastProjectionMatrix []float32 + lastColorMatrix []float32 + lastColorMatrixTranslation []float32 + lastSourceWidth int + lastSourceHeight int } var ( @@ -171,6 +149,8 @@ func (s *openGLState) reset() error { s.lastProgram = zeroProgram s.lastProjectionMatrix = nil + s.lastColorMatrix = nil + s.lastColorMatrixTranslation = nil s.lastSourceWidth = 0 s.lastSourceHeight = 0 @@ -270,7 +250,7 @@ func areSameFloat32Array(a, b []float32) bool { } // useProgram uses the program (programTexture). -func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, src *Image, filter Filter) { +func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, dst, src *Image, colorM *affine.ColorM, filter Filter) { c := opengl.GetContext() var program opengl.Program @@ -300,6 +280,8 @@ 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 } @@ -314,6 +296,25 @@ 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 0580a63f8..2fd0efa4a 100644 --- a/internal/graphics/shader.go +++ b/internal/graphics/shader.go @@ -50,24 +50,15 @@ 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 = ` @@ -82,6 +73,8 @@ precision mediump float; {{Definitions}} uniform sampler2D texture; +uniform mat4 color_matrix_body; +uniform vec4 color_matrix_translation; uniform highp vec2 source_size; @@ -92,8 +85,6 @@ 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; @@ -157,7 +148,7 @@ void main(void) { color.rgb /= color.a; } // Apply the color matrix - color = (varying_color_body * color) + varying_color_translate; + color = (color_matrix_body * color) + color_matrix_translation; 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 5cadc446f..9eb8e5744 100644 --- a/internal/graphicsutil/vertices.go +++ b/internal/graphicsutil/vertices.go @@ -15,7 +15,6 @@ package graphicsutil import ( - "github.com/hajimehoshi/ebiten/internal/affine" "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/opengl" ) @@ -48,7 +47,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, colorm *affine.ColorM) []float32 { +func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32) []float32 { if !isPowerOf2(width) { panic("not reached") } @@ -66,16 +65,15 @@ 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, colorm) + return quadVerticesImpl(float32(sx1-sx0), float32(sy1-sy0), u0, v0, u1, v1, a, b, c, d, tx, ty) } -func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32, colorm *affine.ColorM) []float32 { +func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32) []float32 { // Specifying a range explicitly here is redundant but this helps optimization // to eliminate boundry checks. - vs := theVerticesBackend.sliceForOneQuad()[0:104] + vs := theVerticesBackend.sliceForOneQuad()[0:24] ax, by, cx, dy := a*x, b*y, c*x, d*y - cbody, ctranslate := colorm.UnsafeElements() // Vertex coordinates vs[0] = tx @@ -90,40 +88,26 @@ func quadVerticesImpl(x, y, u0, v0, u1, v1, a, b, c, d, tx, ty float32, colorm * vs[5] = v1 // and the same for the other three coordinates - vs[26] = ax + tx - vs[27] = cx + ty - vs[28] = u1 - vs[29] = v0 - vs[30] = u0 - vs[31] = v1 + vs[6] = ax + tx + vs[7] = cx + ty + vs[8] = u1 + vs[9] = v0 + vs[10] = u0 + vs[11] = v1 - vs[52] = by + tx - vs[53] = dy + ty - vs[54] = u0 - vs[55] = v1 - vs[56] = u1 - vs[57] = v0 + vs[12] = by + tx + vs[13] = dy + ty + vs[14] = u0 + vs[15] = v1 + vs[16] = u1 + vs[17] = 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] - } + vs[18] = ax + by + tx + vs[19] = cx + dy + ty + vs[20] = u1 + vs[21] = v1 + vs[22] = u0 + vs[23] = v0 return vs } diff --git a/internal/restorable/image.go b/internal/restorable/image.go index 917b1a519..c74e1837a 100644 --- a/internal/restorable/image.go +++ b/internal/restorable/image.go @@ -31,6 +31,7 @@ type drawImageHistoryItem struct { image *Image vertices []float32 indices []uint16 + colorm *affine.ColorM mode opengl.CompositeMode filter graphics.Filter } @@ -162,10 +163,9 @@ 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), - colorm) + float32(x), float32(y)) is := graphicsutil.QuadIndices() - i.image.DrawImage(dummyImage.image, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + i.image.DrawImage(dummyImage.image, vs, is, colorm, opengl.CompositeModeCopy, graphics.FilterNearest) } if x == 0 && y == 0 && width == w && height == h { @@ -202,7 +202,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, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { if len(vertices) == 0 { return } @@ -211,13 +211,13 @@ func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, mode if img.stale || img.volatile || i.screen || !IsRestoringEnabled() { i.makeStale() } else { - i.appendDrawImageHistory(img, vertices, indices, mode, filter) + i.appendDrawImageHistory(img, vertices, indices, colorm, mode, filter) } - i.image.DrawImage(img.image, vertices, indices, mode, filter) + i.image.DrawImage(img.image, vertices, indices, colorm, mode, filter) } // appendDrawImageHistory appends a draw-image history item to the image. -func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, mode opengl.CompositeMode, filter graphics.Filter) { if i.stale || i.volatile || i.screen { return } @@ -232,6 +232,7 @@ func (i *Image) appendDrawImageHistory(image *Image, vertices []float32, indices image: image, vertices: vertices, indices: indices, + colorm: colorm, mode: mode, filter: filter, } @@ -362,7 +363,7 @@ func (i *Image) restore() error { if c.image.hasDependency() { panic("not reached") } - gimg.DrawImage(c.image.image, c.vertices, c.indices, c.mode, c.filter) + gimg.DrawImage(c.image.image, c.vertices, c.indices, c.colorm, c.mode, c.filter) } i.image = gimg diff --git a/internal/restorable/images_test.go b/internal/restorable/images_test.go index 84ea721e5..4aefae02c 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - imgs[i+1].DrawImage(imgs[i], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[i+1].DrawImage(imgs[i], vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - imgs[8].DrawImage(imgs[7], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) - imgs[9].DrawImage(imgs[8], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[8].DrawImage(imgs[7], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[9].DrawImage(imgs[8], vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) for i := 0; i < 7; i++ { - imgs[i+1].DrawImage(imgs[i], vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + imgs[i+1].DrawImage(imgs[i], vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - img2.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) - img3.DrawImage(img2, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img2.DrawImage(img1, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img3.DrawImage(img2, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) fill(img0, clr1.R, clr1.G, clr1.B, clr1.A) - img1.DrawImage(img0, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - 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) + 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) 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 1, 0) is := graphicsutil.QuadIndices() - img1.DrawImage(img0, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) - img0.DrawImage(img1, vs, is, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, nil, opengl.CompositeModeSourceOver, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - img1.DrawImage(img0, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img0, vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) - img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img2, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - img0.DrawImage(img1, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, nil, 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 cebb8c07a..02766d36b 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, nil) + vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - newImg.DrawImage(oldImg, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + newImg.DrawImage(oldImg, vs, is, nil, 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, nil) + vs := graphicsutil.QuadVertices(vw, vh, x, y, x+w, y+h, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - newImg.DrawImage(i.backend.restorable, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + newImg.DrawImage(i.backend.restorable, vs, is, nil, 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, colorm *affine.ColorM) []float32 { +func (i *Image) QuadVertices(sx0, sy0, sx1, sy1 int, a, b, c, d, tx, ty float32) []float32 { if i.backend == nil { i.allocate(true) } ox, oy, _, _ := i.region() w, h := i.backend.restorable.SizePowerOf2() - return graphicsutil.QuadVertices(w, h, sx0+ox, sy0+oy, sx1+ox, sy1+oy, a, b, c, d, tx, ty, colorm) + return graphicsutil.QuadVertices(w, h, sx0+ox, sy0+oy, sx1+ox, sy1+oy, a, b, c, d, tx, ty) } const MaxCountForShare = 10 -func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, mode opengl.CompositeMode, filter graphics.Filter) { +func (i *Image) DrawImage(img *Image, vertices []float32, indices []uint16, colorm *affine.ColorM, 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, mode panic("shareable: Image.DrawImage: img must be different from the receiver") } - i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, mode, filter) + i.backend.restorable.DrawImage(img.backend.restorable, vertices, indices, colorm, 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 b39c99116..6b5abd157 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, nil) + vs := img3.QuadVertices(0, 0, size/2, size/2, 1, 0, 0, 1, size/4, size/4) is := graphicsutil.QuadIndices() - img4.DrawImage(img3, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, vs, is, nil, 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, opengl.CompositeModeCopy, graphics.FilterNearest) + img4.DrawImage(img3, vs, is, nil, 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, nil) + vs := img2.QuadVertices(0, 0, size, size, 1, 0, 0, 1, 0, 0) is := graphicsutil.QuadIndices() - img1.DrawImage(img2, vs, is, opengl.CompositeModeCopy, graphics.FilterNearest) + img1.DrawImage(img2, vs, is, nil, 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, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, nil, 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, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img1, vs, is, nil, 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, opengl.CompositeModeCopy, graphics.FilterNearest) + img0.DrawImage(img3, vs, is, nil, opengl.CompositeModeCopy, graphics.FilterNearest) want := false if got := img3.IsSharedForTesting(); got != want { t.Errorf("got: %v, want: %v", got, want)