graphics: Optimize GeoM

This commit is contained in:
Hajime Hoshi 2017-05-23 11:30:54 +09:00
parent 06d3eb66c7
commit 6db994f0e8
5 changed files with 121 additions and 72 deletions

View File

@ -36,7 +36,7 @@ type ColorM struct {
// Concat multiplies a color matrix with the other color matrix. // 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. // This is same as muptiplying the matrix other and the matrix c in this order.
func (c *ColorM) Concat(other ColorM) { func (c *ColorM) Concat(other ColorM) {
c.impl.Concat(other.impl) c.impl.Concat(&other.impl)
} }
// Add is deprecated as of 1.5.0-alpha. // Add is deprecated as of 1.5.0-alpha.

20
geom.go
View File

@ -30,13 +30,29 @@ type GeoM struct {
// Element returns a value of a matrix at (i, j). // Element returns a value of a matrix at (i, j).
func (g *GeoM) Element(i, j int) float64 { func (g *GeoM) Element(i, j int) float64 {
return g.impl.UnsafeElements()[i*affine.GeoMDim+j] a, b, c, d, tx, ty := g.impl.Elements()
switch {
case i == 0 && j == 0:
return a
case i == 0 && j == 1:
return b
case i == 0 && j == 2:
return tx
case i == 1 && j == 0:
return c
case i == 1 && j == 1:
return d
case i == 1 && j == 2:
return ty
default:
panic("ebiten: i or j is out of index")
}
} }
// Concat multiplies a geometry matrix with the other geometry matrix. // Concat multiplies a geometry matrix with the other geometry matrix.
// This is same as muptiplying the matrix other and the matrix g in this order. // This is same as muptiplying the matrix other and the matrix g in this order.
func (g *GeoM) Concat(other GeoM) { func (g *GeoM) Concat(other GeoM) {
g.impl.Concat(other.impl) g.impl.Concat(&other.impl)
} }
// Add is deprecated as of 1.5.0-alpha. // Add is deprecated as of 1.5.0-alpha.

View File

@ -82,7 +82,7 @@ func (c *ColorM) Equals(other *ColorM) bool {
// Concat multiplies a color matrix with the other color matrix. // 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. // This is same as muptiplying the matrix other and the matrix c in this order.
func (c *ColorM) Concat(other ColorM) { func (c *ColorM) Concat(other *ColorM) {
if c.elements == nil { if c.elements == nil {
c.elements = colorMIdentityElements c.elements = colorMIdentityElements
} }
@ -182,8 +182,8 @@ var (
// This conversion uses RGB to/from YCrCb conversion. // This conversion uses RGB to/from YCrCb conversion.
func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale float64) { func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale float64) {
sin, cos := math.Sincos(hueTheta) sin, cos := math.Sincos(hueTheta)
c.Concat(rgbToYCbCr) c.Concat(&rgbToYCbCr)
c.Concat(ColorM{ c.Concat(&ColorM{
elements: []float64{ elements: []float64{
1, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, cos, -sin, 0, 0, 0, cos, -sin, 0, 0,
@ -194,7 +194,7 @@ func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale
s := saturationScale s := saturationScale
v := valueScale v := valueScale
c.Scale(v, s*v, s*v, 1) c.Scale(v, s*v, s*v, 1)
c.Concat(yCbCrToRgb) c.Concat(&yCbCrToRgb)
} }
var monochrome ColorM var monochrome ColorM

View File

@ -21,105 +21,138 @@ import (
// GeoMDim is a dimension of a GeoM. // GeoMDim is a dimension of a GeoM.
const GeoMDim = 3 const GeoMDim = 3
var (
geoMIdentityElements = []float64{
1, 0, 0,
0, 1, 0,
}
)
// A GeoM represents a matrix to transform geometry when rendering an image. // A GeoM represents a matrix to transform geometry when rendering an image.
// //
// The initial value is identity. // The initial value is identity.
type GeoM struct { type GeoM struct {
// When elements is empty, this matrix is identity. a float64
// elements is immutable and a new array must be created when updating. b float64
elements []float64 c float64
d float64
tx float64
ty float64
inited bool
} }
func (g *GeoM) UnsafeElements() []float64 { func (g *GeoM) Elements() (a, b, c, d, tx, ty float64) {
if g.elements == nil { if !g.inited {
g.elements = geoMIdentityElements return 1, 0, 0, 1, 0, 0
} }
return g.elements return g.a, g.b, g.c, g.d, g.tx, g.ty
}
func (g *GeoM) init() {
g.a = 1
g.b = 0
g.c = 0
g.d = 1
g.tx = 0
g.ty = 0
g.inited = true
} }
// SetElement sets an element at (i, j). // SetElement sets an element at (i, j).
func (g *GeoM) SetElement(i, j int, element float64) { func (g *GeoM) SetElement(i, j int, element float64) {
if g.elements == nil { if !g.inited {
g.elements = geoMIdentityElements g.init()
}
switch {
case i == 0 && j == 0:
g.a = element
case i == 0 && j == 1:
g.b = element
case i == 0 && j == 2:
g.tx = element
case i == 1 && j == 0:
g.c = element
case i == 1 && j == 1:
g.d = element
case i == 1 && j == 2:
g.ty = element
default:
panic("affine: i or j is out of index")
} }
es := make([]float64, len(g.elements))
copy(es, g.elements)
es[i*GeoMDim+j] = element
g.elements = es
} }
// Concat multiplies a geometry matrix with the other geometry matrix. // Concat multiplies a geometry matrix with the other geometry matrix.
// This is same as muptiplying the matrix other and the matrix g in this order. // This is same as muptiplying the matrix other and the matrix g in this order.
func (g *GeoM) Concat(other GeoM) { func (g *GeoM) Concat(other *GeoM) {
if g.elements == nil { if !g.inited {
g.elements = geoMIdentityElements g.init()
} }
if other.elements == nil { if !other.inited {
other.elements = geoMIdentityElements other.init()
} }
g.elements = mul(other.elements, g.elements, GeoMDim) a, b, c, d, tx, ty := g.a, g.b, g.c, g.d, g.tx, g.ty
g.a = other.a*a + other.b*c
g.b = other.a*b + other.b*d
g.tx = other.a*tx + other.b*ty + other.tx
g.c = other.c*a + other.d*c
g.d = other.c*b + other.d*d
g.ty = other.c*tx + other.d*ty + other.ty
} }
// Add is deprecated. // Add is deprecated.
func (g *GeoM) Add(other GeoM) { func (g *GeoM) Add(other GeoM) {
if g.elements == nil { if !g.inited {
g.elements = geoMIdentityElements g.init()
} }
if other.elements == nil { if !other.inited {
other.elements = geoMIdentityElements other.init()
} }
g.elements = add(other.elements, g.elements, GeoMDim) g.a += other.a
g.b += other.b
g.c += other.c
g.d += other.d
g.tx += other.tx
g.ty += other.ty
} }
// Scale scales the matrix by (x, y). // Scale scales the matrix by (x, y).
func (g *GeoM) Scale(x, y float64) { func (g *GeoM) Scale(x, y float64) {
if g.elements == nil { if !g.inited {
g.elements = []float64{ g.a = x
x, 0, 0, g.b = 0
0, y, 0, g.c = 0
} g.d = y
g.tx = 0
g.ty = 0
g.inited = true
return return
} }
es := make([]float64, len(g.elements)) g.a *= x
copy(es, g.elements) g.b *= x
for i := 0; i < GeoMDim; i++ { g.tx *= x
es[i] *= x g.c *= y
es[i+GeoMDim] *= y g.d *= y
} g.ty *= y
g.elements = es
} }
// Translate translates the matrix by (x, y). // Translate translates the matrix by (x, y).
func (g *GeoM) Translate(tx, ty float64) { func (g *GeoM) Translate(tx, ty float64) {
if g.elements == nil { if !g.inited {
g.elements = []float64{ g.a = 1
1, 0, tx, g.b = 0
0, 1, ty, g.c = 0
} g.d = 1
g.tx = tx
g.ty = ty
g.inited = true
return return
} }
es := make([]float64, len(g.elements)) g.tx += tx
copy(es, g.elements) g.ty += ty
es[2] += tx
es[2+GeoMDim] += ty
g.elements = es
} }
// Rotate rotates the matrix by theta. // Rotate rotates the matrix by theta.
func (g *GeoM) Rotate(theta float64) { func (g *GeoM) Rotate(theta float64) {
sin, cos := math.Sincos(theta) sin, cos := math.Sincos(theta)
g.Concat(GeoM{ g.Concat(&GeoM{
elements: []float64{ a: cos,
cos, -sin, 0, b: -sin,
sin, cos, 0, c: sin,
}, d: cos,
inited: true,
}) })
} }

View File

@ -31,13 +31,13 @@ func vertices(parts ImageParts, width, height int, geo *affine.GeoM) []float32 {
// TODO: This function should be in graphics package? // TODO: This function should be in graphics package?
l := parts.Len() l := parts.Len()
vs := make([]float32, l*quadFloat32Num) vs := make([]float32, l*quadFloat32Num)
g := geo.UnsafeElements() a, b, c, d, tx, ty := geo.Elements()
g0 := float32(g[0]) g0 := float32(a)
g1 := float32(g[1]) g1 := float32(b)
g2 := float32(g[3]) g2 := float32(c)
g3 := float32(g[4]) g3 := float32(d)
g4 := float32(g[2]) g4 := float32(tx)
g5 := float32(g[5]) g5 := float32(ty)
w := 1 w := 1
h := 1 h := 1
for w < width { for w < width {