replace Transform by much simpler Matrix
This commit is contained in:
parent
1083ca720d
commit
f0394ec7d1
35
batch.go
35
batch.go
|
@ -3,9 +3,8 @@ package pixel
|
|||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
)
|
||||
|
||||
// Batch is a Target that allows for efficient drawing of many objects with the same Picture (but
|
||||
|
@ -16,7 +15,7 @@ import (
|
|||
type Batch struct {
|
||||
cont Drawer
|
||||
|
||||
mat mgl32.Mat3
|
||||
mat Matrix
|
||||
col NRGBA
|
||||
}
|
||||
|
||||
|
@ -45,9 +44,9 @@ func (b *Batch) Draw(t Target) {
|
|||
b.cont.Draw(t)
|
||||
}
|
||||
|
||||
// SetTransform sets transforms used in the following draws onto the Batch.
|
||||
func (b *Batch) SetTransform(t ...Transform) {
|
||||
b.mat = transformToMat(t...)
|
||||
// SetMatrix sets a Matrix that every point will be projected by.
|
||||
func (b *Batch) SetMatrix(m Matrix) {
|
||||
b.mat = m
|
||||
}
|
||||
|
||||
// SetColorMask sets a mask color used in the following draws onto the Batch.
|
||||
|
@ -74,10 +73,12 @@ func (b *Batch) MakeTriangles(t Triangles) TargetTriangles {
|
|||
|
||||
// MakePicture returns a specialized copy of the provided Picture that draws onto this Batch.
|
||||
func (b *Batch) MakePicture(p Picture) TargetPicture {
|
||||
return &batchPicture{
|
||||
bp := &batchPicture{
|
||||
Picture: p,
|
||||
b: b,
|
||||
}
|
||||
bp.original = bp
|
||||
return bp
|
||||
}
|
||||
|
||||
type batchTriangles struct {
|
||||
|
@ -89,15 +90,17 @@ type batchTriangles struct {
|
|||
|
||||
func (bt *batchTriangles) draw(bp *batchPicture) {
|
||||
for i := range *bt.trans {
|
||||
transPos := bt.b.mat.Mul3x1(mgl32.Vec3{
|
||||
float32((*bt.orig)[i].Position.X()),
|
||||
float32((*bt.orig)[i].Position.Y()),
|
||||
transPos := mgl64.Mat3(bt.b.mat).Mul3x1(mgl64.Vec3{
|
||||
(*bt.orig)[i].Position.X(),
|
||||
(*bt.orig)[i].Position.Y(),
|
||||
1,
|
||||
})
|
||||
(*bt.trans)[i].Position = V(float64(transPos.X()), float64(transPos.Y()))
|
||||
(*bt.trans)[i].Color = (*bt.orig)[i].Color.Mul(bt.b.col)
|
||||
(*bt.trans)[i].Picture = (*bt.orig)[i].Picture
|
||||
(*bt.trans)[i].Intensity = (*bt.orig)[i].Intensity
|
||||
if bp == nil {
|
||||
(*bt.trans)[i].Picture = V(math.Inf(+1), math.Inf(+1))
|
||||
(*bt.trans)[i].Intensity = 0
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -116,15 +119,21 @@ func (bt *batchTriangles) Draw() {
|
|||
type batchPicture struct {
|
||||
Picture
|
||||
|
||||
b *Batch
|
||||
original *batchPicture
|
||||
b *Batch
|
||||
}
|
||||
|
||||
func (bp *batchPicture) Slice(r Rect) Picture {
|
||||
return &batchPicture{
|
||||
Picture: bp.Picture.Slice(r),
|
||||
Picture: bp.Picture.Slice(r),
|
||||
original: bp.original,
|
||||
}
|
||||
}
|
||||
|
||||
func (bp *batchPicture) Original() Picture {
|
||||
return bp.original
|
||||
}
|
||||
|
||||
func (bp *batchPicture) Draw(t TargetTriangles) {
|
||||
bt := t.(*batchTriangles)
|
||||
if bp.b != bt.b {
|
||||
|
|
62
geometry.go
62
geometry.go
|
@ -4,6 +4,8 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/cmplx"
|
||||
|
||||
"github.com/go-gl/mathgl/mgl64"
|
||||
)
|
||||
|
||||
// Vec is a 2D vector type. It is unusually implemented as complex128 for convenience. Since
|
||||
|
@ -175,3 +177,63 @@ func (r Rect) Contains(u Vec) bool {
|
|||
min, max := r.Pos, r.Pos+r.Size
|
||||
return min.X() <= u.X() && u.X() <= max.X() && min.Y() <= u.Y() && u.Y() <= max.Y()
|
||||
}
|
||||
|
||||
// Matrix is a 3x3 transformation matrix that can be used for all kinds of spacial transforms, such
|
||||
// as movement, scaling and rotations.
|
||||
//
|
||||
// Matrix has a handful of useful methods, each of which adds a transformation to the matrix. For
|
||||
// example:
|
||||
//
|
||||
// pixel.ZM.Move(pixel.V(100, 200)).Rotate(0, math.Pi/2)
|
||||
//
|
||||
// This code creates a Matrix that first moves everything by 100 units horizontaly and 200 units
|
||||
// vertically and then rotates everything by 90 degrees around the origin.
|
||||
type Matrix [9]float64
|
||||
|
||||
// ZM stands for Zero-Matrix which is the identity matrix. Does nothing, no transformation.
|
||||
var ZM = Matrix(mgl64.Ident3())
|
||||
|
||||
// Move moves everything by the delta vector.
|
||||
func (m Matrix) Move(delta Vec) Matrix {
|
||||
m3 := mgl64.Mat3(m)
|
||||
m3 = mgl64.Translate2D(delta.XY()).Mul3(m3)
|
||||
return Matrix(m3)
|
||||
}
|
||||
|
||||
// ScaleXY scales everything around a given point by the scale factor in each axis respectively.
|
||||
func (m Matrix) ScaleXY(around Vec, scale Vec) Matrix {
|
||||
m3 := mgl64.Mat3(m)
|
||||
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3)
|
||||
m3 = mgl64.Scale2D(scale.XY()).Mul3(m3)
|
||||
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
|
||||
return Matrix(m3)
|
||||
}
|
||||
|
||||
// Scale scales everything around a given point by the scale factor.
|
||||
func (m Matrix) Scale(around Vec, scale float64) Matrix {
|
||||
return m.ScaleXY(around, V(scale, scale))
|
||||
}
|
||||
|
||||
// Rotate rotates everything around a given point by the given angle in radians.
|
||||
func (m Matrix) Rotate(around Vec, angle float64) Matrix {
|
||||
m3 := mgl64.Mat3(m)
|
||||
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3)
|
||||
m3 = mgl64.Rotate3DZ(angle).Mul3(m3)
|
||||
m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
|
||||
return Matrix(m3)
|
||||
}
|
||||
|
||||
// Project applies all transformations added to the Matrix to a vector u and returns the result.
|
||||
func (m Matrix) Project(u Vec) Vec {
|
||||
m3 := mgl64.Mat3(m)
|
||||
proj := m3.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1})
|
||||
return V(proj.X(), proj.Y())
|
||||
}
|
||||
|
||||
// Unproject does the inverse operation to Project.
|
||||
func (m Matrix) Unproject(u Vec) Vec {
|
||||
m3 := mgl64.Mat3(m)
|
||||
inv := m3.Inv()
|
||||
unproj := inv.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1})
|
||||
return V(unproj.X(), unproj.Y())
|
||||
}
|
||||
|
|
|
@ -29,11 +29,10 @@ type Target interface {
|
|||
type BasicTarget interface {
|
||||
Target
|
||||
|
||||
// SetTransform sets a Transform that transforms the TrianglesPosition property of all
|
||||
// Triangles.
|
||||
SetTransform(...Transform)
|
||||
// SetMatrix sets a Matrix that every point will be projected by.
|
||||
SetMatrix(Matrix)
|
||||
|
||||
// SetMColorMask sets a color that will be multiplied with the TrianglesColor property of all
|
||||
// SetColorMask sets a color that will be multiplied with the TrianglesColor property of all
|
||||
// Triangles.
|
||||
SetColorMask(color.Color)
|
||||
}
|
||||
|
|
|
@ -116,9 +116,11 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
|
|||
return cp
|
||||
}
|
||||
|
||||
// SetTransform sets a set of Transforms that every position in triangles will be put through.
|
||||
func (c *Canvas) SetTransform(t ...pixel.Transform) {
|
||||
c.mat = transformToMat(t...)
|
||||
// SetMatrix sets a Matrix that every point will be projected by.
|
||||
func (c *Canvas) SetMatrix(m pixel.Matrix) {
|
||||
for i := range m {
|
||||
c.mat[i] = float32(m[i])
|
||||
}
|
||||
}
|
||||
|
||||
// SetColorMask sets a color that every color in triangles or a picture will be multiplied by.
|
||||
|
|
|
@ -4,17 +4,8 @@ import (
|
|||
"math"
|
||||
|
||||
"github.com/faiface/pixel"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
func transformToMat(t ...pixel.Transform) mgl32.Mat3 {
|
||||
mat := mgl32.Ident3()
|
||||
for i := range t {
|
||||
mat = mat.Mul3(t[i].Mat())
|
||||
}
|
||||
return mat
|
||||
}
|
||||
|
||||
func discreteBounds(bounds pixel.Rect) (x, y, w, h int) {
|
||||
x0 := int(math.Floor(bounds.Pos.X()))
|
||||
y0 := int(math.Floor(bounds.Pos.Y()))
|
||||
|
|
|
@ -377,11 +377,9 @@ func (w *Window) MakePicture(p pixel.Picture) pixel.TargetPicture {
|
|||
return w.canvas.MakePicture(p)
|
||||
}
|
||||
|
||||
// SetTransform sets a global transformation matrix for the Window.
|
||||
//
|
||||
// Transforms are applied right-to-left.
|
||||
func (w *Window) SetTransform(t ...pixel.Transform) {
|
||||
w.canvas.SetTransform(t...)
|
||||
// SetMatrix sets a Matrix that every point will be projected by.
|
||||
func (w *Window) SetMatrix(m pixel.Matrix) {
|
||||
w.canvas.SetMatrix(m)
|
||||
}
|
||||
|
||||
// SetColorMask sets a global color mask for the Window.
|
||||
|
|
190
transform.go
190
transform.go
|
@ -1,190 +0,0 @@
|
|||
package pixel
|
||||
|
||||
import "github.com/go-gl/mathgl/mgl32"
|
||||
|
||||
// Transform holds space transformation information. Concretely, a transformation is specified
|
||||
// by position, anchor, scale and rotation.
|
||||
//
|
||||
// All points are first rotated around the anchor. Then they are multiplied by the scale. If
|
||||
// the scale factor is 2, the object becomes 2x bigger. Finally, all points are moved, so that
|
||||
// the original anchor is located precisely at the position.
|
||||
//
|
||||
// Create a Transform object with Position/Anchor/Rotation/... function. This sets the position
|
||||
// one of it's properties. Then use methods, like Scale and Rotate to change scale, rotation and
|
||||
// achor. The order in which you apply these methods is irrelevant.
|
||||
//
|
||||
// pixel.Position(pixel.V(100, 100)).Rotate(math.Pi / 3).Scale(1.5)
|
||||
//
|
||||
// Also note, that no method changes the Transform. All simply return a new, changed Transform.
|
||||
type Transform struct {
|
||||
pos, anc, sca Vec
|
||||
rot float64
|
||||
}
|
||||
|
||||
// ZT stands for Zero-Transform. This Transform is a neutral Transform, does not change anything.
|
||||
var ZT = Transform{}.Scale(1)
|
||||
|
||||
// Position returns a Zero-Transform with Position set to pos.
|
||||
func Position(pos Vec) Transform {
|
||||
return ZT.Position(pos)
|
||||
}
|
||||
|
||||
// Anchor returns a Zero-Transform with Anchor set to anchor.
|
||||
func Anchor(anchor Vec) Transform {
|
||||
return ZT.Anchor(anchor)
|
||||
}
|
||||
|
||||
// Scale returns a Zero-Transform with Scale set to scale.
|
||||
func Scale(scale float64) Transform {
|
||||
return ZT.Scale(scale)
|
||||
}
|
||||
|
||||
// ScaleXY returns a Zero-Transform with ScaleXY set to scale.
|
||||
func ScaleXY(scale Vec) Transform {
|
||||
return ZT.ScaleXY(scale)
|
||||
}
|
||||
|
||||
// Rotation returns a Zero-Transform with Rotation set to angle (in radians).
|
||||
func Rotation(angle float64) Transform {
|
||||
return ZT.Rotation(angle)
|
||||
}
|
||||
|
||||
// Position moves an object by the specified vector. A zero vector will end up precisely at pos.
|
||||
func (t Transform) Position(pos Vec) Transform {
|
||||
t.pos = pos
|
||||
return t
|
||||
}
|
||||
|
||||
// AddPosition adds delta to the existing Position of this Transform.
|
||||
func (t Transform) AddPosition(delta Vec) Transform {
|
||||
t.pos += delta
|
||||
return t
|
||||
}
|
||||
|
||||
// Anchor specifies the zero vector, point originally located at anchor will be treated as zero.
|
||||
// This affects Rotation and Position.
|
||||
func (t Transform) Anchor(anchor Vec) Transform {
|
||||
t.anc = anchor
|
||||
return t
|
||||
}
|
||||
|
||||
// AddAnchor adds delta to the existing Anchor of this Transform.
|
||||
func (t Transform) AddAnchor(delta Vec) Transform {
|
||||
t.anc += delta
|
||||
return t
|
||||
}
|
||||
|
||||
// Scale specifies a factor by which an object will be scaled around it's Anchor.
|
||||
//
|
||||
// Same as:
|
||||
// t.ScaleXY(pixel.V(scale, scale)).
|
||||
func (t Transform) Scale(scale float64) Transform {
|
||||
t.sca = V(scale, scale)
|
||||
return t
|
||||
}
|
||||
|
||||
// MulScale multiplies the existing Scale of this Transform by factor.
|
||||
//
|
||||
// Same as:
|
||||
// t.MulScaleXY(pixel.V(factor, factor)).
|
||||
func (t Transform) MulScale(factor float64) Transform {
|
||||
t.sca = t.sca.Scaled(factor)
|
||||
return t
|
||||
}
|
||||
|
||||
// ScaleXY specifies a factor in each dimension, by which an object will be scaled around it's
|
||||
// Anchor.
|
||||
func (t Transform) ScaleXY(scale Vec) Transform {
|
||||
t.sca = scale
|
||||
return t
|
||||
}
|
||||
|
||||
// MulScaleXY multiplies the existing ScaleXY of this Transform by factor, component-wise.
|
||||
func (t Transform) MulScaleXY(factor Vec) Transform {
|
||||
t.sca = V(
|
||||
t.sca.X()*factor.X(),
|
||||
t.sca.Y()*factor.Y(),
|
||||
)
|
||||
return t
|
||||
}
|
||||
|
||||
// Rotation specifies an angle by which an object will be rotated around it's Anchor.
|
||||
//
|
||||
// The angle is in radians.
|
||||
func (t Transform) Rotation(angle float64) Transform {
|
||||
t.rot = angle
|
||||
return t
|
||||
}
|
||||
|
||||
// AddRotation adds delta to the existing Angle of this Transform.
|
||||
//
|
||||
// The delta is in radians.
|
||||
func (t Transform) AddRotation(delta float64) Transform {
|
||||
t.rot += delta
|
||||
return t
|
||||
}
|
||||
|
||||
// GetPosition returns the Position of the Transform.
|
||||
func (t Transform) GetPosition() Vec {
|
||||
return t.pos
|
||||
}
|
||||
|
||||
// GetAnchor returns the Anchor of the Transform.
|
||||
func (t Transform) GetAnchor() Vec {
|
||||
return t.anc
|
||||
}
|
||||
|
||||
// GetScaleXY returns the ScaleXY of the Transform.
|
||||
func (t Transform) GetScaleXY() Vec {
|
||||
return t.sca
|
||||
}
|
||||
|
||||
// GetRotation returns the Rotation of the Transform.
|
||||
func (t Transform) GetRotation() float64 {
|
||||
return t.rot
|
||||
}
|
||||
|
||||
// Project transforms a vector by a transform.
|
||||
func (t Transform) Project(v Vec) Vec {
|
||||
mat := t.Mat()
|
||||
vec := mgl32.Vec3{float32(v.X()), float32(v.Y()), 1}
|
||||
pro := mat.Mul3x1(vec)
|
||||
return V(float64(pro.X()), float64(pro.Y()))
|
||||
}
|
||||
|
||||
// Unproject does the inverse operation to Project.
|
||||
func (t Transform) Unproject(v Vec) Vec {
|
||||
mat := t.InvMat()
|
||||
vec := mgl32.Vec3{float32(v.X()), float32(v.Y()), 1}
|
||||
unp := mat.Mul3x1(vec)
|
||||
return V(float64(unp.X()), float64(unp.Y()))
|
||||
}
|
||||
|
||||
// Mat returns a transformation matrix that satisfies previously set transform properties.
|
||||
func (t Transform) Mat() mgl32.Mat3 {
|
||||
mat := mgl32.Ident3()
|
||||
mat = mat.Mul3(mgl32.Translate2D(float32(t.pos.X()), float32(t.pos.Y())))
|
||||
mat = mat.Mul3(mgl32.Rotate3DZ(float32(t.rot)))
|
||||
mat = mat.Mul3(mgl32.Scale2D(float32(t.sca.X()), float32(t.sca.Y())))
|
||||
mat = mat.Mul3(mgl32.Translate2D(float32(-t.anc.X()), float32(-t.anc.Y())))
|
||||
return mat
|
||||
}
|
||||
|
||||
// InvMat returns an inverse transformation matrix to the matrix returned by Mat3 method.
|
||||
func (t Transform) InvMat() mgl32.Mat3 {
|
||||
mat := mgl32.Ident3()
|
||||
mat = mat.Mul3(mgl32.Translate2D(float32(t.anc.X()), float32(t.anc.Y())))
|
||||
mat = mat.Mul3(mgl32.Scale2D(float32(1/t.sca.X()), float32(1/t.sca.Y())))
|
||||
mat = mat.Mul3(mgl32.Rotate3DZ(float32(-t.rot)))
|
||||
mat = mat.Mul3(mgl32.Translate2D(float32(-t.pos.X()), float32(-t.pos.Y())))
|
||||
return mat
|
||||
}
|
||||
|
||||
// Camera is a convenience function, that returns a Transform that acts like a camera. Center is
|
||||
// the position in the world coordinates, that will be projected onto the center of the screen.
|
||||
// One unit in world coordinates will be projected onto zoom pixels.
|
||||
//
|
||||
// It is possible to apply additional rotations, scales and moves to the returned transform.
|
||||
func Camera(center, zoom, screenSize Vec) Transform {
|
||||
return Anchor(center).ScaleXY(2 * zoom).MulScaleXY(V(1/screenSize.X(), 1/screenSize.Y()))
|
||||
}
|
10
util.go
10
util.go
|
@ -1,7 +1,5 @@
|
|||
package pixel
|
||||
|
||||
import "github.com/go-gl/mathgl/mgl32"
|
||||
|
||||
func clamp(x, low, high float64) float64 {
|
||||
if x < low {
|
||||
return low
|
||||
|
@ -11,11 +9,3 @@ func clamp(x, low, high float64) float64 {
|
|||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func transformToMat(t ...Transform) mgl32.Mat3 {
|
||||
mat := mgl32.Ident3()
|
||||
for i := range t {
|
||||
mat = mat.Mul3(t[i].Mat())
|
||||
}
|
||||
return mat
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue