mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
affine: Use float32 values for GeoM
float32 was slow on GopherJS, but not slow on Wasm.
This commit is contained in:
parent
4c2fc30311
commit
95561bbf6b
77
geom.go
77
geom.go
@ -26,12 +26,12 @@ const GeoMDim = 3
|
|||||||
//
|
//
|
||||||
// The initial value is identity.
|
// The initial value is identity.
|
||||||
type GeoM struct {
|
type GeoM struct {
|
||||||
a_1 float64 // The actual 'a' value minus 1
|
a_1 float32 // The actual 'a' value minus 1
|
||||||
b float64
|
b float32
|
||||||
c float64
|
c float32
|
||||||
d_1 float64 // The actual 'd' value minus 1
|
d_1 float32 // The actual 'd' value minus 1
|
||||||
tx float64
|
tx float32
|
||||||
ty float64
|
ty float32
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string representation of GeoM.
|
// String returns a string representation of GeoM.
|
||||||
@ -52,7 +52,12 @@ func (g *GeoM) Reset() {
|
|||||||
// Apply pre-multiplies a vector (x, y, 1) by the matrix.
|
// Apply pre-multiplies a vector (x, y, 1) by the matrix.
|
||||||
// In other words, Apply calculates GeoM * (x, y, 1)^T.
|
// In other words, Apply calculates GeoM * (x, y, 1)^T.
|
||||||
// The return value is x and y values of the result vector.
|
// The return value is x and y values of the result vector.
|
||||||
func (g *GeoM) Apply(x, y float64) (x2, y2 float64) {
|
func (g *GeoM) Apply(x, y float64) (float64, float64) {
|
||||||
|
x2, y2 := g.apply32(float32(x), float32(y))
|
||||||
|
return float64(x2), float64(y2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *GeoM) apply32(x, y float32) (x2, y2 float32) {
|
||||||
return (g.a_1+1)*x + g.b*y + g.tx, g.c*x + (g.d_1+1)*y + g.ty
|
return (g.a_1+1)*x + g.b*y + g.tx, g.c*x + (g.d_1+1)*y + g.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,17 +65,17 @@ func (g *GeoM) Apply(x, y float64) (x2, y2 float64) {
|
|||||||
func (g *GeoM) Element(i, j int) float64 {
|
func (g *GeoM) Element(i, j int) float64 {
|
||||||
switch {
|
switch {
|
||||||
case i == 0 && j == 0:
|
case i == 0 && j == 0:
|
||||||
return g.a_1 + 1
|
return float64(g.a_1) + 1
|
||||||
case i == 0 && j == 1:
|
case i == 0 && j == 1:
|
||||||
return g.b
|
return float64(g.b)
|
||||||
case i == 0 && j == 2:
|
case i == 0 && j == 2:
|
||||||
return g.tx
|
return float64(g.tx)
|
||||||
case i == 1 && j == 0:
|
case i == 1 && j == 0:
|
||||||
return g.c
|
return float64(g.c)
|
||||||
case i == 1 && j == 1:
|
case i == 1 && j == 1:
|
||||||
return g.d_1 + 1
|
return float64(g.d_1) + 1
|
||||||
case i == 1 && j == 2:
|
case i == 1 && j == 2:
|
||||||
return g.ty
|
return float64(g.ty)
|
||||||
default:
|
default:
|
||||||
panic("ebiten: i or j is out of index")
|
panic("ebiten: i or j is out of index")
|
||||||
}
|
}
|
||||||
@ -107,31 +112,32 @@ func (g *GeoM) Add(other GeoM) {
|
|||||||
|
|
||||||
// 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) {
|
||||||
a := (g.a_1 + 1) * x
|
a := (float64(g.a_1) + 1) * x
|
||||||
b := g.b * x
|
b := float64(g.b) * x
|
||||||
tx := g.tx * x
|
tx := float64(g.tx) * x
|
||||||
c := g.c * y
|
c := float64(g.c) * y
|
||||||
d := (g.d_1 + 1) * y
|
d := (float64(g.d_1) + 1) * y
|
||||||
ty := g.ty * y
|
ty := float64(g.ty) * y
|
||||||
|
|
||||||
g.a_1 = a - 1
|
g.a_1 = float32(a) - 1
|
||||||
g.b = b
|
g.b = float32(b)
|
||||||
g.c = c
|
g.c = float32(c)
|
||||||
g.d_1 = d - 1
|
g.d_1 = float32(d) - 1
|
||||||
g.tx = tx
|
g.tx = float32(tx)
|
||||||
g.ty = ty
|
g.ty = float32(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate translates the matrix by (tx, ty).
|
// Translate translates the matrix by (tx, ty).
|
||||||
func (g *GeoM) Translate(tx, ty float64) {
|
func (g *GeoM) Translate(tx, ty float64) {
|
||||||
g.tx += tx
|
g.tx += float32(tx)
|
||||||
g.ty += ty
|
g.ty += float32(ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotate rotates the matrix by theta.
|
// Rotate rotates the matrix by theta.
|
||||||
// The unit is radian.
|
// The unit is radian.
|
||||||
func (g *GeoM) Rotate(theta float64) {
|
func (g *GeoM) Rotate(theta float64) {
|
||||||
sin, cos := math.Sincos(theta)
|
sin64, cos64 := math.Sincos(theta)
|
||||||
|
sin, cos := float32(sin64), float32(cos64)
|
||||||
|
|
||||||
a := cos*(g.a_1+1) - sin*g.c
|
a := cos*(g.a_1+1) - sin*g.c
|
||||||
b := cos*g.b - sin*(g.d_1+1)
|
b := cos*g.b - sin*(g.d_1+1)
|
||||||
@ -148,7 +154,7 @@ func (g *GeoM) Rotate(theta float64) {
|
|||||||
g.ty = ty
|
g.ty = ty
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GeoM) det() float64 {
|
func (g *GeoM) det() float32 {
|
||||||
return (g.a_1+1)*(g.d_1+1) - g.b*g.c
|
return (g.a_1+1)*(g.d_1+1) - g.b*g.c
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,19 +189,20 @@ func (g *GeoM) Invert() {
|
|||||||
|
|
||||||
// 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) {
|
||||||
|
e := float32(element)
|
||||||
switch {
|
switch {
|
||||||
case i == 0 && j == 0:
|
case i == 0 && j == 0:
|
||||||
g.a_1 = element - 1
|
g.a_1 = e - 1
|
||||||
case i == 0 && j == 1:
|
case i == 0 && j == 1:
|
||||||
g.b = element
|
g.b = e
|
||||||
case i == 0 && j == 2:
|
case i == 0 && j == 2:
|
||||||
g.tx = element
|
g.tx = e
|
||||||
case i == 1 && j == 0:
|
case i == 1 && j == 0:
|
||||||
g.c = element
|
g.c = e
|
||||||
case i == 1 && j == 1:
|
case i == 1 && j == 1:
|
||||||
g.d_1 = element - 1
|
g.d_1 = e - 1
|
||||||
case i == 1 && j == 2:
|
case i == 1 && j == 2:
|
||||||
g.ty = element
|
g.ty = e
|
||||||
default:
|
default:
|
||||||
panic("ebiten: i or j is out of index")
|
panic("ebiten: i or j is out of index")
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ func TestGeoMIsInvert(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const delta = 0.00001
|
const delta = 0.001
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
if c.GeoM.IsInvertible() != c.Invertible {
|
if c.GeoM.IsInvertible() != c.Invertible {
|
||||||
|
17
image.go
17
image.go
@ -126,6 +126,14 @@ func (i *Image) fill(r, g, b, a uint8) {
|
|||||||
_ = i.DrawImage(emptyImage, op)
|
_ = i.DrawImage(emptyImage, op)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type geoM32 struct {
|
||||||
|
inner *GeoM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g geoM32) Apply(x, y float32) (x2, y2 float32) {
|
||||||
|
return g.inner.apply32(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
// DrawImage draws the given image on the image i.
|
// DrawImage draws the given image on the image i.
|
||||||
//
|
//
|
||||||
// DrawImage accepts the options. For details, see the document of DrawImageOptions.
|
// DrawImage accepts the options. For details, see the document of DrawImageOptions.
|
||||||
@ -211,7 +219,7 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
|
|||||||
sy1 = r.Max.Y
|
sy1 = r.Max.Y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
geom := &options.GeoM
|
geom := geoM32{&options.GeoM}
|
||||||
if sx0 < 0 || sy0 < 0 {
|
if sx0 < 0 || sy0 < 0 {
|
||||||
dx := 0.0
|
dx := 0.0
|
||||||
dy := 0.0
|
dy := 0.0
|
||||||
@ -223,9 +231,10 @@ func (i *Image) DrawImage(img *Image, options *DrawImageOptions) error {
|
|||||||
dy = -float64(sy0)
|
dy = -float64(sy0)
|
||||||
sy0 = 0
|
sy0 = 0
|
||||||
}
|
}
|
||||||
geom = &GeoM{}
|
g := &GeoM{}
|
||||||
geom.Translate(dx, dy)
|
g.Translate(dx, dy)
|
||||||
geom.Concat(options.GeoM)
|
g.Concat(options.GeoM)
|
||||||
|
geom = geoM32{g}
|
||||||
}
|
}
|
||||||
|
|
||||||
mode := opengl.CompositeMode(options.CompositeMode)
|
mode := opengl.CompositeMode(options.CompositeMode)
|
||||||
|
@ -44,7 +44,7 @@ func (v *verticesBackend) sliceForOneQuad() []float32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GeoM interface {
|
type GeoM interface {
|
||||||
Apply(x, y float64) (x2, y2 float64)
|
Apply(x, y float32) (x2, y2 float32)
|
||||||
}
|
}
|
||||||
|
|
||||||
func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float32 {
|
func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float32 {
|
||||||
@ -57,8 +57,8 @@ func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float3
|
|||||||
|
|
||||||
vs := theVerticesBackend.sliceForOneQuad()
|
vs := theVerticesBackend.sliceForOneQuad()
|
||||||
|
|
||||||
x0, y0 := 0.0, 0.0
|
x0, y0 := float32(0.0), float32(0.0)
|
||||||
x1, y1 := float64(sx1-sx0), float64(sy1-sy0)
|
x1, y1 := float32(sx1-sx0), float32(sy1-sy0)
|
||||||
|
|
||||||
// it really feels like we should be able to cache this computation
|
// it really feels like we should be able to cache this computation
|
||||||
// but it may not matter.
|
// but it may not matter.
|
||||||
@ -73,11 +73,15 @@ func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float3
|
|||||||
wf := float32(w)
|
wf := float32(w)
|
||||||
hf := float32(h)
|
hf := float32(h)
|
||||||
u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
|
u0, v0, u1, v1 := float32(sx0)/wf, float32(sy0)/hf, float32(sx1)/wf, float32(sy1)/hf
|
||||||
|
quadVerticesImpl(vs, wf, hf, u0, v0, u1, v1, x0, y0, x1, y1, geom)
|
||||||
|
return vs
|
||||||
|
}
|
||||||
|
|
||||||
|
func quadVerticesImpl(vs []float32, wf, hf, u0, v0, u1, v1, x0, y0, x1, y1 float32, geom GeoM) {
|
||||||
x, y := geom.Apply(x0, y0)
|
x, y := geom.Apply(x0, y0)
|
||||||
// Vertex coordinates
|
// Vertex coordinates
|
||||||
vs[0] = float32(x)
|
vs[0] = x
|
||||||
vs[1] = float32(y)
|
vs[1] = y
|
||||||
|
|
||||||
// Texture coordinates: first 2 values indicates the actual coodinate, and
|
// Texture coordinates: first 2 values indicates the actual coodinate, and
|
||||||
// the second indicates diagonally opposite coodinates.
|
// the second indicates diagonally opposite coodinates.
|
||||||
@ -89,28 +93,26 @@ func QuadVertices(width, height int, sx0, sy0, sx1, sy1 int, geom GeoM) []float3
|
|||||||
|
|
||||||
// and the same for the other three coordinates
|
// and the same for the other three coordinates
|
||||||
x, y = geom.Apply(x1, y0)
|
x, y = geom.Apply(x1, y0)
|
||||||
vs[6] = float32(x)
|
vs[6] = x
|
||||||
vs[7] = float32(y)
|
vs[7] = y
|
||||||
vs[8] = u1
|
vs[8] = u1
|
||||||
vs[9] = v0
|
vs[9] = v0
|
||||||
vs[10] = u0
|
vs[10] = u0
|
||||||
vs[11] = v1
|
vs[11] = v1
|
||||||
|
|
||||||
x, y = geom.Apply(x0, y1)
|
x, y = geom.Apply(x0, y1)
|
||||||
vs[12] = float32(x)
|
vs[12] = x
|
||||||
vs[13] = float32(y)
|
vs[13] = y
|
||||||
vs[14] = u0
|
vs[14] = u0
|
||||||
vs[15] = v1
|
vs[15] = v1
|
||||||
vs[16] = u1
|
vs[16] = u1
|
||||||
vs[17] = v0
|
vs[17] = v0
|
||||||
|
|
||||||
x, y = geom.Apply(x1, y1)
|
x, y = geom.Apply(x1, y1)
|
||||||
vs[18] = float32(x)
|
vs[18] = x
|
||||||
vs[19] = float32(y)
|
vs[19] = y
|
||||||
vs[20] = u1
|
vs[20] = u1
|
||||||
vs[21] = v1
|
vs[21] = v1
|
||||||
vs[22] = u0
|
vs[22] = u0
|
||||||
vs[23] = v0
|
vs[23] = v0
|
||||||
|
|
||||||
return vs
|
|
||||||
}
|
}
|
||||||
|
@ -123,13 +123,13 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type geoM struct {
|
type geoM struct {
|
||||||
scaleX float64
|
scaleX float32
|
||||||
scaleY float64
|
scaleY float32
|
||||||
tx float64
|
tx float32
|
||||||
ty float64
|
ty float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *geoM) Apply(x, y float64) (float64, float64) {
|
func (g *geoM) Apply(x, y float32) (float32, float32) {
|
||||||
return x*g.scaleX + g.tx, y*g.scaleY + g.ty
|
return x*g.scaleX + g.tx, y*g.scaleY + g.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,10 +159,10 @@ func (i *Image) ReplacePixels(pixels []byte, x, y, width, height int) {
|
|||||||
w, h := dummyImage.Size()
|
w, h := dummyImage.Size()
|
||||||
colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0)
|
colorm := (*affine.ColorM)(nil).Scale(0, 0, 0, 0)
|
||||||
vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{
|
vs := graphicsutil.QuadVertices(w, h, 0, 0, w, h, &geoM{
|
||||||
scaleX: float64(width) / float64(w),
|
scaleX: float32(width) / float32(w),
|
||||||
scaleY: float64(height) / float64(h),
|
scaleY: float32(height) / float32(h),
|
||||||
tx: float64(x),
|
tx: float32(x),
|
||||||
ty: float64(y),
|
ty: float32(y),
|
||||||
})
|
})
|
||||||
i.image.DrawImage(dummyImage.image, vs, quadIndices, colorm, opengl.CompositeModeCopy, graphics.FilterNearest)
|
i.image.DrawImage(dummyImage.image, vs, quadIndices, colorm, opengl.CompositeModeCopy, graphics.FilterNearest)
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ var (
|
|||||||
|
|
||||||
type idGeoM struct{}
|
type idGeoM struct{}
|
||||||
|
|
||||||
func (idGeoM) Apply(x, y float64) (x2, y2 float64) {
|
func (idGeoM) Apply(x, y float32) (x2, y2 float32) {
|
||||||
return x, y
|
return x, y
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,11 +263,11 @@ func TestRestoreOverrideSource(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type geoM struct {
|
type geoM struct {
|
||||||
tx float64
|
tx float32
|
||||||
ty float64
|
ty float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *geoM) Apply(x, y float64) (x2, y2 float64) {
|
func (g *geoM) Apply(x, y float32) (x2, y2 float32) {
|
||||||
return x + g.tx, y + g.ty
|
return x + g.tx, y + g.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ type Image struct {
|
|||||||
|
|
||||||
type idGeoM struct{}
|
type idGeoM struct{}
|
||||||
|
|
||||||
func (idGeoM) Apply(x, y float64) (x2, y2 float64) {
|
func (idGeoM) Apply(x, y float32) (x2, y2 float32) {
|
||||||
return x, y
|
return x, y
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,11 +46,11 @@ func TestMain(m *testing.M) {
|
|||||||
const bigSize = 2049
|
const bigSize = 2049
|
||||||
|
|
||||||
type geoM struct {
|
type geoM struct {
|
||||||
tx float64
|
tx float32
|
||||||
ty float64
|
ty float32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *geoM) Apply(x, y float64) (x2, y2 float64) {
|
func (g *geoM) Apply(x, y float32) (x2, y2 float32) {
|
||||||
return x + g.tx, y + g.ty
|
return x + g.tx, y + g.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user