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.
// This is same as muptiplying the matrix other and the matrix c in this order.
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.

20
geom.go
View File

@ -30,13 +30,29 @@ type GeoM struct {
// Element returns a value of a matrix at (i, j).
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.
// This is same as muptiplying the matrix other and the matrix g in this order.
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.

View File

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

View File

@ -21,105 +21,138 @@ import (
// GeoMDim is a dimension of a GeoM.
const GeoMDim = 3
var (
geoMIdentityElements = []float64{
1, 0, 0,
0, 1, 0,
}
)
// A GeoM represents a matrix to transform geometry when rendering an image.
//
// The initial value is identity.
type GeoM struct {
// When elements is empty, this matrix is identity.
// elements is immutable and a new array must be created when updating.
elements []float64
a float64
b float64
c float64
d float64
tx float64
ty float64
inited bool
}
func (g *GeoM) UnsafeElements() []float64 {
if g.elements == nil {
g.elements = geoMIdentityElements
func (g *GeoM) Elements() (a, b, c, d, tx, ty float64) {
if !g.inited {
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).
func (g *GeoM) SetElement(i, j int, element float64) {
if g.elements == nil {
g.elements = geoMIdentityElements
if !g.inited {
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.
// This is same as muptiplying the matrix other and the matrix g in this order.
func (g *GeoM) Concat(other GeoM) {
if g.elements == nil {
g.elements = geoMIdentityElements
func (g *GeoM) Concat(other *GeoM) {
if !g.inited {
g.init()
}
if other.elements == nil {
other.elements = geoMIdentityElements
if !other.inited {
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.
func (g *GeoM) Add(other GeoM) {
if g.elements == nil {
g.elements = geoMIdentityElements
if !g.inited {
g.init()
}
if other.elements == nil {
other.elements = geoMIdentityElements
if !other.inited {
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).
func (g *GeoM) Scale(x, y float64) {
if g.elements == nil {
g.elements = []float64{
x, 0, 0,
0, y, 0,
}
if !g.inited {
g.a = x
g.b = 0
g.c = 0
g.d = y
g.tx = 0
g.ty = 0
g.inited = true
return
}
es := make([]float64, len(g.elements))
copy(es, g.elements)
for i := 0; i < GeoMDim; i++ {
es[i] *= x
es[i+GeoMDim] *= y
}
g.elements = es
g.a *= x
g.b *= x
g.tx *= x
g.c *= y
g.d *= y
g.ty *= y
}
// Translate translates the matrix by (x, y).
func (g *GeoM) Translate(tx, ty float64) {
if g.elements == nil {
g.elements = []float64{
1, 0, tx,
0, 1, ty,
}
if !g.inited {
g.a = 1
g.b = 0
g.c = 0
g.d = 1
g.tx = tx
g.ty = ty
g.inited = true
return
}
es := make([]float64, len(g.elements))
copy(es, g.elements)
es[2] += tx
es[2+GeoMDim] += ty
g.elements = es
g.tx += tx
g.ty += ty
}
// Rotate rotates the matrix by theta.
func (g *GeoM) Rotate(theta float64) {
sin, cos := math.Sincos(theta)
g.Concat(GeoM{
elements: []float64{
cos, -sin, 0,
sin, cos, 0,
},
g.Concat(&GeoM{
a: cos,
b: -sin,
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?
l := parts.Len()
vs := make([]float32, l*quadFloat32Num)
g := geo.UnsafeElements()
g0 := float32(g[0])
g1 := float32(g[1])
g2 := float32(g[3])
g3 := float32(g[4])
g4 := float32(g[2])
g5 := float32(g[5])
a, b, c, d, tx, ty := geo.Elements()
g0 := float32(a)
g1 := float32(b)
g2 := float32(c)
g3 := float32(d)
g4 := float32(tx)
g5 := float32(ty)
w := 1
h := 1
for w < width {