twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

colorm.go (13542B)


      1 // Copyright 2014 Hajime Hoshi
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package affine
     16 
     17 import (
     18 	"image/color"
     19 	"math"
     20 )
     21 
     22 // ColorMDim is a dimension of a ColorM.
     23 const ColorMDim = 5
     24 
     25 var (
     26 	colorMIdentityBody = []float32{
     27 		1, 0, 0, 0,
     28 		0, 1, 0, 0,
     29 		0, 0, 1, 0,
     30 		0, 0, 0, 1,
     31 	}
     32 	colorMIdentityTranslate = []float32{
     33 		0, 0, 0, 0,
     34 	}
     35 )
     36 
     37 // A ColorM represents a matrix to transform coloring when rendering an image.
     38 //
     39 // A ColorM is applied to the source alpha color
     40 // while an Image's pixels' format is alpha premultiplied.
     41 // Before applying a matrix, a color is un-multiplied, and after applying the matrix,
     42 // the color is multiplied again.
     43 //
     44 // The nil and initial value is identity.
     45 type ColorM struct {
     46 	// When elements is nil, this matrix is identity.
     47 	// elements are immutable and a new array must be created when updating.
     48 	body      []float32
     49 	translate []float32
     50 }
     51 
     52 func clamp(x float32) float32 {
     53 	if x > 1 {
     54 		return 1
     55 	}
     56 	if x < 0 {
     57 		return 0
     58 	}
     59 	return x
     60 }
     61 
     62 func (c *ColorM) isInited() bool {
     63 	return c != nil && (c.body != nil || c.translate != nil)
     64 }
     65 
     66 func (c *ColorM) ScaleOnly() bool {
     67 	if c == nil {
     68 		return true
     69 	}
     70 	if c.body != nil {
     71 		if c.body[1] != 0 {
     72 			return false
     73 		}
     74 		if c.body[2] != 0 {
     75 			return false
     76 		}
     77 		if c.body[3] != 0 {
     78 			return false
     79 		}
     80 		if c.body[4] != 0 {
     81 			return false
     82 		}
     83 		if c.body[6] != 0 {
     84 			return false
     85 		}
     86 		if c.body[7] != 0 {
     87 			return false
     88 		}
     89 		if c.body[8] != 0 {
     90 			return false
     91 		}
     92 		if c.body[9] != 0 {
     93 			return false
     94 		}
     95 		if c.body[11] != 0 {
     96 			return false
     97 		}
     98 		if c.body[12] != 0 {
     99 			return false
    100 		}
    101 		if c.body[13] != 0 {
    102 			return false
    103 		}
    104 		if c.body[14] != 0 {
    105 			return false
    106 		}
    107 	}
    108 	if c.translate != nil {
    109 		for _, e := range c.translate {
    110 			if e != 0 {
    111 				return false
    112 			}
    113 		}
    114 	}
    115 	return true
    116 }
    117 
    118 func (c *ColorM) Apply(clr color.Color) color.Color {
    119 	if !c.isInited() {
    120 		return clr
    121 	}
    122 	r, g, b, a := clr.RGBA()
    123 	rf, gf, bf, af := float32(0.0), float32(0.0), float32(0.0), float32(0.0)
    124 	// Unmultiply alpha
    125 	if a > 0 {
    126 		rf = float32(r) / float32(a)
    127 		gf = float32(g) / float32(a)
    128 		bf = float32(b) / float32(a)
    129 		af = float32(a) / 0xffff
    130 	}
    131 	eb := c.body
    132 	if eb == nil {
    133 		eb = colorMIdentityBody
    134 	}
    135 	et := c.translate
    136 	if et == nil {
    137 		et = colorMIdentityTranslate
    138 	}
    139 	rf2 := eb[0]*rf + eb[4]*gf + eb[8]*bf + eb[12]*af + et[0]
    140 	gf2 := eb[1]*rf + eb[5]*gf + eb[9]*bf + eb[13]*af + et[1]
    141 	bf2 := eb[2]*rf + eb[6]*gf + eb[10]*bf + eb[14]*af + et[2]
    142 	af2 := eb[3]*rf + eb[7]*gf + eb[11]*bf + eb[15]*af + et[3]
    143 	rf2 = clamp(rf2)
    144 	gf2 = clamp(gf2)
    145 	bf2 = clamp(bf2)
    146 	af2 = clamp(af2)
    147 	return color.NRGBA64{
    148 		R: uint16(rf2 * 0xffff),
    149 		G: uint16(gf2 * 0xffff),
    150 		B: uint16(bf2 * 0xffff),
    151 		A: uint16(af2 * 0xffff),
    152 	}
    153 }
    154 
    155 func (c *ColorM) UnsafeElements() ([]float32, []float32) {
    156 	if !c.isInited() {
    157 		return colorMIdentityBody, colorMIdentityTranslate
    158 	}
    159 	eb := c.body
    160 	if eb == nil {
    161 		eb = colorMIdentityBody
    162 	}
    163 	et := c.translate
    164 	if et == nil {
    165 		et = colorMIdentityTranslate
    166 	}
    167 	return eb, et
    168 }
    169 
    170 func (c *ColorM) det() float32 {
    171 	if !c.isInited() {
    172 		return 1
    173 	}
    174 
    175 	m00 := c.body[0]
    176 	m01 := c.body[1]
    177 	m02 := c.body[2]
    178 	m03 := c.body[3]
    179 	m10 := c.body[4]
    180 	m11 := c.body[5]
    181 	m12 := c.body[6]
    182 	m13 := c.body[7]
    183 	m20 := c.body[8]
    184 	m21 := c.body[9]
    185 	m22 := c.body[10]
    186 	m23 := c.body[11]
    187 	m30 := c.body[12]
    188 	m31 := c.body[13]
    189 	m32 := c.body[14]
    190 	m33 := c.body[15]
    191 
    192 	b234234 := m22*m33 - m23*m32
    193 	b134234 := m21*m33 - m23*m31
    194 	b124234 := m21*m32 - m22*m31
    195 	b034234 := m20*m33 - m23*m30
    196 	b024234 := m20*m32 - m22*m30
    197 	b014234 := m20*m31 - m21*m30
    198 
    199 	return m00*(m11*b234234-m12*b134234+m13*b124234) -
    200 		m01*(m10*b234234-m12*b034234+m13*b024234) +
    201 		m02*(m10*b134234-m11*b034234+m13*b014234) -
    202 		m03*(m10*b124234-m11*b024234+m12*b014234)
    203 }
    204 
    205 // IsInvertible returns a boolean value indicating
    206 // whether the matrix c is invertible or not.
    207 func (c *ColorM) IsInvertible() bool {
    208 	return c.det() != 0
    209 }
    210 
    211 // Invert inverts the matrix.
    212 // If c is not invertible, Invert panics.
    213 func (c *ColorM) Invert() *ColorM {
    214 	if !c.isInited() {
    215 		return nil
    216 	}
    217 
    218 	det := c.det()
    219 	if det == 0 {
    220 		panic("affine: c is not invertible")
    221 	}
    222 
    223 	m00 := c.body[0]
    224 	m01 := c.body[1]
    225 	m02 := c.body[2]
    226 	m03 := c.body[3]
    227 
    228 	m10 := c.body[4]
    229 	m11 := c.body[5]
    230 	m12 := c.body[6]
    231 	m13 := c.body[7]
    232 
    233 	m20 := c.body[8]
    234 	m21 := c.body[9]
    235 	m22 := c.body[10]
    236 	m23 := c.body[11]
    237 
    238 	m30 := c.body[12]
    239 	m31 := c.body[13]
    240 	m32 := c.body[14]
    241 	m33 := c.body[15]
    242 
    243 	m40 := c.translate[0]
    244 	m41 := c.translate[1]
    245 	m42 := c.translate[2]
    246 	m43 := c.translate[3]
    247 
    248 	a2334 := m32*m43 - m33*m42
    249 	a1334 := m31*m43 - m33*m41
    250 	a1234 := m31*m42 - m32*m41
    251 	a0334 := m30*m43 - m33*m40
    252 	a0234 := m30*m42 - m32*m40
    253 	a0134 := m30*m41 - m31*m40
    254 	a2324 := m22*m43 - m23*m42
    255 	a1324 := m21*m43 - m23*m41
    256 	a1224 := m21*m42 - m22*m41
    257 	a0324 := m20*m43 - m23*m40
    258 	a0224 := m20*m42 - m22*m40
    259 	a0124 := m20*m41 - m21*m40
    260 
    261 	b234234 := m22*m33 - m23*m32
    262 	b134234 := m21*m33 - m23*m31
    263 	b124234 := m21*m32 - m22*m31
    264 	b123234 := m21*a2334 - m22*a1334 + m23*a1234
    265 	b034234 := m20*m33 - m23*m30
    266 	b024234 := m20*m32 - m22*m30
    267 	b023234 := m20*a2334 - m22*a0334 + m23*a0234
    268 	b014234 := m20*m31 - m21*m30
    269 	b013234 := m20*a1334 - m21*a0334 + m23*a0134
    270 	b012234 := m20*a1234 - m21*a0234 + m22*a0134
    271 	b234134 := m12*m33 - m13*m32
    272 	b134134 := m11*m33 - m13*m31
    273 	b124134 := m11*m32 - m12*m31
    274 	b123134 := m11*a2334 - m12*a1334 + m13*a1234
    275 	b234124 := m12*m23 - m13*m22
    276 	b134124 := m11*m23 - m13*m21
    277 	b124124 := m11*m22 - m12*m21
    278 	b123124 := m11*a2324 - m12*a1324 + m13*a1224
    279 	b034134 := m10*m33 - m13*m30
    280 	b024134 := m10*m32 - m12*m30
    281 	b023134 := m10*a2334 - m12*a0334 + m13*a0234
    282 	b034124 := m10*m23 - m13*m20
    283 	b024124 := m10*m22 - m12*m20
    284 	b023124 := m10*a2324 - m12*a0324 + m13*a0224
    285 	b014134 := m10*m31 - m11*m30
    286 	b013134 := m10*a1334 - m11*a0334 + m13*a0134
    287 	b014124 := m10*m21 - m11*m20
    288 	b013124 := m10*a1324 - m11*a0324 + m13*a0124
    289 	b012134 := m10*a1234 - m11*a0234 + m12*a0134
    290 	b012124 := m10*a1224 - m11*a0224 + m12*a0124
    291 
    292 	m := &ColorM{
    293 		body:      make([]float32, 16),
    294 		translate: make([]float32, 4),
    295 	}
    296 
    297 	idet := 1 / det
    298 
    299 	m.body[0] = idet * (m11*b234234 - m12*b134234 + m13*b124234)
    300 	m.body[1] = idet * -(m01*b234234 - m02*b134234 + m03*b124234)
    301 	m.body[2] = idet * (m01*b234134 - m02*b134134 + m03*b124134)
    302 	m.body[3] = idet * -(m01*b234124 - m02*b134124 + m03*b124124)
    303 	m.body[4] = idet * -(m10*b234234 - m12*b034234 + m13*b024234)
    304 	m.body[5] = idet * (m00*b234234 - m02*b034234 + m03*b024234)
    305 	m.body[6] = idet * -(m00*b234134 - m02*b034134 + m03*b024134)
    306 	m.body[7] = idet * (m00*b234124 - m02*b034124 + m03*b024124)
    307 	m.body[8] = idet * (m10*b134234 - m11*b034234 + m13*b014234)
    308 	m.body[9] = idet * -(m00*b134234 - m01*b034234 + m03*b014234)
    309 	m.body[10] = idet * (m00*b134134 - m01*b034134 + m03*b014134)
    310 	m.body[11] = idet * -(m00*b134124 - m01*b034124 + m03*b014124)
    311 	m.body[12] = idet * -(m10*b124234 - m11*b024234 + m12*b014234)
    312 	m.body[13] = idet * (m00*b124234 - m01*b024234 + m02*b014234)
    313 	m.body[14] = idet * -(m00*b124134 - m01*b024134 + m02*b014134)
    314 	m.body[15] = idet * (m00*b124124 - m01*b024124 + m02*b014124)
    315 	m.translate[0] = idet * (m10*b123234 - m11*b023234 + m12*b013234 - m13*b012234)
    316 	m.translate[1] = idet * -(m00*b123234 - m01*b023234 + m02*b013234 - m03*b012234)
    317 	m.translate[2] = idet * (m00*b123134 - m01*b023134 + m02*b013134 - m03*b012134)
    318 	m.translate[3] = idet * -(m00*b123124 - m01*b023124 + m02*b013124 - m03*b012124)
    319 	return m
    320 }
    321 
    322 // Element returns a value of a matrix at (i, j).
    323 func (c *ColorM) Element(i, j int) float32 {
    324 	b, t := c.UnsafeElements()
    325 	if j < ColorMDim-1 {
    326 		return b[i+j*(ColorMDim-1)]
    327 	}
    328 	return t[i]
    329 }
    330 
    331 // SetElement sets an element at (i, j).
    332 func (c *ColorM) SetElement(i, j int, element float32) *ColorM {
    333 	newC := &ColorM{
    334 		body:      make([]float32, 16),
    335 		translate: make([]float32, 4),
    336 	}
    337 	copy(newC.body, colorMIdentityBody)
    338 	copy(newC.translate, colorMIdentityTranslate)
    339 	if c.isInited() {
    340 		if c.body != nil {
    341 			copy(newC.body, c.body)
    342 		}
    343 		if c.translate != nil {
    344 			copy(newC.translate, c.translate)
    345 		}
    346 	}
    347 	if j < (ColorMDim - 1) {
    348 		newC.body[i+j*(ColorMDim-1)] = element
    349 	} else {
    350 		newC.translate[i] = element
    351 	}
    352 	return newC
    353 }
    354 
    355 func (c *ColorM) Equals(other *ColorM) bool {
    356 	if !c.isInited() && !other.isInited() {
    357 		return true
    358 	}
    359 
    360 	lhsb := colorMIdentityBody
    361 	lhst := colorMIdentityTranslate
    362 	rhsb := colorMIdentityBody
    363 	rhst := colorMIdentityTranslate
    364 	if other.isInited() {
    365 		if other.body != nil {
    366 			lhsb = other.body
    367 		}
    368 		if other.translate != nil {
    369 			lhst = other.translate
    370 		}
    371 	}
    372 	if c.isInited() {
    373 		if c.body != nil {
    374 			rhsb = c.body
    375 		}
    376 		if c.translate != nil {
    377 			rhst = c.translate
    378 		}
    379 	}
    380 	if &lhsb == &rhsb && &lhst == &rhst {
    381 		return true
    382 	}
    383 
    384 	for i := range lhsb {
    385 		if lhsb[i] != rhsb[i] {
    386 			return false
    387 		}
    388 	}
    389 	for i := range lhst {
    390 		if lhst[i] != rhst[i] {
    391 			return false
    392 		}
    393 	}
    394 	return true
    395 }
    396 
    397 // Concat multiplies a color matrix with the other color matrix.
    398 // This is same as muptiplying the matrix other and the matrix c in this order.
    399 func (c *ColorM) Concat(other *ColorM) *ColorM {
    400 	if !c.isInited() {
    401 		return other
    402 	}
    403 	if !other.isInited() {
    404 		return c
    405 	}
    406 
    407 	lhsb := colorMIdentityBody
    408 	lhst := colorMIdentityTranslate
    409 	rhsb := colorMIdentityBody
    410 	rhst := colorMIdentityTranslate
    411 	if other.isInited() {
    412 		if other.body != nil {
    413 			lhsb = other.body
    414 		}
    415 		if other.translate != nil {
    416 			lhst = other.translate
    417 		}
    418 	}
    419 	if c.isInited() {
    420 		if c.body != nil {
    421 			rhsb = c.body
    422 		}
    423 		if c.translate != nil {
    424 			rhst = c.translate
    425 		}
    426 	}
    427 
    428 	return &ColorM{
    429 		// TODO: This is a temporary hack to calculate multiply of transposed matrices.
    430 		// Fix mulSquare implmentation and swap the arguments.
    431 		body: mulSquare(rhsb, lhsb, ColorMDim-1),
    432 		translate: []float32{
    433 			lhsb[0]*rhst[0] + lhsb[4]*rhst[1] + lhsb[8]*rhst[2] + lhsb[12]*rhst[3] + lhst[0],
    434 			lhsb[1]*rhst[0] + lhsb[5]*rhst[1] + lhsb[9]*rhst[2] + lhsb[13]*rhst[3] + lhst[1],
    435 			lhsb[2]*rhst[0] + lhsb[6]*rhst[1] + lhsb[10]*rhst[2] + lhsb[14]*rhst[3] + lhst[2],
    436 			lhsb[3]*rhst[0] + lhsb[7]*rhst[1] + lhsb[11]*rhst[2] + lhsb[15]*rhst[3] + lhst[3],
    437 		},
    438 	}
    439 }
    440 
    441 // Add is deprecated.
    442 func (c *ColorM) Add(other *ColorM) *ColorM {
    443 	lhsb := colorMIdentityBody
    444 	lhst := colorMIdentityTranslate
    445 	rhsb := colorMIdentityBody
    446 	rhst := colorMIdentityTranslate
    447 	if other.isInited() {
    448 		if other.body != nil {
    449 			lhsb = other.body
    450 		}
    451 		if other.translate != nil {
    452 			lhst = other.translate
    453 		}
    454 	}
    455 	if c.isInited() {
    456 		if c.body != nil {
    457 			rhsb = c.body
    458 		}
    459 		if c.translate != nil {
    460 			rhst = c.translate
    461 		}
    462 	}
    463 
    464 	newC := &ColorM{
    465 		body:      make([]float32, 16),
    466 		translate: make([]float32, 4),
    467 	}
    468 	for i := range lhsb {
    469 		newC.body[i] = lhsb[i] + rhsb[i]
    470 	}
    471 	for i := range lhst {
    472 		newC.translate[i] = lhst[i] + rhst[i]
    473 	}
    474 
    475 	return newC
    476 }
    477 
    478 // Scale scales the matrix by (r, g, b, a).
    479 func (c *ColorM) Scale(r, g, b, a float32) *ColorM {
    480 	if !c.isInited() {
    481 		return &ColorM{
    482 			body: []float32{
    483 				r, 0, 0, 0,
    484 				0, g, 0, 0,
    485 				0, 0, b, 0,
    486 				0, 0, 0, a,
    487 			},
    488 		}
    489 	}
    490 	eb := make([]float32, len(colorMIdentityBody))
    491 	if c.body != nil {
    492 		copy(eb, c.body)
    493 		for i := 0; i < ColorMDim-1; i++ {
    494 			eb[i*(ColorMDim-1)] *= r
    495 			eb[i*(ColorMDim-1)+1] *= g
    496 			eb[i*(ColorMDim-1)+2] *= b
    497 			eb[i*(ColorMDim-1)+3] *= a
    498 		}
    499 	} else {
    500 		eb[0] = r
    501 		eb[5] = g
    502 		eb[10] = b
    503 		eb[15] = a
    504 	}
    505 
    506 	et := make([]float32, len(colorMIdentityTranslate))
    507 	if c.translate != nil {
    508 		et[0] = c.translate[0] * r
    509 		et[1] = c.translate[1] * g
    510 		et[2] = c.translate[2] * b
    511 		et[3] = c.translate[3] * a
    512 	}
    513 
    514 	return &ColorM{
    515 		body:      eb,
    516 		translate: et,
    517 	}
    518 }
    519 
    520 // Translate translates the matrix by (r, g, b, a).
    521 func (c *ColorM) Translate(r, g, b, a float32) *ColorM {
    522 	if !c.isInited() {
    523 		return &ColorM{
    524 			translate: []float32{r, g, b, a},
    525 		}
    526 	}
    527 	es := make([]float32, len(colorMIdentityTranslate))
    528 	if c.translate != nil {
    529 		copy(es, c.translate)
    530 	}
    531 	es[0] += r
    532 	es[1] += g
    533 	es[2] += b
    534 	es[3] += a
    535 	return &ColorM{
    536 		body:      c.body,
    537 		translate: es,
    538 	}
    539 }
    540 
    541 var (
    542 	// The YCbCr value ranges are:
    543 	//   Y:  [ 0   - 1  ]
    544 	//   Cb: [-0.5 - 0.5]
    545 	//   Cr: [-0.5 - 0.5]
    546 
    547 	rgbToYCbCr = &ColorM{
    548 		body: []float32{
    549 			0.2990, -0.1687, 0.5000, 0,
    550 			0.5870, -0.3313, -0.4187, 0,
    551 			0.1140, 0.5000, -0.0813, 0,
    552 			0, 0, 0, 1,
    553 		},
    554 	}
    555 	yCbCrToRgb = &ColorM{
    556 		body: []float32{
    557 			1, 1, 1, 0,
    558 			0, -0.34414, 1.77200, 0,
    559 			1.40200, -0.71414, 0, 0,
    560 			0, 0, 0, 1,
    561 		},
    562 	}
    563 )
    564 
    565 // ChangeHSV changes HSV (Hue-Saturation-Value) elements.
    566 // hueTheta is a radian value to ratate hue.
    567 // saturationScale is a value to scale saturation.
    568 // valueScale is a value to scale value (a.k.a. brightness).
    569 //
    570 // This conversion uses RGB to/from YCrCb conversion.
    571 func (c *ColorM) ChangeHSV(hueTheta float64, saturationScale float32, valueScale float32) *ColorM {
    572 	sin, cos := math.Sincos(hueTheta)
    573 	s32, c32 := float32(sin), float32(cos)
    574 	c = c.Concat(rgbToYCbCr)
    575 	c = c.Concat(&ColorM{
    576 		body: []float32{
    577 			1, 0, 0, 0,
    578 			0, c32, s32, 0,
    579 			0, -s32, c32, 0,
    580 			0, 0, 0, 1,
    581 		},
    582 	})
    583 	s := saturationScale
    584 	v := valueScale
    585 	c = c.Scale(v, s*v, s*v, 1)
    586 	c = c.Concat(yCbCrToRgb)
    587 	return c
    588 }