mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 10:48:53 +01:00
Add the new package graphics/matrix
This commit is contained in:
parent
773e3afa1d
commit
b430d385bf
@ -17,6 +17,7 @@ import "C"
|
||||
import (
|
||||
"github.com/hajimehoshi/go.ebiten"
|
||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||
"image"
|
||||
"image/color"
|
||||
_ "image/png"
|
||||
@ -116,16 +117,17 @@ func (game *DemoGame) Update() {
|
||||
|
||||
func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.TextureID) {
|
||||
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
|
||||
geometryMatrix := graphics.IdentityGeometryMatrix()
|
||||
|
||||
geometryMatrix := matrix.IdentityGeometry()
|
||||
tx, ty := float64(game.ebitenTexture.Width), float64(game.ebitenTexture.Height)
|
||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(-tx/2, -ty/2))
|
||||
geometryMatrix = geometryMatrix.Concat(graphics.RotateMatrix(float64(game.x) / 60))
|
||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(tx/2, ty/2))
|
||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(100, 100))
|
||||
geometryMatrix.Translate(-tx/2, -ty/2)
|
||||
geometryMatrix.Rotate(float64(game.x) / 60)
|
||||
geometryMatrix.Translate(tx/2, ty/2)
|
||||
geometryMatrix.Translate(100, 100)
|
||||
g.DrawTexture(game.ebitenTexture.ID,
|
||||
0, 0, int(tx), int(ty),
|
||||
geometryMatrix,
|
||||
graphics.IdentityColorMatrix())
|
||||
matrix.IdentityColor())
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
@ -1,112 +0,0 @@
|
||||
package graphics
|
||||
|
||||
type affineMatrixElement float64
|
||||
|
||||
type AffineMatrix struct {
|
||||
elements []affineMatrixElement
|
||||
dimension int
|
||||
}
|
||||
|
||||
func NewAffineMatrix(dimension int) *AffineMatrix {
|
||||
if dimension < 0 {
|
||||
panic("invalid dimension")
|
||||
}
|
||||
matrix := &AffineMatrix{}
|
||||
elementsNumber := dimension * (dimension - 1)
|
||||
matrix.elements = make([]affineMatrixElement, elementsNumber)
|
||||
matrix.dimension = dimension
|
||||
return matrix
|
||||
}
|
||||
|
||||
func IdentityAffineMatrix(dimension int) *AffineMatrix {
|
||||
if dimension < 0 {
|
||||
panic("invalid dimension")
|
||||
}
|
||||
matrix := NewAffineMatrix(dimension)
|
||||
for i := 0; i < dimension-1; i++ {
|
||||
for j := 0; j < dimension; j++ {
|
||||
if i == j {
|
||||
matrix.elements[i*dimension+j] = 1
|
||||
} else {
|
||||
matrix.elements[i*dimension+j] = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return matrix
|
||||
}
|
||||
|
||||
func (matrix *AffineMatrix) Clone() *AffineMatrix {
|
||||
result := NewAffineMatrix(matrix.dimension)
|
||||
copy(result.elements, matrix.elements)
|
||||
return result
|
||||
}
|
||||
|
||||
func (matrix *AffineMatrix) Element(i, j int) float64 {
|
||||
dimension := matrix.dimension
|
||||
if i < 0 || dimension <= i {
|
||||
panic("out of range index i")
|
||||
}
|
||||
if j < 0 || dimension <= j {
|
||||
panic("out of range index j")
|
||||
}
|
||||
if i == dimension-1 {
|
||||
if j == dimension-1 {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
return float64(matrix.elements[i*dimension+j])
|
||||
}
|
||||
|
||||
func (matrix *AffineMatrix) SetElement(i, j int, element float64) {
|
||||
dimension := matrix.dimension
|
||||
if i < 0 || dimension-1 <= i {
|
||||
panic("out of range index i")
|
||||
}
|
||||
if j < 0 || dimension <= j {
|
||||
panic("out of range index j")
|
||||
}
|
||||
matrix.elements[i*dimension+j] = affineMatrixElement(element)
|
||||
}
|
||||
|
||||
func (matrix *AffineMatrix) IsIdentity() bool {
|
||||
dimension := matrix.dimension
|
||||
for i := 0; i < dimension-1; i++ {
|
||||
for j := 0; j < dimension; j++ {
|
||||
element := matrix.elements[i*dimension+j]
|
||||
if i == j && element != 1 {
|
||||
return false
|
||||
} else if i != j && element != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: The arguments' names are strange even though they are not wrong.
|
||||
*/
|
||||
func (rhs *AffineMatrix) Concat(lhs *AffineMatrix) *AffineMatrix {
|
||||
dimension := lhs.dimension
|
||||
if dimension != rhs.dimension {
|
||||
panic("diffrent-sized matrices can't be concatenated")
|
||||
}
|
||||
result := NewAffineMatrix(dimension)
|
||||
|
||||
for i := 0; i < dimension-1; i++ {
|
||||
for j := 0; j < dimension; j++ {
|
||||
element := affineMatrixElement(0.0)
|
||||
for k := 0; k < dimension-1; k++ {
|
||||
element += lhs.elements[i*dimension+k] *
|
||||
rhs.elements[k*dimension+j]
|
||||
}
|
||||
if j == dimension-1 {
|
||||
element += lhs.elements[i*dimension+dimension-1]
|
||||
}
|
||||
result.elements[i*dimension+j] = element
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
package graphics_test
|
||||
|
||||
import (
|
||||
. "."
|
||||
"testing"
|
||||
)
|
||||
|
||||
func setElements(matrix *AffineMatrix, elements [][]float64) {
|
||||
dimension := len(elements) + 1
|
||||
for i := 0; i < dimension-1; i++ {
|
||||
for j := 0; j < dimension; j++ {
|
||||
matrix.SetElement(i, j, elements[i][j])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffineMatrixElement(t *testing.T) {
|
||||
matrix := NewAffineMatrix(4)
|
||||
matrix.SetElement(0, 0, 1)
|
||||
matrix.SetElement(0, 1, 2)
|
||||
matrix.SetElement(0, 2, 3)
|
||||
expected := [][]float64{
|
||||
{1, 2, 3, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{0, 0, 0, 1},
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
got := matrix.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix.SetElement(1, 0, 4)
|
||||
matrix.SetElement(1, 1, 5)
|
||||
matrix.SetElement(2, 3, 6)
|
||||
expected = [][]float64{
|
||||
{1, 2, 3, 0},
|
||||
{4, 5, 0, 0},
|
||||
{0, 0, 0, 6},
|
||||
{0, 0, 0, 1},
|
||||
}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
got := matrix.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffineMatrixIsIdentity(t *testing.T) {
|
||||
matrix := NewAffineMatrix(4)
|
||||
matrix.SetElement(0, 0, 1)
|
||||
matrix.SetElement(1, 1, 1)
|
||||
matrix.SetElement(2, 2, 1)
|
||||
got := matrix.IsIdentity()
|
||||
want := true
|
||||
if want != got {
|
||||
t.Errorf("matrix.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
|
||||
matrix2 := matrix.Clone()
|
||||
got = matrix2.IsIdentity()
|
||||
want = true
|
||||
if want != got {
|
||||
t.Errorf("matrix2.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
|
||||
matrix2.SetElement(0, 1, 1)
|
||||
got = matrix2.IsIdentity()
|
||||
want = false
|
||||
if want != got {
|
||||
t.Errorf("matrix2.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAffineMatrixConcat(t *testing.T) {
|
||||
matrix1 := IdentityAffineMatrix(3)
|
||||
matrix2 := IdentityAffineMatrix(3)
|
||||
setElements(matrix1, [][]float64{
|
||||
{2, 0, 0},
|
||||
{0, 2, 0},
|
||||
})
|
||||
setElements(matrix2, [][]float64{
|
||||
{1, 0, 1},
|
||||
{0, 1, 1},
|
||||
})
|
||||
|
||||
// TODO: 'matrix1x2' may not be a good name.
|
||||
matrix1x2 := matrix1.Concat(matrix2)
|
||||
expected := [][]float64{
|
||||
{2, 0, 1},
|
||||
{0, 2, 1},
|
||||
{0, 0, 1},
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
got := matrix1x2.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix1x2.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix2x1 := matrix2.Concat(matrix1)
|
||||
expected = [][]float64{
|
||||
{2, 0, 2},
|
||||
{0, 2, 2},
|
||||
{0, 0, 1},
|
||||
}
|
||||
for i := 0; i < 3; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
got := matrix2x1.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix2x1.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix3 := NewAffineMatrix(4)
|
||||
matrix4 := NewAffineMatrix(4)
|
||||
setElements(matrix3, [][]float64{
|
||||
{1, 2, 3, 4},
|
||||
{5, 6, 7, 8},
|
||||
{9, 10, 11, 12},
|
||||
})
|
||||
setElements(matrix4, [][]float64{
|
||||
{13, 14, 15, 16},
|
||||
{17, 18, 19, 20},
|
||||
{21, 22, 23, 24},
|
||||
})
|
||||
|
||||
matrix3x4 := matrix3.Concat(matrix4)
|
||||
expected = [][]float64{
|
||||
{218, 260, 302, 360},
|
||||
{278, 332, 386, 460},
|
||||
{338, 404, 470, 560},
|
||||
{0, 0, 0, 1}}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
got := matrix3x4.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix3x4.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix4x3 := matrix4.Concat(matrix3)
|
||||
expected = [][]float64{
|
||||
{110, 116, 122, 132},
|
||||
{314, 332, 350, 376},
|
||||
{518, 548, 578, 620},
|
||||
{0, 0, 0, 1}}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
got := matrix4x3.Element(i, j)
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix4x3.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
package graphics
|
||||
|
||||
type ColorMatrix struct {
|
||||
AffineMatrix
|
||||
}
|
||||
|
||||
const colorMatrixDimension = 5
|
||||
|
||||
func NewColorMatrix() *ColorMatrix {
|
||||
return &ColorMatrix{*NewAffineMatrix(colorMatrixDimension)}
|
||||
}
|
||||
|
||||
func IdentityColorMatrix() *ColorMatrix {
|
||||
return &ColorMatrix{*IdentityAffineMatrix(colorMatrixDimension)}
|
||||
}
|
||||
|
||||
func (matrix *ColorMatrix) Concat(other *ColorMatrix) *ColorMatrix {
|
||||
return &ColorMatrix{*matrix.AffineMatrix.Concat(&other.AffineMatrix)}
|
||||
}
|
||||
|
||||
func (matrix *ColorMatrix) Clone() *ColorMatrix {
|
||||
return &ColorMatrix{*(matrix.AffineMatrix.Clone())}
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
package graphics
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type GeometryMatrix struct {
|
||||
AffineMatrix
|
||||
}
|
||||
|
||||
const geometryMatrixDimension = 3
|
||||
|
||||
func NewGeometryMatrix() *GeometryMatrix {
|
||||
return &GeometryMatrix{*NewAffineMatrix(geometryMatrixDimension)}
|
||||
}
|
||||
|
||||
func IdentityGeometryMatrix() *GeometryMatrix {
|
||||
return &GeometryMatrix{*IdentityAffineMatrix(geometryMatrixDimension)}
|
||||
}
|
||||
|
||||
func TranslateMatrix(tx, ty float64) *GeometryMatrix {
|
||||
matrix := IdentityGeometryMatrix()
|
||||
matrix.SetTx(tx)
|
||||
matrix.SetTy(ty)
|
||||
return matrix
|
||||
}
|
||||
|
||||
func RotateMatrix(theta float64) *GeometryMatrix {
|
||||
matrix := NewGeometryMatrix()
|
||||
cos, sin := math.Cos(theta), math.Sin(theta)
|
||||
matrix.SetA(cos)
|
||||
matrix.SetB(-sin)
|
||||
matrix.SetC(sin)
|
||||
matrix.SetD(cos)
|
||||
return matrix
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) Concat(other *GeometryMatrix) *GeometryMatrix {
|
||||
return &GeometryMatrix{*matrix.AffineMatrix.Concat(&other.AffineMatrix)}
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) Clone() *GeometryMatrix {
|
||||
return &GeometryMatrix{*(matrix.AffineMatrix.Clone())}
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) A() float64 {
|
||||
return matrix.Element(0, 0)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) B() float64 {
|
||||
return matrix.Element(0, 1)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) C() float64 {
|
||||
return matrix.Element(1, 0)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) D() float64 {
|
||||
return matrix.Element(1, 1)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) Tx() float64 {
|
||||
return matrix.Element(0, 2)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) Ty() float64 {
|
||||
return matrix.Element(1, 2)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetA(a float64) {
|
||||
matrix.SetElement(0, 0, a)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetB(b float64) {
|
||||
matrix.SetElement(0, 1, b)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetC(c float64) {
|
||||
matrix.SetElement(1, 0, c)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetD(d float64) {
|
||||
matrix.SetElement(1, 1, d)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetTx(tx float64) {
|
||||
matrix.SetElement(0, 2, tx)
|
||||
}
|
||||
|
||||
func (matrix *GeometryMatrix) SetTy(ty float64) {
|
||||
matrix.SetElement(1, 2, ty)
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
package graphics_test
|
||||
|
||||
import (
|
||||
. "."
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGeometryMatrixElements(t *testing.T) {
|
||||
matrix := NewGeometryMatrix()
|
||||
matrix.SetA(1)
|
||||
matrix.SetB(2)
|
||||
matrix.SetC(3)
|
||||
matrix.SetD(4)
|
||||
matrix.SetTx(5)
|
||||
matrix.SetTy(6)
|
||||
|
||||
got := matrix.A()
|
||||
want := float64(1)
|
||||
if want != got {
|
||||
t.Errorf("matrix.A() = %f, want %f", got, want)
|
||||
}
|
||||
|
||||
got = matrix.B()
|
||||
want = float64(2)
|
||||
if want != got {
|
||||
t.Errorf("matrix.B() = %f, want %f", got, want)
|
||||
}
|
||||
|
||||
got = matrix.C()
|
||||
want = float64(3)
|
||||
if want != got {
|
||||
t.Errorf("matrix.C() = %f, want %f", got, want)
|
||||
}
|
||||
|
||||
got = matrix.D()
|
||||
want = float64(4)
|
||||
if want != got {
|
||||
t.Errorf("matrix.D() = %f, want %f", got, want)
|
||||
}
|
||||
|
||||
got = matrix.Tx()
|
||||
want = float64(5)
|
||||
if want != got {
|
||||
t.Errorf("matrix.Tx() = %f, want %f", got, want)
|
||||
}
|
||||
|
||||
got = matrix.Ty()
|
||||
want = float64(6)
|
||||
if want != got {
|
||||
t.Errorf("matrix.Ty() = %f, want %f", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeometryIdentity(t *testing.T) {
|
||||
matrix := IdentityGeometryMatrix()
|
||||
got := matrix.IsIdentity()
|
||||
want := true
|
||||
if want != got {
|
||||
t.Errorf("matrix.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package graphics
|
||||
|
||||
import (
|
||||
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||
"image"
|
||||
"image/color"
|
||||
)
|
||||
@ -15,7 +16,7 @@ type GraphicsContext interface {
|
||||
Fill(color color.Color)
|
||||
DrawTexture(textureId TextureID,
|
||||
srcX, srcY, srcWidth, srcHeight int,
|
||||
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix)
|
||||
geometryMatrix matrix.Geometry, colorMatrix matrix.Color)
|
||||
SetOffscreen(textureId TextureID)
|
||||
}
|
||||
|
||||
|
43
graphics/matrix/affine.go
Normal file
43
graphics/matrix/affine.go
Normal file
@ -0,0 +1,43 @@
|
||||
package matrix
|
||||
|
||||
type Affine interface {
|
||||
Dim() int
|
||||
element(i, j int) float64
|
||||
setElement(i, j int, element float64)
|
||||
}
|
||||
|
||||
func isIdentity(matrix Affine) bool {
|
||||
dim := matrix.Dim()
|
||||
for i := 0; i < dim-1; i++ {
|
||||
for j := 0; j < dim; j++ {
|
||||
element := matrix.element(i, j)
|
||||
if i == j && element != 1 {
|
||||
return false
|
||||
} else if i != j && element != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func mul(lhs, rhs, result Affine) {
|
||||
dim := lhs.Dim()
|
||||
if dim != rhs.Dim() {
|
||||
panic("diffrent-sized matrices can't be multiplied")
|
||||
}
|
||||
|
||||
for i := 0; i < dim-1; i++ {
|
||||
for j := 0; j < dim; j++ {
|
||||
element := float64(0)
|
||||
for k := 0; k < dim-1; k++ {
|
||||
element += lhs.element(i, k) *
|
||||
rhs.element(k, j)
|
||||
}
|
||||
if j == dim-1 {
|
||||
element += lhs.element(i, j)
|
||||
}
|
||||
result.setElement(i, j, element)
|
||||
}
|
||||
}
|
||||
}
|
3
graphics/matrix/affine_test.go
Normal file
3
graphics/matrix/affine_test.go
Normal file
@ -0,0 +1,3 @@
|
||||
package matrix_test
|
||||
|
||||
|
40
graphics/matrix/color.go
Normal file
40
graphics/matrix/color.go
Normal file
@ -0,0 +1,40 @@
|
||||
package matrix
|
||||
|
||||
const colorDim = 5
|
||||
|
||||
type Color struct {
|
||||
Elements [colorDim - 1][colorDim]float64
|
||||
}
|
||||
|
||||
func IdentityColor() Color {
|
||||
return Color{
|
||||
[colorDim - 1][colorDim]float64{
|
||||
{1, 0, 0, 0, 0},
|
||||
{0, 1, 0, 0, 0},
|
||||
{0, 0, 1, 0, 0},
|
||||
{0, 0, 0, 1, 0},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (matrix *Color) Dim() int {
|
||||
return colorDim
|
||||
}
|
||||
|
||||
func (matrix *Color) Concat(other Color) {
|
||||
result := Color{}
|
||||
mul(&other, matrix, &result)
|
||||
*matrix = result
|
||||
}
|
||||
|
||||
func (matrix *Color) IsIdentity() bool {
|
||||
return isIdentity(matrix)
|
||||
}
|
||||
|
||||
func (matrix *Color) element(i, j int) float64 {
|
||||
return matrix.Elements[i][j]
|
||||
}
|
||||
|
||||
func (matrix *Color) setElement(i, j int, element float64) {
|
||||
matrix.Elements[i][j] = element
|
||||
}
|
15
graphics/matrix/color_test.go
Normal file
15
graphics/matrix/color_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package matrix_test
|
||||
|
||||
import (
|
||||
. "."
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestColorIdentity(t *testing.T) {
|
||||
matrix := IdentityColor()
|
||||
got := matrix.IsIdentity()
|
||||
want := true
|
||||
if want != got {
|
||||
t.Errorf("matrix.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
}
|
59
graphics/matrix/geometry.go
Normal file
59
graphics/matrix/geometry.go
Normal file
@ -0,0 +1,59 @@
|
||||
package matrix
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
const geometryDim = 3
|
||||
|
||||
type Geometry struct {
|
||||
Elements [geometryDim - 1][geometryDim]float64
|
||||
}
|
||||
|
||||
func IdentityGeometry() Geometry {
|
||||
return Geometry{
|
||||
[geometryDim - 1][geometryDim]float64{
|
||||
{1, 0, 0},
|
||||
{0, 1, 0},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (matrix *Geometry) Dim() int {
|
||||
return geometryDim
|
||||
}
|
||||
|
||||
func (matrix *Geometry) Concat(other Geometry) {
|
||||
result := Geometry{}
|
||||
mul(&other, matrix, &result)
|
||||
*matrix = result
|
||||
}
|
||||
|
||||
func (matrix *Geometry) IsIdentity() bool {
|
||||
return isIdentity(matrix)
|
||||
}
|
||||
|
||||
func (matrix *Geometry) element(i, j int) float64 {
|
||||
return matrix.Elements[i][j]
|
||||
}
|
||||
|
||||
func (matrix *Geometry) setElement(i, j int, element float64) {
|
||||
matrix.Elements[i][j] = element
|
||||
}
|
||||
|
||||
func (matrix *Geometry) Translate(tx, ty float64) {
|
||||
matrix.Elements[0][2] += tx
|
||||
matrix.Elements[1][2] += ty
|
||||
}
|
||||
|
||||
func (matrix *Geometry) Rotate(theta float64) {
|
||||
cos := math.Cos(theta)
|
||||
sin := math.Sin(theta)
|
||||
rotate := Geometry{
|
||||
[2][3]float64{
|
||||
{cos, -sin, 0},
|
||||
{sin, cos, 0},
|
||||
},
|
||||
}
|
||||
matrix.Concat(rotate)
|
||||
}
|
63
graphics/matrix/geometry_test.go
Normal file
63
graphics/matrix/geometry_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package matrix_test
|
||||
|
||||
import (
|
||||
. "."
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGeometryIdentity(t *testing.T) {
|
||||
matrix := IdentityGeometry()
|
||||
got := matrix.IsIdentity()
|
||||
want := true
|
||||
if want != got {
|
||||
t.Errorf("matrix.IsIdentity() = %t, want %t", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGeometryConcat(t *testing.T) {
|
||||
matrix1 := Geometry{}
|
||||
matrix2 := Geometry{}
|
||||
matrix1.Elements = [2][3]float64{
|
||||
{2, 0, 0},
|
||||
{0, 2, 0},
|
||||
}
|
||||
matrix2.Elements = [2][3]float64{
|
||||
{1, 0, 1},
|
||||
{0, 1, 1},
|
||||
}
|
||||
|
||||
// TODO: 'matrix1x2' may not be a good name.
|
||||
matrix1x2 := matrix1
|
||||
matrix1x2.Concat(matrix2)
|
||||
expected := [][]float64{
|
||||
{2, 0, 1},
|
||||
{0, 2, 1},
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
got := matrix1x2.Elements[i][j]
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix1x2.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matrix2x1 := matrix2
|
||||
matrix2x1.Concat(matrix1)
|
||||
expected = [][]float64{
|
||||
{2, 0, 2},
|
||||
{0, 2, 2},
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
for j := 0; j < 3; j++ {
|
||||
got := matrix2x1.Elements[i][j]
|
||||
want := expected[i][j]
|
||||
if want != got {
|
||||
t.Errorf("matrix2x1.Element(%d, %d) = %f, want %f",
|
||||
i, j, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ package opengl
|
||||
import "C"
|
||||
import (
|
||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||
)
|
||||
|
||||
type Device struct {
|
||||
@ -46,12 +47,17 @@ func (device *Device) Update() {
|
||||
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR)
|
||||
g.resetOffscreen()
|
||||
g.Clear()
|
||||
geometryMatrix := graphics.IdentityGeometryMatrix()
|
||||
geometryMatrix.SetA(float64(g.screenScale))
|
||||
geometryMatrix.SetD(float64(g.screenScale))
|
||||
|
||||
scale := float64(g.screenScale)
|
||||
geometryMatrix := matrix.Geometry{
|
||||
[2][3]float64{
|
||||
{scale, 0, 0},
|
||||
{0, scale, 0},
|
||||
},
|
||||
}
|
||||
g.DrawTexture(device.offscreenTexture.ID,
|
||||
0, 0, device.screenWidth, device.screenHeight,
|
||||
geometryMatrix, graphics.IdentityColorMatrix())
|
||||
geometryMatrix, matrix.IdentityColor())
|
||||
g.flush()
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||
"image"
|
||||
"image/color"
|
||||
"unsafe"
|
||||
@ -67,9 +68,7 @@ func (context *GraphicsContext) DrawRect(x, y, width, height int, clr color.Colo
|
||||
func (context *GraphicsContext) DrawTexture(
|
||||
textureID graphics.TextureID,
|
||||
srcX, srcY, srcWidth, srcHeight int,
|
||||
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
||||
geometryMatrix = geometryMatrix.Clone()
|
||||
colorMatrix = colorMatrix.Clone()
|
||||
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||
|
||||
texture := context.textures[textureID]
|
||||
|
||||
@ -180,7 +179,7 @@ func (context *GraphicsContext) flush() {
|
||||
|
||||
// This method should be called on the UI thread.
|
||||
func (context *GraphicsContext) setShaderProgram(
|
||||
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
||||
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||
program := C.GLuint(0)
|
||||
if colorMatrix.IsIdentity() {
|
||||
program = regularShaderProgram
|
||||
@ -195,12 +194,12 @@ func (context *GraphicsContext) setShaderProgram(
|
||||
1, C.GL_FALSE,
|
||||
(*C.GLfloat)(&context.projectionMatrix[0]))
|
||||
|
||||
a := float32(geometryMatrix.A())
|
||||
b := float32(geometryMatrix.B())
|
||||
c := float32(geometryMatrix.C())
|
||||
d := float32(geometryMatrix.D())
|
||||
tx := float32(geometryMatrix.Tx())
|
||||
ty := float32(geometryMatrix.Ty())
|
||||
a := float32(geometryMatrix.Elements[0][0])
|
||||
b := float32(geometryMatrix.Elements[0][1])
|
||||
c := float32(geometryMatrix.Elements[1][0])
|
||||
d := float32(geometryMatrix.Elements[1][1])
|
||||
tx := float32(geometryMatrix.Elements[0][2])
|
||||
ty := float32(geometryMatrix.Elements[1][2])
|
||||
glModelviewMatrix := [...]float32{
|
||||
a, c, 0, 0,
|
||||
b, d, 0, 0,
|
||||
@ -220,7 +219,7 @@ func (context *GraphicsContext) setShaderProgram(
|
||||
e := [4][5]float32{}
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
e[i][j] = float32(colorMatrix.Element(i, j))
|
||||
e[i][j] = float32(colorMatrix.Elements[i][j])
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user