replace complex128 Vec with a struct

This commit is contained in:
faiface 2017-05-21 19:25:06 +02:00
parent 8221ab58bc
commit fcfeb200b6
13 changed files with 230 additions and 260 deletions

26
data.go
View File

@ -45,7 +45,7 @@ func (td *TrianglesData) SetLen(len int) {
Color RGBA Color RGBA
Picture Vec Picture Vec
Intensity float64 Intensity float64
}{V(0, 0), Alpha(1), V(0, 0), 0}) }{ZV, Alpha(1), ZV, 0})
} }
} }
if len < td.Len() { if len < td.Len() {
@ -136,8 +136,8 @@ type PictureData struct {
// MakePictureData creates a zero-initialized PictureData covering the given rectangle. // MakePictureData creates a zero-initialized PictureData covering the given rectangle.
func MakePictureData(rect Rect) *PictureData { func MakePictureData(rect Rect) *PictureData {
w := int(math.Ceil(rect.Max.X())) - int(math.Floor(rect.Min.X())) w := int(math.Ceil(rect.Max.X)) - int(math.Floor(rect.Min.X))
h := int(math.Ceil(rect.Max.Y())) - int(math.Floor(rect.Min.Y())) h := int(math.Ceil(rect.Max.Y)) - int(math.Floor(rect.Min.Y))
pd := &PictureData{ pd := &PictureData{
Stride: w, Stride: w,
Rect: rect, Rect: rect,
@ -205,12 +205,12 @@ func PictureDataFromPicture(pic Picture) *PictureData {
pd := MakePictureData(bounds) pd := MakePictureData(bounds)
if pic, ok := pic.(PictureColor); ok { if pic, ok := pic.(PictureColor); ok {
for y := math.Floor(bounds.Min.Y()); y < bounds.Max.Y(); y++ { for y := math.Floor(bounds.Min.Y); y < bounds.Max.Y; y++ {
for x := math.Floor(bounds.Min.X()); x < bounds.Max.X(); x++ { for x := math.Floor(bounds.Min.X); x < bounds.Max.X; x++ {
// this together with the Floor is a trick to get all of the pixels // this together with the Floor is a trick to get all of the pixels
at := V( at := V(
math.Max(x, bounds.Min.X()), math.Max(x, bounds.Min.X),
math.Max(y, bounds.Min.Y()), math.Max(y, bounds.Min.Y),
) )
col := pic.Color(at) col := pic.Color(at)
pd.Pix[pd.Index(at)] = color.RGBA{ pd.Pix[pd.Index(at)] = color.RGBA{
@ -231,10 +231,10 @@ func PictureDataFromPicture(pic Picture) *PictureData {
// The resulting image.RGBA's Bounds will be equivalent of the PictureData's Bounds. // The resulting image.RGBA's Bounds will be equivalent of the PictureData's Bounds.
func (pd *PictureData) Image() *image.RGBA { func (pd *PictureData) Image() *image.RGBA {
bounds := image.Rect( bounds := image.Rect(
int(math.Floor(pd.Rect.Min.X())), int(math.Floor(pd.Rect.Min.X)),
int(math.Floor(pd.Rect.Min.Y())), int(math.Floor(pd.Rect.Min.Y)),
int(math.Ceil(pd.Rect.Max.X())), int(math.Ceil(pd.Rect.Max.X)),
int(math.Ceil(pd.Rect.Max.Y())), int(math.Ceil(pd.Rect.Max.Y)),
) )
rgba := image.NewRGBA(bounds) rgba := image.NewRGBA(bounds)
@ -257,8 +257,8 @@ func (pd *PictureData) Image() *image.RGBA {
// Index returns the index of the pixel at the specified position inside the Pix slice. // Index returns the index of the pixel at the specified position inside the Pix slice.
func (pd *PictureData) Index(at Vec) int { func (pd *PictureData) Index(at Vec) int {
at -= pd.Rect.Min.Map(math.Floor) at = at.Sub(pd.Rect.Min.Map(math.Floor))
x, y := int(at.X()), int(at.Y()) x, y := int(at.X), int(at.Y)
return y*pd.Stride + x return y*pd.Stride + x
} }

View File

@ -3,50 +3,38 @@ package pixel
import ( import (
"fmt" "fmt"
"math" "math"
"math/cmplx"
"github.com/go-gl/mathgl/mgl64" "github.com/go-gl/mathgl/mgl64"
) )
// Vec is a 2D vector type. It is unusually implemented as complex128 for convenience. Since // Vec is a 2D vector type with X and Y coordinates.
// Go does not allow operator overloading, implementing vector as a struct leads to a bunch of
// methods for addition, subtraction and multiplication of vectors. With complex128, much of
// this functionality is given through operators.
// //
// Create vectors with the V constructor: // Create vectors with the V constructor:
// //
// u := pixel.V(1, 2) // u := pixel.V(1, 2)
// v := pixel.V(8, -3) // v := pixel.V(8, -3)
// //
// Add and subtract them using the standard + and - operators: // Use various methods to manipulate them:
// //
// w := u + v // w := u.Add(v)
// fmt.Println(w) // Vec(9, -1) // fmt.Println(w) // Vec(9, -1)
// fmt.Println(u - v) // Vec(-7, 5) // fmt.Println(u.Sub(v)) // Vec(-7, 5)
// // u = pixel.V(2, 3)
// Additional standard vector operations can be obtained with methods: // v = pixel.V(8, 1)
// // if u.X < 0 {
// u := pixel.V(2, 3)
// v := pixel.V(8, 1)
// if u.X() < 0 {
// fmt.Println("this won't happen") // fmt.Println("this won't happen")
// } // }
// x := u.Unit().Dot(v.Unit()) // x := u.Unit().Dot(v.Unit())
type Vec complex128 type Vec struct {
X, Y float64
}
// ZV is a zero vector.
var ZV = Vec{0, 0}
// V returns a new 2D vector with the given coordinates. // V returns a new 2D vector with the given coordinates.
func V(x, y float64) Vec { func V(x, y float64) Vec {
return Vec(complex(x, y)) return Vec{x, y}
}
// X returns a 2D vector with coordinates (x, 0).
func X(x float64) Vec {
return V(x, 0)
}
// Y returns a 2D vector with coordinates (0, y).
func Y(y float64) Vec {
return V(0, y)
} }
// String returns the string representation of the vector u. // String returns the string representation of the vector u.
@ -55,76 +43,75 @@ func Y(y float64) Vec {
// u.String() // returns "Vec(4.5, -1.3)" // u.String() // returns "Vec(4.5, -1.3)"
// fmt.Println(u) // Vec(4.5, -1.3) // fmt.Println(u) // Vec(4.5, -1.3)
func (u Vec) String() string { func (u Vec) String() string {
return fmt.Sprintf("Vec(%v, %v)", u.X(), u.Y()) return fmt.Sprintf("Vec(%v, %v)", u.X, u.Y)
}
// X returns the x coordinate of the vector u.
func (u Vec) X() float64 {
return real(u)
}
// Y returns the y coordinate of the vector u.
func (u Vec) Y() float64 {
return imag(u)
} }
// XY returns the components of the vector in two return values. // XY returns the components of the vector in two return values.
func (u Vec) XY() (x, y float64) { func (u Vec) XY() (x, y float64) {
return real(u), imag(u) return u.X, u.Y
} }
// Len returns the length of the vector u. // Add returns the sum of vectors u and v.
func (u Vec) Len() float64 { func (u Vec) Add(v Vec) Vec {
return cmplx.Abs(complex128(u)) return Vec{
} u.X + v.X,
u.Y + v.Y,
// Angle returns the angle between the vector u and the x-axis. The result is in range [-Pi, Pi]. }
func (u Vec) Angle() float64 { }
return cmplx.Phase(complex128(u))
} // Sub returns the difference betweeen vectors u and v.
func (u Vec) Sub(v Vec) Vec {
// Unit returns a vector of length 1 facing the direction of u (has the same angle). return Vec{
func (u Vec) Unit() Vec { u.X - v.X,
if u == 0 { u.Y - v.Y,
return 1
} }
return u / V(u.Len(), 0)
} }
// Scaled returns the vector u multiplied by c. // Scaled returns the vector u multiplied by c.
func (u Vec) Scaled(c float64) Vec { func (u Vec) Scaled(c float64) Vec {
return u * V(c, 0) return Vec{u.X * c, u.Y * c}
} }
// ScaledXY returns the vector u multiplied by the vector v component-wise. // ScaledXY returns the vector u multiplied by the vector v component-wise.
func (u Vec) ScaledXY(v Vec) Vec { func (u Vec) ScaledXY(v Vec) Vec {
return V(u.X()*v.X(), u.Y()*v.Y()) return Vec{u.X * v.X, u.Y * v.Y}
}
// Len returns the length of the vector u.
func (u Vec) Len() float64 {
return math.Hypot(u.X, u.Y)
}
// Angle returns the angle between the vector u and the x-axis. The result is in range [-Pi, Pi].
func (u Vec) Angle() float64 {
return math.Atan2(u.Y, u.X)
}
// Unit returns a vector of length 1 facing the direction of u (has the same angle).
func (u Vec) Unit() Vec {
if u.X == 0 && u.Y == 0 {
return Vec{1, 0}
}
return u.Scaled(1 / u.Len())
} }
// Rotated returns the vector u rotated by the given angle in radians. // Rotated returns the vector u rotated by the given angle in radians.
func (u Vec) Rotated(angle float64) Vec { func (u Vec) Rotated(angle float64) Vec {
sin, cos := math.Sincos(angle) sin, cos := math.Sincos(angle)
return u * V(cos, sin) return Vec{
} u.X*cos - u.Y*sin,
u.X*sin + u.Y*cos,
// WithX return the vector u with the x coordinate changed to the given value. }
func (u Vec) WithX(x float64) Vec {
return V(x, u.Y())
}
// WithY returns the vector u with the y coordinate changed to the given value.
func (u Vec) WithY(y float64) Vec {
return V(u.X(), y)
} }
// Dot returns the dot product of vectors u and v. // Dot returns the dot product of vectors u and v.
func (u Vec) Dot(v Vec) float64 { func (u Vec) Dot(v Vec) float64 {
return u.X()*v.X() + u.Y()*v.Y() return u.X*v.X + u.Y*v.Y
} }
// Cross return the cross product of vectors u and v. // Cross return the cross product of vectors u and v.
func (u Vec) Cross(v Vec) float64 { func (u Vec) Cross(v Vec) float64 {
return u.X()*v.Y() - v.X()*u.Y() return u.X*v.Y - v.X*u.Y
} }
// Map applies the function f to both x and y components of the vector u and returns the modified // Map applies the function f to both x and y components of the vector u and returns the modified
@ -133,10 +120,10 @@ func (u Vec) Cross(v Vec) float64 {
// u := pixel.V(10.5, -1.5) // u := pixel.V(10.5, -1.5)
// v := u.Map(math.Floor) // v is Vec(10, -2), both components of u floored // v := u.Map(math.Floor) // v is Vec(10, -2), both components of u floored
func (u Vec) Map(f func(float64) float64) Vec { func (u Vec) Map(f func(float64) float64) Vec {
return V( return Vec{
f(u.X()), f(u.X),
f(u.Y()), f(u.Y),
) }
} }
// Lerp returns a linear interpolation between vectors a and b. // Lerp returns a linear interpolation between vectors a and b.
@ -145,7 +132,7 @@ func (u Vec) Map(f func(float64) float64) Vec {
// If t is 0, then a will be returned, if t is 1, b will be returned. Anything between 0 and 1 will // If t is 0, then a will be returned, if t is 1, b will be returned. Anything between 0 and 1 will
// return the appropriate point between a and b and so on. // return the appropriate point between a and b and so on.
func Lerp(a, b Vec, t float64) Vec { func Lerp(a, b Vec, t float64) Vec {
return a.Scaled(1-t) + b.Scaled(t) return a.Scaled(1 - t).Add(b.Scaled(t))
} }
// Rect is a 2D rectangle aligned with the axes of the coordinate system. It is defined by two // Rect is a 2D rectangle aligned with the axes of the coordinate system. It is defined by two
@ -171,31 +158,31 @@ func R(minX, minY, maxX, maxY float64) Rect {
// r.String() // returns "Rect(100, 50, 200, 300)" // r.String() // returns "Rect(100, 50, 200, 300)"
// fmt.Println(r) // Rect(100, 50, 200, 300) // fmt.Println(r) // Rect(100, 50, 200, 300)
func (r Rect) String() string { func (r Rect) String() string {
return fmt.Sprintf("Rect(%v, %v, %v, %v)", r.Min.X(), r.Min.Y(), r.Max.X(), r.Max.Y()) return fmt.Sprintf("Rect(%v, %v, %v, %v)", r.Min.X, r.Min.Y, r.Max.X, r.Max.Y)
} }
// Norm returns the Rect in normal form, such that Max is component-wise greater or equal than Min. // Norm returns the Rect in normal form, such that Max is component-wise greater or equal than Min.
func (r Rect) Norm() Rect { func (r Rect) Norm() Rect {
return Rect{ return Rect{
Min: V( Min: Vec{
math.Min(r.Min.X(), r.Max.X()), math.Min(r.Min.X, r.Max.X),
math.Min(r.Min.Y(), r.Max.Y()), math.Min(r.Min.Y, r.Max.Y),
), },
Max: V( Max: Vec{
math.Max(r.Min.X(), r.Max.X()), math.Max(r.Min.X, r.Max.X),
math.Max(r.Min.Y(), r.Max.Y()), math.Max(r.Min.Y, r.Max.Y),
), },
} }
} }
// W returns the width of the Rect. // W returns the width of the Rect.
func (r Rect) W() float64 { func (r Rect) W() float64 {
return r.Max.X() - r.Min.X() return r.Max.X - r.Min.X
} }
// H returns the height of the Rect. // H returns the height of the Rect.
func (r Rect) H() float64 { func (r Rect) H() float64 {
return r.Max.Y() - r.Min.Y() return r.Max.Y - r.Min.Y
} }
// Size returns the vector of width and height of the Rect. // Size returns the vector of width and height of the Rect.
@ -205,34 +192,14 @@ func (r Rect) Size() Vec {
// Center returns the position of the center of the Rect. // Center returns the position of the center of the Rect.
func (r Rect) Center() Vec { func (r Rect) Center() Vec {
return (r.Min + r.Max) / 2 return Lerp(r.Min, r.Max, 0.5)
} }
// Moved returns the Rect moved (both Min and Max) by the given vector delta. // Moved returns the Rect moved (both Min and Max) by the given vector delta.
func (r Rect) Moved(delta Vec) Rect { func (r Rect) Moved(delta Vec) Rect {
return Rect{ return Rect{
Min: r.Min + delta, Min: r.Min.Add(delta),
Max: r.Max + delta, Max: r.Max.Add(delta),
}
}
// WithMin returns the Rect with it's Min changed to the given position.
//
// Note, that the Rect is not automatically normalized.
func (r Rect) WithMin(min Vec) Rect {
return Rect{
Min: min,
Max: r.Max,
}
}
// WithMax returns the Rect with it's Max changed to the given position.
//
// Note, that the Rect is not automatically normalized.
func (r Rect) WithMax(max Vec) Rect {
return Rect{
Min: r.Min,
Max: max,
} }
} }
@ -249,10 +216,10 @@ func (r Rect) Resized(anchor, size Vec) Rect {
if r.W()*r.H() == 0 { if r.W()*r.H() == 0 {
panic(fmt.Errorf("(%T).Resize: zero area", r)) panic(fmt.Errorf("(%T).Resize: zero area", r))
} }
fraction := V(size.X()/r.W(), size.Y()/r.H()) fraction := Vec{size.X / r.W(), size.Y / r.H()}
return Rect{ return Rect{
Min: anchor + (r.Min - anchor).ScaledXY(fraction), Min: anchor.Add(r.Min.Sub(anchor)).ScaledXY(fraction),
Max: anchor + (r.Max - anchor).ScaledXY(fraction), Max: anchor.Add(r.Max.Sub(anchor)).ScaledXY(fraction),
} }
} }
@ -263,22 +230,22 @@ func (r Rect) Resized(anchor, size Vec) Rect {
func (r Rect) ResizedMin(size Vec) Rect { func (r Rect) ResizedMin(size Vec) Rect {
return Rect{ return Rect{
Min: r.Min, Min: r.Min,
Max: r.Min + size, Max: r.Min.Add(size),
} }
} }
// Contains checks whether a vector u is contained within this Rect (including it's borders). // Contains checks whether a vector u is contained within this Rect (including it's borders).
func (r Rect) Contains(u Vec) bool { func (r Rect) Contains(u Vec) bool {
return r.Min.X() <= u.X() && u.X() <= r.Max.X() && r.Min.Y() <= u.Y() && u.Y() <= r.Max.Y() return r.Min.X <= u.X && u.X <= r.Max.X && r.Min.Y <= u.Y && u.Y <= r.Max.Y
} }
// Union returns a minimal Rect which covers both r and s. Rects r and s should be normalized. // Union returns a minimal Rect which covers both r and s. Rects r and s should be normalized.
func (r Rect) Union(s Rect) Rect { func (r Rect) Union(s Rect) Rect {
return R( return R(
math.Min(r.Min.X(), s.Min.X()), math.Min(r.Min.X, s.Min.X),
math.Min(r.Min.Y(), s.Min.Y()), math.Min(r.Min.Y, s.Min.Y),
math.Max(r.Max.X(), s.Max.X()), math.Max(r.Max.X, s.Max.X),
math.Max(r.Max.Y(), s.Max.Y()), math.Max(r.Max.Y, s.Max.Y),
) )
} }
@ -320,7 +287,7 @@ func (m Matrix) Moved(delta Vec) Matrix {
// ScaledXY scales everything around a given point by the scale factor in each axis respectively. // ScaledXY scales everything around a given point by the scale factor in each axis respectively.
func (m Matrix) ScaledXY(around Vec, scale Vec) Matrix { func (m Matrix) ScaledXY(around Vec, scale Vec) Matrix {
m3 := mgl64.Mat3(m) m3 := mgl64.Mat3(m)
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3) m3 = mgl64.Translate2D(around.Scaled(-1).XY()).Mul3(m3)
m3 = mgl64.Scale2D(scale.XY()).Mul3(m3) m3 = mgl64.Scale2D(scale.XY()).Mul3(m3)
m3 = mgl64.Translate2D(around.XY()).Mul3(m3) m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
return Matrix(m3) return Matrix(m3)
@ -334,7 +301,7 @@ func (m Matrix) Scaled(around Vec, scale float64) Matrix {
// Rotated rotates everything around a given point by the given angle in radians. // Rotated rotates everything around a given point by the given angle in radians.
func (m Matrix) Rotated(around Vec, angle float64) Matrix { func (m Matrix) Rotated(around Vec, angle float64) Matrix {
m3 := mgl64.Mat3(m) m3 := mgl64.Mat3(m)
m3 = mgl64.Translate2D((-around).XY()).Mul3(m3) m3 = mgl64.Translate2D(around.Scaled(-1).XY()).Mul3(m3)
m3 = mgl64.Rotate3DZ(angle).Mul3(m3) m3 = mgl64.Rotate3DZ(angle).Mul3(m3)
m3 = mgl64.Translate2D(around.XY()).Mul3(m3) m3 = mgl64.Translate2D(around.XY()).Mul3(m3)
return Matrix(m3) return Matrix(m3)
@ -353,7 +320,7 @@ func (m Matrix) Chained(next Matrix) Matrix {
// Time complexity is O(1). // Time complexity is O(1).
func (m Matrix) Project(u Vec) Vec { func (m Matrix) Project(u Vec) Vec {
m3 := mgl64.Mat3(m) m3 := mgl64.Mat3(m)
proj := m3.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1}) proj := m3.Mul3x1(mgl64.Vec3{u.X, u.Y, 1})
return V(proj.X(), proj.Y()) return V(proj.X(), proj.Y())
} }
@ -363,6 +330,6 @@ func (m Matrix) Project(u Vec) Vec {
func (m Matrix) Unproject(u Vec) Vec { func (m Matrix) Unproject(u Vec) Vec {
m3 := mgl64.Mat3(m) m3 := mgl64.Mat3(m)
inv := m3.Inv() inv := m3.Inv()
unproj := inv.Mul3x1(mgl64.Vec3{u.X(), u.Y(), 1}) unproj := inv.Mul3x1(mgl64.Vec3{u.X, u.Y, 1})
return V(unproj.X(), unproj.Y()) return V(unproj.X(), unproj.Y())
} }

View File

@ -111,7 +111,7 @@ func (imd *IMDraw) Clear() {
func (imd *IMDraw) Reset() { func (imd *IMDraw) Reset() {
imd.points = nil imd.points = nil
imd.Color = pixel.Alpha(1) imd.Color = pixel.Alpha(1)
imd.Picture = 0 imd.Picture = pixel.ZV
imd.Intensity = 0 imd.Intensity = 0
imd.Precision = 64 imd.Precision = 64
imd.EndShape = NoEndShape imd.EndShape = NoEndShape
@ -280,15 +280,15 @@ func (imd *IMDraw) fillRectangle() {
for i, j := 0, off; i+1 < len(points); i, j = i+1, j+6 { for i, j := 0, off; i+1 < len(points); i, j = i+1, j+6 {
a, b := points[i], points[i+1] a, b := points[i], points[i+1]
c := point{ c := point{
pos: pixel.V(a.pos.X(), b.pos.Y()), pos: pixel.V(a.pos.X, b.pos.Y),
col: a.col.Add(b.col).Mul(pixel.Alpha(0.5)), col: a.col.Add(b.col).Mul(pixel.Alpha(0.5)),
pic: pixel.V(a.pic.X(), b.pic.Y()), pic: pixel.V(a.pic.X, b.pic.Y),
in: (a.in + b.in) / 2, in: (a.in + b.in) / 2,
} }
d := point{ d := point{
pos: pixel.V(b.pos.X(), a.pos.Y()), pos: pixel.V(b.pos.X, a.pos.Y),
col: a.col.Add(b.col).Mul(pixel.Alpha(0.5)), col: a.col.Add(b.col).Mul(pixel.Alpha(0.5)),
pic: pixel.V(b.pic.X(), a.pic.Y()), pic: pixel.V(b.pic.X, a.pic.Y),
in: (a.in + b.in) / 2, in: (a.in + b.in) / 2,
} }
@ -318,9 +318,9 @@ func (imd *IMDraw) outlineRectangle(thickness float64) {
mid.in = (a.in + b.in) / 2 mid.in = (a.in + b.in) / 2
imd.pushPt(a.pos, a) imd.pushPt(a.pos, a)
imd.pushPt(pixel.V(a.pos.X(), b.pos.Y()), mid) imd.pushPt(pixel.V(a.pos.X, b.pos.Y), mid)
imd.pushPt(b.pos, b) imd.pushPt(b.pos, b)
imd.pushPt(pixel.V(b.pos.X(), a.pos.Y()), mid) imd.pushPt(pixel.V(b.pos.X, a.pos.Y), mid)
imd.polyline(thickness, true) imd.polyline(thickness, true)
} }
} }
@ -360,24 +360,24 @@ func (imd *IMDraw) fillEllipseArc(radius pixel.Vec, low, high float64) {
for i := range (*imd.tri)[off:] { for i := range (*imd.tri)[off:] {
(*imd.tri)[off+i].Color = pt.col (*imd.tri)[off+i].Color = pt.col
(*imd.tri)[off+i].Picture = 0 (*imd.tri)[off+i].Picture = pixel.ZV
(*imd.tri)[off+i].Intensity = 0 (*imd.tri)[off+i].Intensity = 0
} }
for i, j := 0.0, off; i < num; i, j = i+1, j+3 { for i, j := 0.0, off; i < num; i, j = i+1, j+3 {
angle := low + i*delta angle := low + i*delta
sin, cos := math.Sincos(angle) sin, cos := math.Sincos(angle)
a := pt.pos + pixel.V( a := pt.pos.Add(pixel.V(
radius.X()*cos, radius.X*cos,
radius.Y()*sin, radius.Y*sin,
) ))
angle = low + (i+1)*delta angle = low + (i+1)*delta
sin, cos = math.Sincos(angle) sin, cos = math.Sincos(angle)
b := pt.pos + pixel.V( b := pt.pos.Add(pixel.V(
radius.X()*cos, radius.X*cos,
radius.Y()*sin, radius.Y*sin,
) ))
(*imd.tri)[j+0].Position = pt.pos (*imd.tri)[j+0].Position = pt.pos
(*imd.tri)[j+1].Position = a (*imd.tri)[j+1].Position = a
@ -401,7 +401,7 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
for i := range (*imd.tri)[off:] { for i := range (*imd.tri)[off:] {
(*imd.tri)[off+i].Color = pt.col (*imd.tri)[off+i].Color = pt.col
(*imd.tri)[off+i].Picture = 0 (*imd.tri)[off+i].Picture = pixel.ZV
(*imd.tri)[off+i].Intensity = 0 (*imd.tri)[off+i].Intensity = 0
} }
@ -409,26 +409,26 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
angle := low + i*delta angle := low + i*delta
sin, cos := math.Sincos(angle) sin, cos := math.Sincos(angle)
normalSin, normalCos := pixel.V(sin, cos).ScaledXY(radius).Unit().XY() normalSin, normalCos := pixel.V(sin, cos).ScaledXY(radius).Unit().XY()
a := pt.pos + pixel.V( a := pt.pos.Add(pixel.V(
radius.X()*cos-thickness/2*normalCos, radius.X*cos-thickness/2*normalCos,
radius.Y()*sin-thickness/2*normalSin, radius.Y*sin-thickness/2*normalSin,
) ))
b := pt.pos + pixel.V( b := pt.pos.Add(pixel.V(
radius.X()*cos+thickness/2*normalCos, radius.X*cos+thickness/2*normalCos,
radius.Y()*sin+thickness/2*normalSin, radius.Y*sin+thickness/2*normalSin,
) ))
angle = low + (i+1)*delta angle = low + (i+1)*delta
sin, cos = math.Sincos(angle) sin, cos = math.Sincos(angle)
normalSin, normalCos = pixel.V(sin, cos).ScaledXY(radius).Unit().XY() normalSin, normalCos = pixel.V(sin, cos).ScaledXY(radius).Unit().XY()
c := pt.pos + pixel.V( c := pt.pos.Add(pixel.V(
radius.X()*cos-thickness/2*normalCos, radius.X*cos-thickness/2*normalCos,
radius.Y()*sin-thickness/2*normalSin, radius.Y*sin-thickness/2*normalSin,
) ))
d := pt.pos + pixel.V( d := pt.pos.Add(pixel.V(
radius.X()*cos+thickness/2*normalCos, radius.X*cos+thickness/2*normalCos,
radius.Y()*sin+thickness/2*normalSin, radius.Y*sin+thickness/2*normalSin,
) ))
(*imd.tri)[j+0].Position = a (*imd.tri)[j+0].Position = a
(*imd.tri)[j+1].Position = b (*imd.tri)[j+1].Position = b
@ -443,18 +443,18 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
if doEndShape { if doEndShape {
lowSin, lowCos := math.Sincos(low) lowSin, lowCos := math.Sincos(low)
lowCenter := pt.pos + pixel.V( lowCenter := pt.pos.Add(pixel.V(
radius.X()*lowCos, radius.X*lowCos,
radius.Y()*lowSin, radius.Y*lowSin,
) ))
normalLowSin, normalLowCos := pixel.V(lowSin, lowCos).ScaledXY(radius).Unit().XY() normalLowSin, normalLowCos := pixel.V(lowSin, lowCos).ScaledXY(radius).Unit().XY()
normalLow := pixel.V(normalLowCos, normalLowSin).Angle() normalLow := pixel.V(normalLowCos, normalLowSin).Angle()
highSin, highCos := math.Sincos(high) highSin, highCos := math.Sincos(high)
highCenter := pt.pos + pixel.V( highCenter := pt.pos.Add(pixel.V(
radius.X()*highCos, radius.X*highCos,
radius.Y()*highSin, radius.Y*highSin,
) ))
normalHighSin, normalHighCos := pixel.V(highSin, highCos).ScaledXY(radius).Unit().XY() normalHighSin, normalHighCos := pixel.V(highSin, highCos).ScaledXY(radius).Unit().XY()
normalHigh := pixel.V(normalHighCos, normalHighSin).Angle() normalHigh := pixel.V(normalHighCos, normalHighSin).Angle()
@ -467,21 +467,21 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa
case NoEndShape: case NoEndShape:
// nothing // nothing
case SharpEndShape: case SharpEndShape:
thick := pixel.X(thickness / 2).Rotated(normalLow) thick := pixel.V(thickness/2, 0).Rotated(normalLow)
imd.pushPt(lowCenter+thick, pt) imd.pushPt(lowCenter.Add(thick), pt)
imd.pushPt(lowCenter-thick, pt) imd.pushPt(lowCenter.Sub(thick), pt)
imd.pushPt(lowCenter-thick.Rotated(math.Pi/2*orientation), pt) imd.pushPt(lowCenter.Sub(thick.Rotated(math.Pi/2*orientation)), pt)
imd.fillPolygon() imd.fillPolygon()
thick = pixel.X(thickness / 2).Rotated(normalHigh) thick = pixel.V(thickness/2, 0).Rotated(normalHigh)
imd.pushPt(highCenter+thick, pt) imd.pushPt(highCenter.Add(thick), pt)
imd.pushPt(highCenter-thick, pt) imd.pushPt(highCenter.Sub(thick), pt)
imd.pushPt(highCenter+thick.Rotated(math.Pi/2*orientation), pt) imd.pushPt(highCenter.Add(thick.Rotated(math.Pi/2*orientation)), pt)
imd.fillPolygon() imd.fillPolygon()
case RoundEndShape: case RoundEndShape:
imd.pushPt(lowCenter, pt) imd.pushPt(lowCenter, pt)
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, normalLow, normalLow-math.Pi*orientation) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normalLow, normalLow-math.Pi*orientation)
imd.pushPt(highCenter, pt) imd.pushPt(highCenter, pt)
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, normalHigh, normalHigh+math.Pi*orientation) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normalHigh, normalHigh+math.Pi*orientation)
} }
} }
} }
@ -500,25 +500,25 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
// first point // first point
j, i := 0, 1 j, i := 0, 1
normal := (points[i].pos - points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2) normal := points[i].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
if !closed { if !closed {
switch points[j].endshape { switch points[j].endshape {
case NoEndShape: case NoEndShape:
// nothing // nothing
case SharpEndShape: case SharpEndShape:
imd.pushPt(points[j].pos+normal, points[j]) imd.pushPt(points[j].pos.Add(normal), points[j])
imd.pushPt(points[j].pos-normal, points[j]) imd.pushPt(points[j].pos.Sub(normal), points[j])
imd.pushPt(points[j].pos+normal.Rotated(math.Pi/2), points[j]) imd.pushPt(points[j].pos.Add(normal.Rotated(math.Pi/2)), points[j])
imd.fillPolygon() imd.fillPolygon()
case RoundEndShape: case RoundEndShape:
imd.pushPt(points[j].pos, points[j]) imd.pushPt(points[j].pos, points[j])
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, normal.Angle(), normal.Angle()+math.Pi) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()+math.Pi)
} }
} }
imd.pushPt(points[j].pos+normal, points[j]) imd.pushPt(points[j].pos.Add(normal), points[j])
imd.pushPt(points[j].pos-normal, points[j]) imd.pushPt(points[j].pos.Sub(normal), points[j])
// middle points // middle points
for i := 0; i < len(points); i++ { for i := 0; i < len(points); i++ {
@ -536,16 +536,16 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
k %= len(points) k %= len(points)
} }
ijNormal := (points[j].pos - points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2) ijNormal := points[j].pos.Sub(points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
jkNormal := (points[k].pos - points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2) jkNormal := points[k].pos.Sub(points[j].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
orientation := 1.0 orientation := 1.0
if ijNormal.Cross(jkNormal) > 0 { if ijNormal.Cross(jkNormal) > 0 {
orientation = -1.0 orientation = -1.0
} }
imd.pushPt(points[j].pos-ijNormal, points[j]) imd.pushPt(points[j].pos.Sub(ijNormal), points[j])
imd.pushPt(points[j].pos+ijNormal, points[j]) imd.pushPt(points[j].pos.Add(ijNormal), points[j])
imd.fillPolygon() imd.fillPolygon()
switch points[j].endshape { switch points[j].endshape {
@ -553,28 +553,28 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
// nothing // nothing
case SharpEndShape: case SharpEndShape:
imd.pushPt(points[j].pos, points[j]) imd.pushPt(points[j].pos, points[j])
imd.pushPt(points[j].pos+ijNormal.Scaled(orientation), points[j]) imd.pushPt(points[j].pos.Add(ijNormal.Scaled(orientation)), points[j])
imd.pushPt(points[j].pos+jkNormal.Scaled(orientation), points[j]) imd.pushPt(points[j].pos.Add(jkNormal.Scaled(orientation)), points[j])
imd.fillPolygon() imd.fillPolygon()
case RoundEndShape: case RoundEndShape:
imd.pushPt(points[j].pos, points[j]) imd.pushPt(points[j].pos, points[j])
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, ijNormal.Angle(), ijNormal.Angle()-math.Pi) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), ijNormal.Angle(), ijNormal.Angle()-math.Pi)
imd.pushPt(points[j].pos, points[j]) imd.pushPt(points[j].pos, points[j])
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, jkNormal.Angle(), jkNormal.Angle()+math.Pi) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), jkNormal.Angle(), jkNormal.Angle()+math.Pi)
} }
if !closing { if !closing {
imd.pushPt(points[j].pos+jkNormal, points[j]) imd.pushPt(points[j].pos.Add(jkNormal), points[j])
imd.pushPt(points[j].pos-jkNormal, points[j]) imd.pushPt(points[j].pos.Sub(jkNormal), points[j])
} }
} }
// last point // last point
i, j = len(points)-2, len(points)-1 i, j = len(points)-2, len(points)-1
normal = (points[j].pos - points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2) normal = points[j].pos.Sub(points[i].pos).Rotated(math.Pi / 2).Unit().Scaled(thickness / 2)
imd.pushPt(points[j].pos-normal, points[j]) imd.pushPt(points[j].pos.Sub(normal), points[j])
imd.pushPt(points[j].pos+normal, points[j]) imd.pushPt(points[j].pos.Add(normal), points[j])
imd.fillPolygon() imd.fillPolygon()
if !closed { if !closed {
@ -582,13 +582,13 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) {
case NoEndShape: case NoEndShape:
// nothing // nothing
case SharpEndShape: case SharpEndShape:
imd.pushPt(points[j].pos+normal, points[j]) imd.pushPt(points[j].pos.Add(normal), points[j])
imd.pushPt(points[j].pos-normal, points[j]) imd.pushPt(points[j].pos.Sub(normal), points[j])
imd.pushPt(points[j].pos+normal.Rotated(-math.Pi/2), points[j]) imd.pushPt(points[j].pos.Add(normal.Rotated(-math.Pi/2)), points[j])
imd.fillPolygon() imd.fillPolygon()
case RoundEndShape: case RoundEndShape:
imd.pushPt(points[j].pos, points[j]) imd.pushPt(points[j].pos, points[j])
imd.fillEllipseArc(pixel.V(thickness, thickness)/2, normal.Angle(), normal.Angle()-math.Pi) imd.fillEllipseArc(pixel.V(thickness/2, thickness/2), normal.Angle(), normal.Angle()-math.Pi)
} }
} }
} }

View File

@ -285,8 +285,8 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) {
dstBounds := ct.dst.Bounds() dstBounds := ct.dst.Bounds()
shader.SetUniformAttr(canvasBounds, mgl32.Vec4{ shader.SetUniformAttr(canvasBounds, mgl32.Vec4{
float32(dstBounds.Min.X()), float32(dstBounds.Min.X),
float32(dstBounds.Min.Y()), float32(dstBounds.Min.Y),
float32(dstBounds.W()), float32(dstBounds.W()),
float32(dstBounds.H()), float32(dstBounds.H()),
}) })

View File

@ -70,7 +70,7 @@ func (gf *GLFrame) Color(at pixel.Vec) pixel.RGBA {
return pixel.Alpha(0) return pixel.Alpha(0)
} }
bx, by, bw, _ := intBounds(gf.bounds) bx, by, bw, _ := intBounds(gf.bounds)
x, y := int(at.X())-bx, int(at.Y())-by x, y := int(at.X)-bx, int(at.Y)-by
off := y*bw + x off := y*bw + x
return pixel.RGBA{ return pixel.RGBA{
R: float64(gf.pixels[off*4+0]) / 255, R: float64(gf.pixels[off*4+0]) / 255,

View File

@ -42,8 +42,8 @@ func NewGLPicture(p pixel.Picture) GLPicture {
for y := 0; y < bh; y++ { for y := 0; y < bh; y++ {
for x := 0; x < bw; x++ { for x := 0; x < bw; x++ {
at := pixel.V( at := pixel.V(
math.Max(float64(bx+x), bounds.Min.X()), math.Max(float64(bx+x), bounds.Min.X),
math.Max(float64(by+y), bounds.Min.Y()), math.Max(float64(by+y), bounds.Min.Y),
) )
color := p.Color(at) color := p.Color(at)
off := (y*bw + x) * 4 off := (y*bw + x) * 4
@ -87,7 +87,7 @@ func (gp *glPicture) Color(at pixel.Vec) pixel.RGBA {
return pixel.Alpha(0) return pixel.Alpha(0)
} }
bx, by, bw, _ := intBounds(gp.bounds) bx, by, bw, _ := intBounds(gp.bounds)
x, y := int(at.X())-bx, int(at.Y())-by x, y := int(at.X)-bx, int(at.Y)-by
off := y*bw + x off := y*bw + x
return pixel.RGBA{ return pixel.RGBA{
R: float64(gp.pixels[off*4+0]) / 255, R: float64(gp.pixels[off*4+0]) / 255,

View File

@ -135,8 +135,8 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) {
if t, ok := t.(pixel.TrianglesPicture); ok { if t, ok := t.(pixel.TrianglesPicture); ok {
for i := 0; i < gt.Len(); i++ { for i := 0; i < gt.Len(); i++ {
pic, intensity := t.Picture(i) pic, intensity := t.Picture(i)
gt.data[i*gt.vs.Stride()+6] = float32(pic.X()) gt.data[i*gt.vs.Stride()+6] = float32(pic.X)
gt.data[i*gt.vs.Stride()+7] = float32(pic.Y()) gt.data[i*gt.vs.Stride()+7] = float32(pic.Y)
gt.data[i*gt.vs.Stride()+8] = float32(intensity) gt.data[i*gt.vs.Stride()+8] = float32(intensity)
} }
} }

View File

@ -356,13 +356,14 @@ func (w *Window) initInput() {
w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
w.tempInp.mouse = pixel.V( w.tempInp.mouse = pixel.V(
x+w.bounds.Min.X(), x+w.bounds.Min.X,
(w.bounds.H()-y)+w.bounds.Min.Y(), (w.bounds.H()-y)+w.bounds.Min.Y,
) )
}) })
w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) { w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) {
w.tempInp.scroll += pixel.V(xoff, yoff) w.tempInp.scroll.X += xoff
w.tempInp.scroll.Y += yoff
}) })
w.window.SetCharCallback(func(_ *glfw.Window, r rune) { w.window.SetCharCallback(func(_ *glfw.Window, r rune) {
@ -380,6 +381,6 @@ func (w *Window) updateInput() {
w.currInp = w.tempInp w.currInp = w.tempInp
w.tempInp.repeat = [KeyLast + 1]bool{} w.tempInp.repeat = [KeyLast + 1]bool{}
w.tempInp.scroll = 0 w.tempInp.scroll = pixel.ZV
w.tempInp.typed = "" w.tempInp.typed = ""
} }

View File

@ -7,9 +7,9 @@ import (
) )
func intBounds(bounds pixel.Rect) (x, y, w, h int) { func intBounds(bounds pixel.Rect) (x, y, w, h int) {
x0 := int(math.Floor(bounds.Min.X())) x0 := int(math.Floor(bounds.Min.X))
y0 := int(math.Floor(bounds.Min.Y())) y0 := int(math.Floor(bounds.Min.Y))
x1 := int(math.Ceil(bounds.Max.X())) x1 := int(math.Ceil(bounds.Max.X))
y1 := int(math.Ceil(bounds.Max.Y())) y1 := int(math.Ceil(bounds.Max.Y))
return x0, y0, x1 - x0, y1 - y0 return x0, y0, x1 - x0, y1 - y0
} }

View File

@ -160,10 +160,10 @@ func (w *Window) Update() {
mainthread.Call(func() { mainthread.Call(func() {
_, _, oldW, oldH := intBounds(w.bounds) _, _, oldW, oldH := intBounds(w.bounds)
newW, newH := w.window.GetSize() newW, newH := w.window.GetSize()
w.bounds = w.bounds.ResizedMin(w.bounds.Size() + pixel.V( w.bounds = w.bounds.ResizedMin(w.bounds.Size().Add(pixel.V(
float64(newW-oldW), float64(newW-oldW),
float64(newH-oldH), float64(newH-oldH),
)) )))
}) })
w.canvas.SetBounds(w.bounds) w.canvas.SetBounds(w.bounds)

View File

@ -90,20 +90,20 @@ func (s *Sprite) DrawColorMask(t Target, matrix Matrix, mask color.Color) {
func (s *Sprite) calcData() { func (s *Sprite) calcData() {
var ( var (
center = s.frame.Center() center = s.frame.Center()
horizontal = X(s.frame.W() / 2) horizontal = V(s.frame.W()/2, 0)
vertical = Y(s.frame.H() / 2) vertical = V(0, s.frame.H()/2)
) )
(*s.tri)[0].Position = -horizontal - vertical (*s.tri)[0].Position = Vec{}.Sub(horizontal).Sub(vertical)
(*s.tri)[1].Position = +horizontal - vertical (*s.tri)[1].Position = Vec{}.Add(horizontal).Sub(vertical)
(*s.tri)[2].Position = +horizontal + vertical (*s.tri)[2].Position = Vec{}.Add(horizontal).Add(vertical)
(*s.tri)[3].Position = -horizontal - vertical (*s.tri)[3].Position = Vec{}.Sub(horizontal).Sub(vertical)
(*s.tri)[4].Position = +horizontal + vertical (*s.tri)[4].Position = Vec{}.Add(horizontal).Add(vertical)
(*s.tri)[5].Position = -horizontal + vertical (*s.tri)[5].Position = Vec{}.Sub(horizontal).Add(vertical)
for i := range *s.tri { for i := range *s.tri {
(*s.tri)[i].Color = s.mask (*s.tri)[i].Color = s.mask
(*s.tri)[i].Picture = center + (*s.tri)[i].Position (*s.tri)[i].Picture = center.Add((*s.tri)[i].Position)
(*s.tri)[i].Intensity = 1 (*s.tri)[i].Intensity = 1
} }

View File

@ -73,13 +73,13 @@ func NewAtlas(face font.Face, runeSets ...[]rune) *Atlas {
mapping[r] = Glyph{ mapping[r] = Glyph{
Dot: pixel.V( Dot: pixel.V(
i2f(fg.dot.X), i2f(fg.dot.X),
bounds.Max.Y()-(i2f(fg.dot.Y)-bounds.Min.Y()), bounds.Max.Y-(i2f(fg.dot.Y)-bounds.Min.Y),
), ),
Frame: pixel.R( Frame: pixel.R(
i2f(fg.frame.Min.X), i2f(fg.frame.Min.X),
bounds.Max.Y()-(i2f(fg.frame.Min.Y)-bounds.Min.Y()), bounds.Max.Y-(i2f(fg.frame.Min.Y)-bounds.Min.Y),
i2f(fg.frame.Max.X), i2f(fg.frame.Max.X),
bounds.Max.Y()-(i2f(fg.frame.Max.Y)-bounds.Min.Y()), bounds.Max.Y-(i2f(fg.frame.Max.Y)-bounds.Min.Y),
).Norm(), ).Norm(),
Advance: i2f(fg.advance), Advance: i2f(fg.advance),
} }
@ -149,24 +149,24 @@ func (a *Atlas) DrawRune(prevR, r rune, dot pixel.Vec) (rect, frame, bounds pixe
} }
if prevR >= 0 { if prevR >= 0 {
dot += pixel.X(a.Kern(prevR, r)) dot.X += a.Kern(prevR, r)
} }
glyph := a.Glyph(r) glyph := a.Glyph(r)
rect = glyph.Frame.Moved(dot - glyph.Dot) rect = glyph.Frame.Moved(dot.Sub(glyph.Dot))
bounds = rect bounds = rect
if bounds.W()*bounds.H() != 0 { if bounds.W()*bounds.H() != 0 {
bounds = pixel.R( bounds = pixel.R(
bounds.Min.X(), bounds.Min.X,
dot.Y()-a.Descent(), dot.Y-a.Descent(),
bounds.Max.X(), bounds.Max.X,
dot.Y()+a.Ascent(), dot.Y+a.Ascent(),
) )
} }
dot += pixel.X(glyph.Advance) dot.X += glyph.Advance
return rect, glyph.Frame, bounds, dot return rect, glyph.Frame, bounds, dot
} }

View File

@ -39,7 +39,7 @@ func RangeTable(table *unicode.RangeTable) []rune {
// Text allows for effiecient and convenient text drawing. // Text allows for effiecient and convenient text drawing.
// //
// To create a Text object, use the New constructor: // To create a Text object, use the New constructor:
// txt := text.New(pixel.V(0, 0), text.NewAtlas(face, text.ASCII)) // txt := text.New(pixel.ZV, text.NewAtlas(face, text.ASCII))
// //
// As suggested by the constructor, a Text object is always associated with one font face and a // As suggested by the constructor, a Text object is always associated with one font face and a
// fixed set of runes. For example, the Text we created above can draw text using the font face // fixed set of runes. For example, the Text we created above can draw text using the font face
@ -274,17 +274,17 @@ func (txt *Text) DrawColorMask(t pixel.Target, matrix pixel.Matrix, mask color.C
func (txt *Text) controlRune(r rune, dot pixel.Vec) (newDot pixel.Vec, control bool) { func (txt *Text) controlRune(r rune, dot pixel.Vec) (newDot pixel.Vec, control bool) {
switch r { switch r {
case '\n': case '\n':
dot -= pixel.Y(txt.LineHeight) dot.X = txt.Orig.X
dot = dot.WithX(txt.Orig.X()) dot.Y -= txt.LineHeight
case '\r': case '\r':
dot = dot.WithX(txt.Orig.X()) dot.X = txt.Orig.X
case '\t': case '\t':
rem := math.Mod(dot.X()-txt.Orig.X(), txt.TabWidth) rem := math.Mod(dot.X-txt.Orig.X, txt.TabWidth)
rem = math.Mod(rem, rem+txt.TabWidth) rem = math.Mod(rem, rem+txt.TabWidth)
if rem == 0 { if rem == 0 {
rem = txt.TabWidth rem = txt.TabWidth
} }
dot += pixel.X(rem) dot.X += rem
default: default:
return dot, false return dot, false
} }
@ -316,16 +316,18 @@ func (txt *Text) drawBuf() {
txt.prevR = r txt.prevR = r
rv := [...]pixel.Vec{pixel.V(rect.Min.X(), rect.Min.Y()), rv := [...]pixel.Vec{
pixel.V(rect.Max.X(), rect.Min.Y()), {X: rect.Min.X, Y: rect.Min.Y},
pixel.V(rect.Max.X(), rect.Max.Y()), {X: rect.Max.X, Y: rect.Min.Y},
pixel.V(rect.Min.X(), rect.Max.Y()), {X: rect.Max.X, Y: rect.Max.Y},
{X: rect.Min.X, Y: rect.Max.Y},
} }
fv := [...]pixel.Vec{pixel.V(frame.Min.X(), frame.Min.Y()), fv := [...]pixel.Vec{
pixel.V(frame.Max.X(), frame.Min.Y()), {X: frame.Min.X, Y: frame.Min.Y},
pixel.V(frame.Max.X(), frame.Max.Y()), {X: frame.Max.X, Y: frame.Min.Y},
pixel.V(frame.Min.X(), frame.Max.Y()), {X: frame.Max.X, Y: frame.Max.Y},
{X: frame.Min.X, Y: frame.Max.Y},
} }
for i, j := range [...]int{0, 1, 2, 0, 2, 3} { for i, j := range [...]int{0, 1, 2, 0, 2, 3} {