graphics: Embed color matrices values to vertices (#655)

Fixes #531
This commit is contained in:
Hajime Hoshi 2018-07-26 11:37:27 +09:00 committed by GitHub
parent 8144c9d638
commit 5a9235aaf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 158 additions and 184 deletions

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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.

View File

@ -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)

View File

@ -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;

View File

@ -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
}

View File

@ -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

View File

@ -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()

View File

@ -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() {

View File

@ -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)