mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
graphics: Make copying GeoM faster
This commit is contained in:
parent
3331f17723
commit
9087269212
@ -14,27 +14,46 @@
|
|||||||
|
|
||||||
package affine
|
package affine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hajimehoshi/ebiten/internal/endian"
|
||||||
|
)
|
||||||
|
|
||||||
|
var identityValues = map[int]string{
|
||||||
|
ColorMDim: colorMValueString([ColorMDim - 1][ColorMDim]float64{
|
||||||
|
{1, 0, 0, 0, 0},
|
||||||
|
{0, 1, 0, 0, 0},
|
||||||
|
{0, 0, 1, 0, 0},
|
||||||
|
{0, 0, 0, 1, 0},
|
||||||
|
}),
|
||||||
|
GeoMDim: geoMValueString([GeoMDim - 1][GeoMDim]float64{
|
||||||
|
{1, 0, 0},
|
||||||
|
{0, 1, 0},
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
func uint64ToBytes(value uint64) []uint8 {
|
||||||
|
result := make([]uint8, 8)
|
||||||
|
if endian.IsLittle() {
|
||||||
|
for i := 0; i < 8; i++ {
|
||||||
|
result[i] = uint8(value)
|
||||||
|
value >>= 8
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i := 7; 0 <= i; i-- {
|
||||||
|
result[i] = uint8(value)
|
||||||
|
value >>= 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
type affine interface {
|
type affine interface {
|
||||||
dim() int
|
dim() int
|
||||||
Element(i, j int) float64
|
Element(i, j int) float64
|
||||||
SetElement(i, j int, element float64)
|
SetElement(i, j int, element float64)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIdentity(ebiten affine) bool {
|
// add is deprecated
|
||||||
dim := ebiten.dim()
|
|
||||||
for i := 0; i < dim-1; i++ {
|
|
||||||
for j := 0; j < dim; j++ {
|
|
||||||
element := ebiten.Element(i, j)
|
|
||||||
if i == j && element != 1 {
|
|
||||||
return false
|
|
||||||
} else if i != j && element != 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func add(lhs, rhs, result affine) {
|
func add(lhs, rhs, result affine) {
|
||||||
dim := lhs.dim()
|
dim := lhs.dim()
|
||||||
if dim != rhs.dim() {
|
if dim != rhs.dim() {
|
||||||
|
@ -20,27 +20,25 @@ import (
|
|||||||
"github.com/gopherjs/gopherjs/js"
|
"github.com/gopherjs/gopherjs/js"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Element returns a value of a matrix at (i, j).
|
func element(values string, dim int, i, j int) float64 {
|
||||||
func (c *ColorM) Element(i, j int) float64 {
|
if values == "" {
|
||||||
if c.values == "" {
|
|
||||||
if i == j {
|
if i == j {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
a := js.NewArrayBuffer([]uint8(c.values))
|
a := js.NewArrayBuffer([]uint8(values))
|
||||||
af64 := js.Global.Get("Float64Array").New(a)
|
af64 := js.Global.Get("Float64Array").New(a)
|
||||||
return af64.Index(i*ColorMDim + j).Float()
|
return af64.Index(i*dim + j).Float()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetElement sets an element at (i, j).
|
func setElement(values string, dim int, i, j int, value float64) string {
|
||||||
func (c *ColorM) SetElement(i, j int, value float64) {
|
if values == "" {
|
||||||
if c.values == "" {
|
values = identityValues[dim]
|
||||||
c.values = colorMIdentityValue
|
|
||||||
}
|
}
|
||||||
a := js.NewArrayBuffer([]uint8(c.values))
|
a := js.NewArrayBuffer([]uint8(values))
|
||||||
a8 := js.Global.Get("Uint8Array").New(a)
|
a8 := js.Global.Get("Uint8Array").New(a)
|
||||||
af64 := js.Global.Get("Float64Array").New(a)
|
af64 := js.Global.Get("Float64Array").New(a)
|
||||||
af64.SetIndex(i*ColorMDim+j, value)
|
af64.SetIndex(i*dim+j, value)
|
||||||
c.values = string(a8.Interface().([]uint8))
|
return string(a8.Interface().([]uint8))
|
||||||
}
|
}
|
@ -22,36 +22,34 @@ import (
|
|||||||
"github.com/hajimehoshi/ebiten/internal/endian"
|
"github.com/hajimehoshi/ebiten/internal/endian"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Element returns a value of a matrix at (i, j).
|
func element(values string, dim int, i, j int) float64 {
|
||||||
func (c *ColorM) Element(i, j int) float64 {
|
if values == "" {
|
||||||
if c.values == "" {
|
|
||||||
if i == j {
|
if i == j {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
offset := 8 * (i*ColorMDim + j)
|
offset := 8 * (i*dim + j)
|
||||||
v := uint64(0)
|
v := uint64(0)
|
||||||
if endian.IsLittle() {
|
if endian.IsLittle() {
|
||||||
for k := 7; 0 <= k; k-- {
|
for k := 7; 0 <= k; k-- {
|
||||||
v <<= 8
|
v <<= 8
|
||||||
v += uint64(c.values[offset+k])
|
v += uint64(values[offset+k])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for k := 0; k < 8; k++ {
|
for k := 0; k < 8; k++ {
|
||||||
v <<= 8
|
v <<= 8
|
||||||
v += uint64(c.values[offset+k])
|
v += uint64(values[offset+k])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return math.Float64frombits(v)
|
return math.Float64frombits(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetElement sets an element at (i, j).
|
func setElement(values string, dim int, i, j int, value float64) string {
|
||||||
func (c *ColorM) SetElement(i, j int, value float64) {
|
if values == "" {
|
||||||
if c.values == "" {
|
values = identityValues[dim]
|
||||||
c.values = colorMIdentityValue
|
|
||||||
}
|
}
|
||||||
b := uint64ToBytes(math.Float64bits(value))
|
b := uint64ToBytes(math.Float64bits(value))
|
||||||
offset := 8 * (i*ColorMDim + j)
|
offset := 8 * (i*dim + j)
|
||||||
c.values = c.values[:offset] + string(b) + c.values[offset+8:]
|
return values[:offset] + string(b) + values[offset+8:]
|
||||||
}
|
}
|
@ -16,29 +16,11 @@ package affine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/hajimehoshi/ebiten/internal/endian"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ColorMDim is a dimension of a ColorM.
|
// ColorMDim is a dimension of a ColorM.
|
||||||
const ColorMDim = 5
|
const ColorMDim = 5
|
||||||
|
|
||||||
func uint64ToBytes(value uint64) []uint8 {
|
|
||||||
result := make([]uint8, 8)
|
|
||||||
if endian.IsLittle() {
|
|
||||||
for i := 0; i < 8; i++ {
|
|
||||||
result[i] = uint8(value)
|
|
||||||
value >>= 8
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i := 7; 0 <= i; i-- {
|
|
||||||
result[i] = uint8(value)
|
|
||||||
value >>= 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func colorMValueString(values [ColorMDim - 1][ColorMDim]float64) string {
|
func colorMValueString(values [ColorMDim - 1][ColorMDim]float64) string {
|
||||||
b := make([]uint8, 0, (ColorMDim-1)*(ColorMDim)*8)
|
b := make([]uint8, 0, (ColorMDim-1)*(ColorMDim)*8)
|
||||||
for i := 0; i < ColorMDim-1; i++ {
|
for i := 0; i < ColorMDim-1; i++ {
|
||||||
@ -49,15 +31,6 @@ func colorMValueString(values [ColorMDim - 1][ColorMDim]float64) string {
|
|||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
colorMIdentityValue = colorMValueString([ColorMDim - 1][ColorMDim]float64{
|
|
||||||
{1, 0, 0, 0, 0},
|
|
||||||
{0, 1, 0, 0, 0},
|
|
||||||
{0, 0, 1, 0, 0},
|
|
||||||
{0, 0, 0, 1, 0},
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
// A ColorM represents a matrix to transform coloring when rendering an image.
|
// A ColorM represents a matrix to transform coloring when rendering an image.
|
||||||
//
|
//
|
||||||
// A ColorM is applied to the source alpha color
|
// A ColorM is applied to the source alpha color
|
||||||
@ -75,12 +48,22 @@ func (c *ColorM) dim() int {
|
|||||||
return ColorMDim
|
return ColorMDim
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Element returns a value of a matrix at (i, j).
|
||||||
|
func (c *ColorM) Element(i, j int) float64 {
|
||||||
|
return element(c.values, ColorMDim, i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetElement sets an element at (i, j).
|
||||||
|
func (c *ColorM) SetElement(i, j int, element float64) {
|
||||||
|
c.values = setElement(c.values, ColorMDim, i, j, element)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *ColorM) Equals(other *ColorM) bool {
|
func (c *ColorM) Equals(other *ColorM) bool {
|
||||||
if c.values == "" {
|
if c.values == "" {
|
||||||
c.values = colorMIdentityValue
|
c.values = identityValues[ColorMDim]
|
||||||
}
|
}
|
||||||
if other.values == "" {
|
if other.values == "" {
|
||||||
other.values = colorMIdentityValue
|
other.values = identityValues[ColorMDim]
|
||||||
}
|
}
|
||||||
return c.values == other.values
|
return c.values == other.values
|
||||||
}
|
}
|
||||||
@ -93,7 +76,7 @@ func (c *ColorM) Concat(other ColorM) {
|
|||||||
*c = result
|
*c = result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a color matrix with the other color matrix.
|
// Add is deprecated.
|
||||||
func (c *ColorM) Add(other ColorM) {
|
func (c *ColorM) Add(other ColorM) {
|
||||||
result := ColorM{}
|
result := ColorM{}
|
||||||
add(&other, c, &result)
|
add(&other, c, &result)
|
||||||
|
@ -21,52 +21,48 @@ import (
|
|||||||
// GeoMDim is a dimension of a GeoM.
|
// GeoMDim is a dimension of a GeoM.
|
||||||
const GeoMDim = 3
|
const GeoMDim = 3
|
||||||
|
|
||||||
|
func geoMValueString(values [GeoMDim - 1][GeoMDim]float64) string {
|
||||||
|
b := make([]uint8, 0, (GeoMDim-1)*(GeoMDim)*8)
|
||||||
|
for i := 0; i < GeoMDim-1; i++ {
|
||||||
|
for j := 0; j < GeoMDim; j++ {
|
||||||
|
b = append(b, uint64ToBytes(math.Float64bits(values[i][j]))...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
initialized bool
|
// When values is empty, this matrix is identity.
|
||||||
es [(GeoMDim - 1) * GeoMDim]float64
|
values string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GeoM) dim() int {
|
func (g *GeoM) dim() int {
|
||||||
return GeoMDim
|
return GeoMDim
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GeoM) initialize() {
|
|
||||||
g.initialized = true
|
|
||||||
for i := 0; i < GeoMDim-1; i++ {
|
|
||||||
g.es[i*GeoMDim+i] = 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
||||||
if !g.initialized {
|
return element(g.values, GeoMDim, i, j)
|
||||||
if i == j {
|
}
|
||||||
return 1
|
|
||||||
}
|
// SetElement sets an element at (i, j).
|
||||||
return 0
|
func (g *GeoM) SetElement(i, j int, element float64) {
|
||||||
}
|
g.values = setElement(g.values, GeoMDim, i, j, element)
|
||||||
return g.es[i*GeoMDim+j]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.initialized {
|
|
||||||
g.initialize()
|
|
||||||
}
|
|
||||||
result := GeoM{}
|
result := GeoM{}
|
||||||
mul(&other, g, &result)
|
mul(&other, g, &result)
|
||||||
*g = result
|
*g = result
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds a geometry matrix with the other geometry matrix.
|
// Add is deprecated.
|
||||||
func (g *GeoM) Add(other GeoM) {
|
func (g *GeoM) Add(other GeoM) {
|
||||||
if !g.initialized {
|
|
||||||
g.initialize()
|
|
||||||
}
|
|
||||||
result := GeoM{}
|
result := GeoM{}
|
||||||
add(&other, g, &result)
|
add(&other, g, &result)
|
||||||
*g = result
|
*g = result
|
||||||
@ -74,63 +70,46 @@ 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) {
|
||||||
if !g.initialized {
|
|
||||||
g.initialize()
|
|
||||||
}
|
|
||||||
for i := 0; i < GeoMDim; i++ {
|
for i := 0; i < GeoMDim; i++ {
|
||||||
g.es[i] *= x
|
g.SetElement(0, i, g.Element(0, i)*x)
|
||||||
g.es[GeoMDim+i] *= y
|
g.SetElement(1, i, g.Element(1, i)*y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.initialized {
|
g.SetElement(0, 2, g.Element(0, 2)+tx)
|
||||||
g.initialize()
|
g.SetElement(1, 2, g.Element(1, 2)+ty)
|
||||||
}
|
|
||||||
g.es[2] += tx
|
|
||||||
g.es[GeoMDim+2] += ty
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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{
|
||||||
initialized: true,
|
values: geoMValueString([GeoMDim - 1][GeoMDim]float64{
|
||||||
es: [...]float64{
|
{cos, -sin, 0},
|
||||||
cos, -sin, 0,
|
{sin, cos, 0},
|
||||||
sin, cos, 0,
|
}),
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetElement sets an element at (i, j).
|
|
||||||
func (g *GeoM) SetElement(i, j int, element float64) {
|
|
||||||
if !g.initialized {
|
|
||||||
g.initialize()
|
|
||||||
}
|
|
||||||
g.es[i*GeoMDim+j] = element
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScaleGeo is deprecated as of 1.2.0-alpha. Use Scale instead.
|
// ScaleGeo is deprecated as of 1.2.0-alpha. Use Scale instead.
|
||||||
func ScaleGeo(x, y float64) GeoM {
|
func ScaleGeo(x, y float64) GeoM {
|
||||||
return GeoM{
|
return GeoM{
|
||||||
initialized: true,
|
values: geoMValueString([GeoMDim - 1][GeoMDim]float64{
|
||||||
es: [...]float64{
|
{x, 0, 0},
|
||||||
x, 0, 0,
|
{0, y, 0},
|
||||||
0, y, 0,
|
}),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TranslateGeo is deprecated as of 1.2.0-alpha. Use Translate instead.
|
// TranslateGeo is deprecated as of 1.2.0-alpha. Use Translate instead.
|
||||||
func TranslateGeo(tx, ty float64) GeoM {
|
func TranslateGeo(tx, ty float64) GeoM {
|
||||||
return GeoM{
|
return GeoM{
|
||||||
initialized: true,
|
values: geoMValueString([GeoMDim - 1][GeoMDim]float64{
|
||||||
es: [...]float64{
|
{1, 0, tx},
|
||||||
1, 0, tx,
|
{0, 1, ty},
|
||||||
0, 1, ty,
|
}),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,10 +117,9 @@ func TranslateGeo(tx, ty float64) GeoM {
|
|||||||
func RotateGeo(theta float64) GeoM {
|
func RotateGeo(theta float64) GeoM {
|
||||||
sin, cos := math.Sincos(theta)
|
sin, cos := math.Sincos(theta)
|
||||||
return GeoM{
|
return GeoM{
|
||||||
initialized: true,
|
values: geoMValueString([GeoMDim - 1][GeoMDim]float64{
|
||||||
es: [...]float64{
|
{cos, -sin, 0},
|
||||||
cos, -sin, 0,
|
{sin, cos, 0},
|
||||||
sin, cos, 0,
|
}),
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user