mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +01:00
Add the new package graphics/matrix
This commit is contained in:
parent
773e3afa1d
commit
b430d385bf
@ -17,6 +17,7 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"github.com/hajimehoshi/go.ebiten"
|
"github.com/hajimehoshi/go.ebiten"
|
||||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||||
|
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
@ -116,16 +117,17 @@ func (game *DemoGame) Update() {
|
|||||||
|
|
||||||
func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.TextureID) {
|
func (game *DemoGame) Draw(g graphics.GraphicsContext, offscreen graphics.TextureID) {
|
||||||
g.Fill(&color.RGBA{R: 128, G: 128, B: 255, A: 255})
|
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)
|
tx, ty := float64(game.ebitenTexture.Width), float64(game.ebitenTexture.Height)
|
||||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(-tx/2, -ty/2))
|
geometryMatrix.Translate(-tx/2, -ty/2)
|
||||||
geometryMatrix = geometryMatrix.Concat(graphics.RotateMatrix(float64(game.x) / 60))
|
geometryMatrix.Rotate(float64(game.x) / 60)
|
||||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(tx/2, ty/2))
|
geometryMatrix.Translate(tx/2, ty/2)
|
||||||
geometryMatrix = geometryMatrix.Concat(graphics.TranslateMatrix(100, 100))
|
geometryMatrix.Translate(100, 100)
|
||||||
g.DrawTexture(game.ebitenTexture.ID,
|
g.DrawTexture(game.ebitenTexture.ID,
|
||||||
0, 0, int(tx), int(ty),
|
0, 0, int(tx), int(ty),
|
||||||
geometryMatrix,
|
geometryMatrix,
|
||||||
graphics.IdentityColorMatrix())
|
matrix.IdentityColor())
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
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
|
package graphics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
)
|
)
|
||||||
@ -15,7 +16,7 @@ type GraphicsContext interface {
|
|||||||
Fill(color color.Color)
|
Fill(color color.Color)
|
||||||
DrawTexture(textureId TextureID,
|
DrawTexture(textureId TextureID,
|
||||||
srcX, srcY, srcWidth, srcHeight int,
|
srcX, srcY, srcWidth, srcHeight int,
|
||||||
geometryMatrix *GeometryMatrix, colorMatrix *ColorMatrix)
|
geometryMatrix matrix.Geometry, colorMatrix matrix.Color)
|
||||||
SetOffscreen(textureId TextureID)
|
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 "C"
|
||||||
import (
|
import (
|
||||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||||
|
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Device struct {
|
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)
|
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR)
|
||||||
g.resetOffscreen()
|
g.resetOffscreen()
|
||||||
g.Clear()
|
g.Clear()
|
||||||
geometryMatrix := graphics.IdentityGeometryMatrix()
|
|
||||||
geometryMatrix.SetA(float64(g.screenScale))
|
scale := float64(g.screenScale)
|
||||||
geometryMatrix.SetD(float64(g.screenScale))
|
geometryMatrix := matrix.Geometry{
|
||||||
|
[2][3]float64{
|
||||||
|
{scale, 0, 0},
|
||||||
|
{0, scale, 0},
|
||||||
|
},
|
||||||
|
}
|
||||||
g.DrawTexture(device.offscreenTexture.ID,
|
g.DrawTexture(device.offscreenTexture.ID,
|
||||||
0, 0, device.screenWidth, device.screenHeight,
|
0, 0, device.screenWidth, device.screenHeight,
|
||||||
geometryMatrix, graphics.IdentityColorMatrix())
|
geometryMatrix, matrix.IdentityColor())
|
||||||
g.flush()
|
g.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import "C"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/hajimehoshi/go.ebiten/graphics"
|
"github.com/hajimehoshi/go.ebiten/graphics"
|
||||||
|
"github.com/hajimehoshi/go.ebiten/graphics/matrix"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -67,9 +68,7 @@ func (context *GraphicsContext) DrawRect(x, y, width, height int, clr color.Colo
|
|||||||
func (context *GraphicsContext) DrawTexture(
|
func (context *GraphicsContext) DrawTexture(
|
||||||
textureID graphics.TextureID,
|
textureID graphics.TextureID,
|
||||||
srcX, srcY, srcWidth, srcHeight int,
|
srcX, srcY, srcWidth, srcHeight int,
|
||||||
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||||
geometryMatrix = geometryMatrix.Clone()
|
|
||||||
colorMatrix = colorMatrix.Clone()
|
|
||||||
|
|
||||||
texture := context.textures[textureID]
|
texture := context.textures[textureID]
|
||||||
|
|
||||||
@ -180,7 +179,7 @@ func (context *GraphicsContext) flush() {
|
|||||||
|
|
||||||
// This method should be called on the UI thread.
|
// This method should be called on the UI thread.
|
||||||
func (context *GraphicsContext) setShaderProgram(
|
func (context *GraphicsContext) setShaderProgram(
|
||||||
geometryMatrix *graphics.GeometryMatrix, colorMatrix *graphics.ColorMatrix) {
|
geometryMatrix matrix.Geometry, colorMatrix matrix.Color) {
|
||||||
program := C.GLuint(0)
|
program := C.GLuint(0)
|
||||||
if colorMatrix.IsIdentity() {
|
if colorMatrix.IsIdentity() {
|
||||||
program = regularShaderProgram
|
program = regularShaderProgram
|
||||||
@ -195,12 +194,12 @@ func (context *GraphicsContext) setShaderProgram(
|
|||||||
1, C.GL_FALSE,
|
1, C.GL_FALSE,
|
||||||
(*C.GLfloat)(&context.projectionMatrix[0]))
|
(*C.GLfloat)(&context.projectionMatrix[0]))
|
||||||
|
|
||||||
a := float32(geometryMatrix.A())
|
a := float32(geometryMatrix.Elements[0][0])
|
||||||
b := float32(geometryMatrix.B())
|
b := float32(geometryMatrix.Elements[0][1])
|
||||||
c := float32(geometryMatrix.C())
|
c := float32(geometryMatrix.Elements[1][0])
|
||||||
d := float32(geometryMatrix.D())
|
d := float32(geometryMatrix.Elements[1][1])
|
||||||
tx := float32(geometryMatrix.Tx())
|
tx := float32(geometryMatrix.Elements[0][2])
|
||||||
ty := float32(geometryMatrix.Ty())
|
ty := float32(geometryMatrix.Elements[1][2])
|
||||||
glModelviewMatrix := [...]float32{
|
glModelviewMatrix := [...]float32{
|
||||||
a, c, 0, 0,
|
a, c, 0, 0,
|
||||||
b, d, 0, 0,
|
b, d, 0, 0,
|
||||||
@ -220,7 +219,7 @@ func (context *GraphicsContext) setShaderProgram(
|
|||||||
e := [4][5]float32{}
|
e := [4][5]float32{}
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
for j := 0; j < 5; j++ {
|
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