twitchapon-anim

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

geom.go (4879B)


      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 ebiten
     16 
     17 import (
     18 	"fmt"
     19 	"math"
     20 )
     21 
     22 // GeoMDim is a dimension of a GeoM.
     23 const GeoMDim = 3
     24 
     25 // A GeoM represents a matrix to transform geometry when rendering an image.
     26 //
     27 // The initial value is identity.
     28 type GeoM struct {
     29 	a_1 float64 // The actual 'a' value minus 1
     30 	b   float64
     31 	c   float64
     32 	d_1 float64 // The actual 'd' value minus 1
     33 	tx  float64
     34 	ty  float64
     35 }
     36 
     37 // String returns a string representation of GeoM.
     38 func (g *GeoM) String() string {
     39 	return fmt.Sprintf("[[%f, %f, %f], [%f, %f, %f]]", g.a_1+1, g.b, g.tx, g.c, g.d_1+1, g.ty)
     40 }
     41 
     42 // Reset resets the GeoM as identity.
     43 func (g *GeoM) Reset() {
     44 	g.a_1 = 0
     45 	g.b = 0
     46 	g.c = 0
     47 	g.d_1 = 0
     48 	g.tx = 0
     49 	g.ty = 0
     50 }
     51 
     52 // Apply pre-multiplies a vector (x, y, 1) by the matrix.
     53 // In other words, Apply calculates GeoM * (x, y, 1)^T.
     54 // The return value is x and y values of the result vector.
     55 func (g *GeoM) Apply(x, y float64) (float64, float64) {
     56 	return (g.a_1+1)*x + g.b*y + g.tx, g.c*x + (g.d_1+1)*y + g.ty
     57 }
     58 
     59 func (g *GeoM) elements32() (a, b, c, d, tx, ty float32) {
     60 	return float32(g.a_1) + 1, float32(g.b), float32(g.c), float32(g.d_1) + 1, float32(g.tx), float32(g.ty)
     61 }
     62 
     63 // Element returns a value of a matrix at (i, j).
     64 func (g *GeoM) Element(i, j int) float64 {
     65 	switch {
     66 	case i == 0 && j == 0:
     67 		return g.a_1 + 1
     68 	case i == 0 && j == 1:
     69 		return g.b
     70 	case i == 0 && j == 2:
     71 		return g.tx
     72 	case i == 1 && j == 0:
     73 		return g.c
     74 	case i == 1 && j == 1:
     75 		return g.d_1 + 1
     76 	case i == 1 && j == 2:
     77 		return g.ty
     78 	default:
     79 		panic("ebiten: i or j is out of index")
     80 	}
     81 }
     82 
     83 // Concat multiplies a geometry matrix with the other geometry matrix.
     84 // This is same as muptiplying the matrix other and the matrix g in this order.
     85 func (g *GeoM) Concat(other GeoM) {
     86 	a := (other.a_1+1)*(g.a_1+1) + other.b*g.c
     87 	b := (other.a_1+1)*g.b + other.b*(g.d_1+1)
     88 	tx := (other.a_1+1)*g.tx + other.b*g.ty + other.tx
     89 	c := other.c*(g.a_1+1) + (other.d_1+1)*g.c
     90 	d := other.c*g.b + (other.d_1+1)*(g.d_1+1)
     91 	ty := other.c*g.tx + (other.d_1+1)*g.ty + other.ty
     92 
     93 	g.a_1 = a - 1
     94 	g.b = b
     95 	g.c = c
     96 	g.d_1 = d - 1
     97 	g.tx = tx
     98 	g.ty = ty
     99 }
    100 
    101 // Scale scales the matrix by (x, y).
    102 func (g *GeoM) Scale(x, y float64) {
    103 	a := (g.a_1 + 1) * x
    104 	b := g.b * x
    105 	tx := g.tx * x
    106 	c := g.c * y
    107 	d := (g.d_1 + 1) * y
    108 	ty := g.ty * y
    109 
    110 	g.a_1 = a - 1
    111 	g.b = b
    112 	g.c = c
    113 	g.d_1 = d - 1
    114 	g.tx = tx
    115 	g.ty = ty
    116 }
    117 
    118 // Translate translates the matrix by (tx, ty).
    119 func (g *GeoM) Translate(tx, ty float64) {
    120 	g.tx += tx
    121 	g.ty += ty
    122 }
    123 
    124 // Rotate rotates the matrix by theta.
    125 // The unit is radian.
    126 func (g *GeoM) Rotate(theta float64) {
    127 	if theta == 0 {
    128 		return
    129 	}
    130 
    131 	sin, cos := math.Sincos(theta)
    132 
    133 	a := cos*(g.a_1+1) - sin*g.c
    134 	b := cos*g.b - sin*(g.d_1+1)
    135 	tx := cos*g.tx - sin*g.ty
    136 	c := sin*(g.a_1+1) + cos*g.c
    137 	d := sin*g.b + cos*(g.d_1+1)
    138 	ty := sin*g.tx + cos*g.ty
    139 
    140 	g.a_1 = a - 1
    141 	g.b = b
    142 	g.c = c
    143 	g.d_1 = d - 1
    144 	g.tx = tx
    145 	g.ty = ty
    146 }
    147 
    148 // Skew skews the matrix by (skewX, skewY). The unit is radian.
    149 func (g *GeoM) Skew(skewX, skewY float64) {
    150 	sx := math.Tan(skewX)
    151 	sy := math.Tan(skewY)
    152 
    153 	a := (g.a_1 + 1) + g.c*sx
    154 	b := g.b + (g.d_1+1)*sx
    155 	c := (g.a_1+1)*sy + g.c
    156 	d := g.b*sy + (g.d_1 + 1)
    157 	tx := g.tx + g.ty*sx
    158 	ty := g.ty + g.tx*sy
    159 
    160 	g.a_1 = a - 1
    161 	g.b = b
    162 	g.c = c
    163 	g.d_1 = d - 1
    164 	g.tx = tx
    165 	g.ty = ty
    166 }
    167 
    168 func (g *GeoM) det2x2() float64 {
    169 	return (g.a_1+1)*(g.d_1+1) - g.b*g.c
    170 }
    171 
    172 // IsInvertible returns a boolean value indicating
    173 // whether the matrix g is invertible or not.
    174 func (g *GeoM) IsInvertible() bool {
    175 	return g.det2x2() != 0
    176 }
    177 
    178 // Invert inverts the matrix.
    179 // If g is not invertible, Invert panics.
    180 func (g *GeoM) Invert() {
    181 	det := g.det2x2()
    182 	if det == 0 {
    183 		panic("ebiten: g is not invertible")
    184 	}
    185 
    186 	a := (g.d_1 + 1) / det
    187 	b := -g.b / det
    188 	c := -g.c / det
    189 	d := (g.a_1 + 1) / det
    190 	tx := (-(g.d_1+1)*g.tx + g.b*g.ty) / det
    191 	ty := (g.c*g.tx + -(g.a_1+1)*g.ty) / det
    192 
    193 	g.a_1 = a - 1
    194 	g.b = b
    195 	g.c = c
    196 	g.d_1 = d - 1
    197 	g.tx = tx
    198 	g.ty = ty
    199 }
    200 
    201 // SetElement sets an element at (i, j).
    202 func (g *GeoM) SetElement(i, j int, element float64) {
    203 	e := element
    204 	switch {
    205 	case i == 0 && j == 0:
    206 		g.a_1 = e - 1
    207 	case i == 0 && j == 1:
    208 		g.b = e
    209 	case i == 0 && j == 2:
    210 		g.tx = e
    211 	case i == 1 && j == 0:
    212 		g.c = e
    213 	case i == 1 && j == 1:
    214 		g.d_1 = e - 1
    215 	case i == 1 && j == 2:
    216 		g.ty = e
    217 	default:
    218 		panic("ebiten: i or j is out of index")
    219 	}
    220 }