mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 03:08:54 +01:00
affine: Separate ColorM impl into two slices
This fix avoids unnecessary allocating arrays.
This commit is contained in:
parent
d70e703d5e
commit
95480d0644
@ -87,7 +87,11 @@ func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale
|
|||||||
|
|
||||||
// Element returns a value of a matrix at (i, j).
|
// Element returns a value of a matrix at (i, j).
|
||||||
func (c *ColorM) Element(i, j int) float64 {
|
func (c *ColorM) Element(i, j int) float64 {
|
||||||
return c.impl.UnsafeElements()[i*affine.ColorMDim+j]
|
b, t := c.impl.UnsafeElements()
|
||||||
|
if j < ColorMDim-1 {
|
||||||
|
return b[i*(ColorMDim-1)+j]
|
||||||
|
}
|
||||||
|
return t[i]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetElement sets an element at (i, j).
|
// SetElement sets an element at (i, j).
|
||||||
|
@ -25,17 +25,14 @@ func add(lhs, rhs []float64, dim int) []float64 {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func mul(lhs, rhs []float64, dim int) []float64 {
|
func mulSquare(lhs, rhs []float64, dim int) []float64 {
|
||||||
result := make([]float64, len(lhs))
|
result := make([]float64, len(lhs))
|
||||||
for i := 0; i < dim-1; i++ {
|
for i := 0; i < dim; i++ {
|
||||||
for j := 0; j < dim; j++ {
|
for j := 0; j < dim; j++ {
|
||||||
e := 0.0
|
e := 0.0
|
||||||
for k := 0; k < dim-1; k++ {
|
for k := 0; k < dim; k++ {
|
||||||
e += lhs[i*dim+k] * rhs[k*dim+j]
|
e += lhs[i*dim+k] * rhs[k*dim+j]
|
||||||
}
|
}
|
||||||
if j == dim-1 {
|
|
||||||
e += lhs[i*dim+j]
|
|
||||||
}
|
|
||||||
result[i*dim+j] = e
|
result[i*dim+j] = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,11 +23,14 @@ import (
|
|||||||
const ColorMDim = 5
|
const ColorMDim = 5
|
||||||
|
|
||||||
var (
|
var (
|
||||||
colorMIdentityElements = []float64{
|
colorMIdentityBody = []float64{
|
||||||
1, 0, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, 1, 0, 0, 0,
|
0, 1, 0, 0,
|
||||||
0, 0, 1, 0, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1, 0,
|
0, 0, 0, 1,
|
||||||
|
}
|
||||||
|
colorMIdentityTranslate = []float64{
|
||||||
|
0, 0, 0, 0,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,11 +45,13 @@ var (
|
|||||||
type ColorM struct {
|
type ColorM struct {
|
||||||
// When elements is nil, this matrix is identity.
|
// When elements is nil, this matrix is identity.
|
||||||
// elements is immutable and a new array must be created when updating.
|
// elements is immutable and a new array must be created when updating.
|
||||||
elements []float64
|
body []float64 // TODO: Transpose this to pass this OpenGL easily
|
||||||
|
translate []float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ColorM) Reset() {
|
func (c *ColorM) Reset() {
|
||||||
c.elements = nil
|
c.body = nil
|
||||||
|
c.translate = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func clamp(x float64) float64 {
|
func clamp(x float64) float64 {
|
||||||
@ -60,22 +65,24 @@ func clamp(x float64) float64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *ColorM) Apply(clr color.Color) color.Color {
|
func (c *ColorM) Apply(clr color.Color) color.Color {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
return clr
|
return clr
|
||||||
}
|
}
|
||||||
r, g, b, a := clr.RGBA()
|
r, g, b, a := clr.RGBA()
|
||||||
if a == 0 {
|
if a == 0 {
|
||||||
return color.Transparent
|
return color.Transparent
|
||||||
}
|
}
|
||||||
|
// Unmultiply alpha
|
||||||
rf := float64(r) / float64(a)
|
rf := float64(r) / float64(a)
|
||||||
gf := float64(g) / float64(a)
|
gf := float64(g) / float64(a)
|
||||||
bf := float64(b) / float64(a)
|
bf := float64(b) / float64(a)
|
||||||
af := float64(a) / 0xffff
|
af := float64(a) / 0xffff
|
||||||
e := c.elements
|
eb := c.body
|
||||||
rf2 := e[0]*rf + e[1]*gf + e[2]*bf + e[3]*af + e[4]
|
et := c.translate
|
||||||
gf2 := e[5]*rf + e[6]*gf + e[7]*bf + e[8]*af + e[9]
|
rf2 := eb[0]*rf + eb[1]*gf + eb[2]*bf + eb[3]*af + et[0]
|
||||||
bf2 := e[10]*rf + e[11]*gf + e[12]*bf + e[13]*af + e[14]
|
gf2 := eb[4]*rf + eb[5]*gf + eb[6]*bf + eb[7]*af + et[1]
|
||||||
af2 := e[15]*rf + e[16]*gf + e[17]*bf + e[18]*af + e[19]
|
bf2 := eb[8]*rf + eb[9]*gf + eb[10]*bf + eb[11]*af + et[2]
|
||||||
|
af2 := eb[12]*rf + eb[13]*gf + eb[14]*bf + eb[15]*af + et[3]
|
||||||
rf2 = clamp(rf2)
|
rf2 = clamp(rf2)
|
||||||
gf2 = clamp(gf2)
|
gf2 = clamp(gf2)
|
||||||
bf2 = clamp(bf2)
|
bf2 = clamp(bf2)
|
||||||
@ -88,36 +95,52 @@ func (c *ColorM) Apply(clr color.Color) color.Color {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ColorM) UnsafeElements() []float64 {
|
func (c *ColorM) UnsafeElements() ([]float64, []float64) {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
c.elements = colorMIdentityElements
|
c.body = colorMIdentityBody
|
||||||
|
c.translate = colorMIdentityTranslate
|
||||||
}
|
}
|
||||||
return c.elements
|
return c.body, c.translate
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetElement sets an element at (i, j).
|
// SetElement sets an element at (i, j).
|
||||||
func (c *ColorM) SetElement(i, j int, element float64) {
|
func (c *ColorM) SetElement(i, j int, element float64) {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
c.elements = colorMIdentityElements
|
c.body = colorMIdentityBody
|
||||||
|
c.translate = colorMIdentityTranslate
|
||||||
|
}
|
||||||
|
if j < (ColorMDim - 1) {
|
||||||
|
es := make([]float64, len(c.body))
|
||||||
|
copy(es, c.body)
|
||||||
|
es[i*(ColorMDim-1)+j] = element
|
||||||
|
c.body = es
|
||||||
|
} else {
|
||||||
|
es := make([]float64, len(c.translate))
|
||||||
|
copy(es, c.translate)
|
||||||
|
es[i] = element
|
||||||
|
c.translate = es
|
||||||
}
|
}
|
||||||
es := make([]float64, len(c.elements))
|
|
||||||
copy(es, c.elements)
|
|
||||||
es[i*ColorMDim+j] = element
|
|
||||||
c.elements = es
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ColorM) Equals(other *ColorM) bool {
|
func (c *ColorM) Equals(other *ColorM) bool {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
if other.elements == nil {
|
if other.body == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
c.elements = colorMIdentityElements
|
c.body = colorMIdentityBody
|
||||||
|
c.translate = colorMIdentityTranslate
|
||||||
}
|
}
|
||||||
if other.elements == nil {
|
if other.body == nil {
|
||||||
other.elements = colorMIdentityElements
|
other.body = colorMIdentityBody
|
||||||
|
other.translate = colorMIdentityTranslate
|
||||||
}
|
}
|
||||||
for i := range c.elements {
|
for i := range c.body {
|
||||||
if c.elements[i] != other.elements[i] {
|
if c.body[i] != other.body[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := range c.translate {
|
||||||
|
if c.translate[i] != other.translate[i] {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,66 +150,76 @@ 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.body == nil {
|
||||||
c.elements = colorMIdentityElements
|
c.body = colorMIdentityBody
|
||||||
|
c.translate = colorMIdentityTranslate
|
||||||
}
|
}
|
||||||
if other.elements == nil {
|
if other.body == nil {
|
||||||
other.elements = colorMIdentityElements
|
other.body = colorMIdentityBody
|
||||||
|
other.translate = colorMIdentityTranslate
|
||||||
|
}
|
||||||
|
c.body = mulSquare(other.body, c.body, ColorMDim-1)
|
||||||
|
|
||||||
|
lhsb := other.body
|
||||||
|
lhst := other.translate
|
||||||
|
rhst := c.translate
|
||||||
|
c.translate = []float64{
|
||||||
|
lhsb[0]*rhst[0] + lhsb[1]*rhst[1] + lhsb[2]*rhst[2] + lhsb[3]*rhst[3] + lhst[0],
|
||||||
|
lhsb[4]*rhst[0] + lhsb[5]*rhst[1] + lhsb[6]*rhst[2] + lhsb[7]*rhst[3] + lhst[1],
|
||||||
|
lhsb[8]*rhst[0] + lhsb[9]*rhst[1] + lhsb[10]*rhst[2] + lhsb[11]*rhst[3] + lhst[2],
|
||||||
|
lhsb[12]*rhst[0] + lhsb[13]*rhst[1] + lhsb[14]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
|
||||||
}
|
}
|
||||||
c.elements = mul(other.elements, c.elements, ColorMDim)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add is deprecated.
|
// Add is deprecated.
|
||||||
func (c *ColorM) Add(other ColorM) {
|
func (c *ColorM) Add(other ColorM) {
|
||||||
if c.elements == nil {
|
// Do nothing.
|
||||||
c.elements = colorMIdentityElements
|
|
||||||
}
|
|
||||||
if other.elements == nil {
|
|
||||||
other.elements = colorMIdentityElements
|
|
||||||
}
|
|
||||||
c.elements = add(other.elements, c.elements, ColorMDim)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale scales the matrix by (r, g, b, a).
|
// Scale scales the matrix by (r, g, b, a).
|
||||||
func (c *ColorM) Scale(r, g, b, a float64) {
|
func (c *ColorM) Scale(r, g, b, a float64) {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
c.elements = []float64{
|
c.body = []float64{
|
||||||
r, 0, 0, 0, 0,
|
r, 0, 0, 0,
|
||||||
0, g, 0, 0, 0,
|
0, g, 0, 0,
|
||||||
0, 0, b, 0, 0,
|
0, 0, b, 0,
|
||||||
0, 0, 0, a, 0,
|
0, 0, 0, a,
|
||||||
}
|
}
|
||||||
|
c.translate = colorMIdentityTranslate
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
es := make([]float64, len(c.elements))
|
es := make([]float64, len(c.body))
|
||||||
copy(es, c.elements)
|
copy(es, c.body)
|
||||||
for i := 0; i < ColorMDim; i++ {
|
for i := 0; i < ColorMDim-1; i++ {
|
||||||
es[i] *= r
|
es[i] *= r
|
||||||
es[i+ColorMDim] *= g
|
es[i+(ColorMDim-1)] *= g
|
||||||
es[i+ColorMDim*2] *= b
|
es[i+(ColorMDim-1)*2] *= b
|
||||||
es[i+ColorMDim*3] *= a
|
es[i+(ColorMDim-1)*3] *= a
|
||||||
|
}
|
||||||
|
c.body = es
|
||||||
|
|
||||||
|
c.translate = []float64{
|
||||||
|
c.translate[0] * r,
|
||||||
|
c.translate[1] * g,
|
||||||
|
c.translate[2] * b,
|
||||||
|
c.translate[3] * a,
|
||||||
}
|
}
|
||||||
c.elements = es
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Translate translates the matrix by (r, g, b, a).
|
// Translate translates the matrix by (r, g, b, a).
|
||||||
func (c *ColorM) Translate(r, g, b, a float64) {
|
func (c *ColorM) Translate(r, g, b, a float64) {
|
||||||
if c.elements == nil {
|
if c.body == nil {
|
||||||
c.elements = []float64{
|
c.body = colorMIdentityBody
|
||||||
1, 0, 0, 0, r,
|
c.translate = []float64{r, g, b, a}
|
||||||
0, 1, 0, 0, g,
|
|
||||||
0, 0, 1, 0, b,
|
|
||||||
0, 0, 0, 1, a,
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
es := make([]float64, len(c.elements))
|
es := make([]float64, len(c.translate))
|
||||||
copy(es, c.elements)
|
copy(es, c.translate)
|
||||||
es[4] += r
|
es[0] += r
|
||||||
es[4+ColorMDim] += g
|
es[1] += g
|
||||||
es[4+ColorMDim*2] += b
|
es[2] += b
|
||||||
es[4+ColorMDim*3] += a
|
es[3] += a
|
||||||
c.elements = es
|
c.translate = es
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -196,20 +229,22 @@ var (
|
|||||||
// Cr: [-0.5 - 0.5]
|
// Cr: [-0.5 - 0.5]
|
||||||
|
|
||||||
rgbToYCbCr = ColorM{
|
rgbToYCbCr = ColorM{
|
||||||
elements: []float64{
|
body: []float64{
|
||||||
0.2990, 0.5870, 0.1140, 0, 0,
|
0.2990, 0.5870, 0.1140, 0,
|
||||||
-0.1687, -0.3313, 0.5000, 0, 0,
|
-0.1687, -0.3313, 0.5000, 0,
|
||||||
0.5000, -0.4187, -0.0813, 0, 0,
|
0.5000, -0.4187, -0.0813, 0,
|
||||||
0, 0, 0, 1, 0,
|
0, 0, 0, 1,
|
||||||
},
|
},
|
||||||
|
translate: []float64{0, 0, 0, 0},
|
||||||
}
|
}
|
||||||
yCbCrToRgb = ColorM{
|
yCbCrToRgb = ColorM{
|
||||||
elements: []float64{
|
body: []float64{
|
||||||
1, 0, 1.40200, 0, 0,
|
1, 0, 1.40200, 0,
|
||||||
1, -0.34414, -0.71414, 0, 0,
|
1, -0.34414, -0.71414, 0,
|
||||||
1, 1.77200, 0, 0, 0,
|
1, 1.77200, 0, 0,
|
||||||
0, 0, 0, 1, 0,
|
0, 0, 0, 1,
|
||||||
},
|
},
|
||||||
|
translate: []float64{0, 0, 0, 0},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -223,12 +258,13 @@ func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float64, valueScale
|
|||||||
sin, cos := math.Sincos(hueTheta)
|
sin, cos := math.Sincos(hueTheta)
|
||||||
c.Concat(&rgbToYCbCr)
|
c.Concat(&rgbToYCbCr)
|
||||||
c.Concat(&ColorM{
|
c.Concat(&ColorM{
|
||||||
elements: []float64{
|
body: []float64{
|
||||||
1, 0, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, cos, -sin, 0, 0,
|
0, cos, -sin, 0,
|
||||||
0, sin, cos, 0, 0,
|
0, sin, cos, 0,
|
||||||
0, 0, 0, 1, 0,
|
0, 0, 0, 1,
|
||||||
},
|
},
|
||||||
|
translate: []float64{0, 0, 0, 0},
|
||||||
})
|
})
|
||||||
s := saturationScale
|
s := saturationScale
|
||||||
v := valueScale
|
v := valueScale
|
||||||
|
@ -264,19 +264,14 @@ func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, sourceW
|
|||||||
copy(s.lastProjectionMatrix, proj)
|
copy(s.lastProjectionMatrix, proj)
|
||||||
}
|
}
|
||||||
|
|
||||||
e := [4][5]float32{}
|
esBody, esTranslate := colorM.UnsafeElements()
|
||||||
es := colorM.UnsafeElements()
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
for j := 0; j < 5; j++ {
|
|
||||||
e[i][j] = float32(es[i*affine.ColorMDim+j])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
colorMatrix := []float32{
|
// transpose
|
||||||
e[0][0], e[1][0], e[2][0], e[3][0],
|
colorMatrix := make([]float32, (affine.ColorMDim-1)*(affine.ColorMDim-1))
|
||||||
e[0][1], e[1][1], e[2][1], e[3][1],
|
for i := 0; i < affine.ColorMDim-1; i++ {
|
||||||
e[0][2], e[1][2], e[2][2], e[3][2],
|
for j := 0; j < affine.ColorMDim-1; j++ {
|
||||||
e[0][3], e[1][3], e[2][3], e[3][3],
|
colorMatrix[i+j*(affine.ColorMDim-1)] = float32(esBody[i*(affine.ColorMDim-1)+j])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if !areSameFloat32Array(s.lastColorMatrix, colorMatrix) {
|
if !areSameFloat32Array(s.lastColorMatrix, colorMatrix) {
|
||||||
c.UniformFloats(program, "color_matrix", colorMatrix)
|
c.UniformFloats(program, "color_matrix", colorMatrix)
|
||||||
@ -286,7 +281,10 @@ func (s *openGLState) useProgram(proj []float32, texture opengl.Texture, sourceW
|
|||||||
copy(s.lastColorMatrix, colorMatrix)
|
copy(s.lastColorMatrix, colorMatrix)
|
||||||
}
|
}
|
||||||
colorMatrixTranslation := []float32{
|
colorMatrixTranslation := []float32{
|
||||||
e[0][4], e[1][4], e[2][4], e[3][4],
|
float32(esTranslate[0]),
|
||||||
|
float32(esTranslate[1]),
|
||||||
|
float32(esTranslate[2]),
|
||||||
|
float32(esTranslate[3]),
|
||||||
}
|
}
|
||||||
if !areSameFloat32Array(s.lastColorMatrixTranslation, colorMatrixTranslation) {
|
if !areSameFloat32Array(s.lastColorMatrixTranslation, colorMatrixTranslation) {
|
||||||
c.UniformFloats(program, "color_matrix_translation", colorMatrixTranslation)
|
c.UniformFloats(program, "color_matrix_translation", colorMatrixTranslation)
|
||||||
|
Loading…
Reference in New Issue
Block a user