diff --git a/data.go b/data.go index 437d88d..4e6c528 100644 --- a/data.go +++ b/data.go @@ -45,7 +45,7 @@ func (td *TrianglesData) SetLen(len int) { Color RGBA Picture Vec Intensity float64 - }{V(0, 0), Alpha(1), V(0, 0), 0}) + }{ZV, Alpha(1), ZV, 0}) } } if len < td.Len() { @@ -136,8 +136,8 @@ type PictureData struct { // MakePictureData creates a zero-initialized PictureData covering the given rectangle. func MakePictureData(rect Rect) *PictureData { - 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())) + 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)) pd := &PictureData{ Stride: w, Rect: rect, @@ -205,12 +205,12 @@ func PictureDataFromPicture(pic Picture) *PictureData { pd := MakePictureData(bounds) if pic, ok := pic.(PictureColor); ok { - 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 y := math.Floor(bounds.Min.Y); y < bounds.Max.Y; y++ { + 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 at := V( - math.Max(x, bounds.Min.X()), - math.Max(y, bounds.Min.Y()), + math.Max(x, bounds.Min.X), + math.Max(y, bounds.Min.Y), ) col := pic.Color(at) 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. func (pd *PictureData) Image() *image.RGBA { bounds := image.Rect( - int(math.Floor(pd.Rect.Min.X())), - int(math.Floor(pd.Rect.Min.Y())), - int(math.Ceil(pd.Rect.Max.X())), - int(math.Ceil(pd.Rect.Max.Y())), + int(math.Floor(pd.Rect.Min.X)), + int(math.Floor(pd.Rect.Min.Y)), + int(math.Ceil(pd.Rect.Max.X)), + int(math.Ceil(pd.Rect.Max.Y)), ) 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. func (pd *PictureData) Index(at Vec) int { - at -= pd.Rect.Min.Map(math.Floor) - x, y := int(at.X()), int(at.Y()) + at = at.Sub(pd.Rect.Min.Map(math.Floor)) + x, y := int(at.X), int(at.Y) return y*pd.Stride + x } diff --git a/geometry.go b/geometry.go index 8837300..207ab27 100644 --- a/geometry.go +++ b/geometry.go @@ -3,50 +3,38 @@ package pixel 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 -// 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. +// Vec is a 2D vector type with X and Y coordinates. // // Create vectors with the V constructor: // // u := pixel.V(1, 2) // v := pixel.V(8, -3) // -// Add and subtract them using the standard + and - operators: +// Use various methods to manipulate them: // -// w := u + v -// fmt.Println(w) // Vec(9, -1) -// fmt.Println(u - v) // Vec(-7, 5) -// -// Additional standard vector operations can be obtained with methods: -// -// u := pixel.V(2, 3) -// v := pixel.V(8, 1) -// if u.X() < 0 { +// w := u.Add(v) +// fmt.Println(w) // Vec(9, -1) +// fmt.Println(u.Sub(v)) // Vec(-7, 5) +// u = pixel.V(2, 3) +// v = pixel.V(8, 1) +// if u.X < 0 { // fmt.Println("this won't happen") // } // 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. func V(x, y float64) Vec { - return Vec(complex(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) + return Vec{x, y} } // 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)" // fmt.Println(u) // Vec(4.5, -1.3) func (u Vec) String() string { - 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) + return fmt.Sprintf("Vec(%v, %v)", u.X, u.Y) } // XY returns the components of the vector in two return values. 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. -func (u Vec) Len() float64 { - return cmplx.Abs(complex128(u)) -} - -// 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)) -} - -// Unit returns a vector of length 1 facing the direction of u (has the same angle). -func (u Vec) Unit() Vec { - if u == 0 { - return 1 +// Add returns the sum of vectors u and v. +func (u Vec) Add(v Vec) Vec { + return Vec{ + u.X + v.X, + u.Y + v.Y, + } +} + +// Sub returns the difference betweeen vectors u and v. +func (u Vec) Sub(v Vec) Vec { + return Vec{ + u.X - v.X, + u.Y - v.Y, } - return u / V(u.Len(), 0) } // Scaled returns the vector u multiplied by c. 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. 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. func (u Vec) Rotated(angle float64) Vec { sin, cos := math.Sincos(angle) - return u * V(cos, sin) -} - -// 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) + return Vec{ + u.X*cos - u.Y*sin, + u.X*sin + u.Y*cos, + } } // Dot returns the dot product of vectors u and v. 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. 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 @@ -133,10 +120,10 @@ func (u Vec) Cross(v Vec) float64 { // u := pixel.V(10.5, -1.5) // v := u.Map(math.Floor) // v is Vec(10, -2), both components of u floored func (u Vec) Map(f func(float64) float64) Vec { - return V( - f(u.X()), - f(u.Y()), - ) + return Vec{ + f(u.X), + f(u.Y), + } } // 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 // return the appropriate point between a and b and so on. 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 @@ -171,31 +158,31 @@ func R(minX, minY, maxX, maxY float64) Rect { // r.String() // returns "Rect(100, 50, 200, 300)" // fmt.Println(r) // Rect(100, 50, 200, 300) 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. func (r Rect) Norm() Rect { return Rect{ - Min: V( - math.Min(r.Min.X(), r.Max.X()), - math.Min(r.Min.Y(), r.Max.Y()), - ), - Max: V( - math.Max(r.Min.X(), r.Max.X()), - math.Max(r.Min.Y(), r.Max.Y()), - ), + Min: Vec{ + math.Min(r.Min.X, r.Max.X), + math.Min(r.Min.Y, r.Max.Y), + }, + Max: Vec{ + math.Max(r.Min.X, r.Max.X), + math.Max(r.Min.Y, r.Max.Y), + }, } } // W returns the width of the Rect. 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. 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. @@ -205,34 +192,14 @@ func (r Rect) Size() Vec { // Center returns the position of the center of the Rect. 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. func (r Rect) Moved(delta Vec) Rect { return Rect{ - Min: r.Min + delta, - Max: r.Max + 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, + Min: r.Min.Add(delta), + Max: r.Max.Add(delta), } } @@ -249,10 +216,10 @@ func (r Rect) Resized(anchor, size Vec) Rect { if r.W()*r.H() == 0 { 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{ - Min: anchor + (r.Min - anchor).ScaledXY(fraction), - Max: anchor + (r.Max - anchor).ScaledXY(fraction), + Min: anchor.Add(r.Min.Sub(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 { return Rect{ 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). 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. func (r Rect) Union(s Rect) Rect { return R( - math.Min(r.Min.X(), s.Min.X()), - math.Min(r.Min.Y(), s.Min.Y()), - math.Max(r.Max.X(), s.Max.X()), - math.Max(r.Max.Y(), s.Max.Y()), + math.Min(r.Min.X, s.Min.X), + math.Min(r.Min.Y, s.Min.Y), + math.Max(r.Max.X, s.Max.X), + 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. func (m Matrix) ScaledXY(around Vec, scale Vec) Matrix { 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.Translate2D(around.XY()).Mul3(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. func (m Matrix) Rotated(around Vec, angle float64) Matrix { 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.Translate2D(around.XY()).Mul3(m3) return Matrix(m3) @@ -353,7 +320,7 @@ func (m Matrix) Chained(next Matrix) Matrix { // Time complexity is O(1). func (m Matrix) Project(u Vec) Vec { 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()) } @@ -363,6 +330,6 @@ func (m Matrix) Project(u Vec) Vec { func (m Matrix) Unproject(u Vec) Vec { m3 := mgl64.Mat3(m) 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()) } diff --git a/imdraw/imdraw.go b/imdraw/imdraw.go index 3664459..626cb2f 100644 --- a/imdraw/imdraw.go +++ b/imdraw/imdraw.go @@ -111,7 +111,7 @@ func (imd *IMDraw) Clear() { func (imd *IMDraw) Reset() { imd.points = nil imd.Color = pixel.Alpha(1) - imd.Picture = 0 + imd.Picture = pixel.ZV imd.Intensity = 0 imd.Precision = 64 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 { a, b := points[i], points[i+1] 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)), - pic: pixel.V(a.pic.X(), b.pic.Y()), + pic: pixel.V(a.pic.X, b.pic.Y), in: (a.in + b.in) / 2, } 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)), - pic: pixel.V(b.pic.X(), a.pic.Y()), + pic: pixel.V(b.pic.X, a.pic.Y), in: (a.in + b.in) / 2, } @@ -318,9 +318,9 @@ func (imd *IMDraw) outlineRectangle(thickness float64) { mid.in = (a.in + b.in) / 2 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(pixel.V(b.pos.X(), a.pos.Y()), mid) + imd.pushPt(pixel.V(b.pos.X, a.pos.Y), mid) imd.polyline(thickness, true) } } @@ -360,24 +360,24 @@ func (imd *IMDraw) fillEllipseArc(radius pixel.Vec, low, high float64) { for i := range (*imd.tri)[off:] { (*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 } for i, j := 0.0, off; i < num; i, j = i+1, j+3 { angle := low + i*delta sin, cos := math.Sincos(angle) - a := pt.pos + pixel.V( - radius.X()*cos, - radius.Y()*sin, - ) + a := pt.pos.Add(pixel.V( + radius.X*cos, + radius.Y*sin, + )) angle = low + (i+1)*delta sin, cos = math.Sincos(angle) - b := pt.pos + pixel.V( - radius.X()*cos, - radius.Y()*sin, - ) + b := pt.pos.Add(pixel.V( + radius.X*cos, + radius.Y*sin, + )) (*imd.tri)[j+0].Position = pt.pos (*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:] { (*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 } @@ -409,26 +409,26 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa angle := low + i*delta sin, cos := math.Sincos(angle) normalSin, normalCos := pixel.V(sin, cos).ScaledXY(radius).Unit().XY() - a := pt.pos + pixel.V( - radius.X()*cos-thickness/2*normalCos, - radius.Y()*sin-thickness/2*normalSin, - ) - b := pt.pos + pixel.V( - radius.X()*cos+thickness/2*normalCos, - radius.Y()*sin+thickness/2*normalSin, - ) + a := pt.pos.Add(pixel.V( + radius.X*cos-thickness/2*normalCos, + radius.Y*sin-thickness/2*normalSin, + )) + b := pt.pos.Add(pixel.V( + radius.X*cos+thickness/2*normalCos, + radius.Y*sin+thickness/2*normalSin, + )) angle = low + (i+1)*delta sin, cos = math.Sincos(angle) normalSin, normalCos = pixel.V(sin, cos).ScaledXY(radius).Unit().XY() - c := pt.pos + pixel.V( - radius.X()*cos-thickness/2*normalCos, - radius.Y()*sin-thickness/2*normalSin, - ) - d := pt.pos + pixel.V( - radius.X()*cos+thickness/2*normalCos, - radius.Y()*sin+thickness/2*normalSin, - ) + c := pt.pos.Add(pixel.V( + radius.X*cos-thickness/2*normalCos, + radius.Y*sin-thickness/2*normalSin, + )) + d := pt.pos.Add(pixel.V( + radius.X*cos+thickness/2*normalCos, + radius.Y*sin+thickness/2*normalSin, + )) (*imd.tri)[j+0].Position = a (*imd.tri)[j+1].Position = b @@ -443,18 +443,18 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa if doEndShape { lowSin, lowCos := math.Sincos(low) - lowCenter := pt.pos + pixel.V( - radius.X()*lowCos, - radius.Y()*lowSin, - ) + lowCenter := pt.pos.Add(pixel.V( + radius.X*lowCos, + radius.Y*lowSin, + )) normalLowSin, normalLowCos := pixel.V(lowSin, lowCos).ScaledXY(radius).Unit().XY() normalLow := pixel.V(normalLowCos, normalLowSin).Angle() highSin, highCos := math.Sincos(high) - highCenter := pt.pos + pixel.V( - radius.X()*highCos, - radius.Y()*highSin, - ) + highCenter := pt.pos.Add(pixel.V( + radius.X*highCos, + radius.Y*highSin, + )) normalHighSin, normalHighCos := pixel.V(highSin, highCos).ScaledXY(radius).Unit().XY() normalHigh := pixel.V(normalHighCos, normalHighSin).Angle() @@ -467,21 +467,21 @@ func (imd *IMDraw) outlineEllipseArc(radius pixel.Vec, low, high, thickness floa case NoEndShape: // nothing case SharpEndShape: - thick := pixel.X(thickness / 2).Rotated(normalLow) - imd.pushPt(lowCenter+thick, pt) - imd.pushPt(lowCenter-thick, pt) - imd.pushPt(lowCenter-thick.Rotated(math.Pi/2*orientation), pt) + thick := pixel.V(thickness/2, 0).Rotated(normalLow) + imd.pushPt(lowCenter.Add(thick), pt) + imd.pushPt(lowCenter.Sub(thick), pt) + imd.pushPt(lowCenter.Sub(thick.Rotated(math.Pi/2*orientation)), pt) imd.fillPolygon() - thick = pixel.X(thickness / 2).Rotated(normalHigh) - imd.pushPt(highCenter+thick, pt) - imd.pushPt(highCenter-thick, pt) - imd.pushPt(highCenter+thick.Rotated(math.Pi/2*orientation), pt) + thick = pixel.V(thickness/2, 0).Rotated(normalHigh) + imd.pushPt(highCenter.Add(thick), pt) + imd.pushPt(highCenter.Sub(thick), pt) + imd.pushPt(highCenter.Add(thick.Rotated(math.Pi/2*orientation)), pt) imd.fillPolygon() case RoundEndShape: 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.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 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 { switch points[j].endshape { case NoEndShape: // nothing case SharpEndShape: - imd.pushPt(points[j].pos+normal, points[j]) - imd.pushPt(points[j].pos-normal, points[j]) - imd.pushPt(points[j].pos+normal.Rotated(math.Pi/2), points[j]) + imd.pushPt(points[j].pos.Add(normal), points[j]) + imd.pushPt(points[j].pos.Sub(normal), points[j]) + imd.pushPt(points[j].pos.Add(normal.Rotated(math.Pi/2)), points[j]) imd.fillPolygon() case RoundEndShape: 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-normal, points[j]) + imd.pushPt(points[j].pos.Add(normal), points[j]) + imd.pushPt(points[j].pos.Sub(normal), points[j]) // middle points for i := 0; i < len(points); i++ { @@ -536,16 +536,16 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) { k %= len(points) } - ijNormal := (points[j].pos - 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) + ijNormal := points[j].pos.Sub(points[i].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 if ijNormal.Cross(jkNormal) > 0 { orientation = -1.0 } - imd.pushPt(points[j].pos-ijNormal, points[j]) - imd.pushPt(points[j].pos+ijNormal, points[j]) + imd.pushPt(points[j].pos.Sub(ijNormal), points[j]) + imd.pushPt(points[j].pos.Add(ijNormal), points[j]) imd.fillPolygon() switch points[j].endshape { @@ -553,28 +553,28 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) { // nothing case SharpEndShape: imd.pushPt(points[j].pos, points[j]) - imd.pushPt(points[j].pos+ijNormal.Scaled(orientation), points[j]) - imd.pushPt(points[j].pos+jkNormal.Scaled(orientation), points[j]) + imd.pushPt(points[j].pos.Add(ijNormal.Scaled(orientation)), points[j]) + imd.pushPt(points[j].pos.Add(jkNormal.Scaled(orientation)), points[j]) imd.fillPolygon() case RoundEndShape: 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.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 { - imd.pushPt(points[j].pos+jkNormal, points[j]) - imd.pushPt(points[j].pos-jkNormal, points[j]) + imd.pushPt(points[j].pos.Add(jkNormal), points[j]) + imd.pushPt(points[j].pos.Sub(jkNormal), points[j]) } } // last point 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+normal, points[j]) + imd.pushPt(points[j].pos.Sub(normal), points[j]) + imd.pushPt(points[j].pos.Add(normal), points[j]) imd.fillPolygon() if !closed { @@ -582,13 +582,13 @@ func (imd *IMDraw) polyline(thickness float64, closed bool) { case NoEndShape: // nothing case SharpEndShape: - imd.pushPt(points[j].pos+normal, points[j]) - imd.pushPt(points[j].pos-normal, points[j]) - imd.pushPt(points[j].pos+normal.Rotated(-math.Pi/2), points[j]) + imd.pushPt(points[j].pos.Add(normal), points[j]) + imd.pushPt(points[j].pos.Sub(normal), points[j]) + imd.pushPt(points[j].pos.Add(normal.Rotated(-math.Pi/2)), points[j]) imd.fillPolygon() case RoundEndShape: 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) } } } diff --git a/pixelgl/canvas.go b/pixelgl/canvas.go index 038bcc0..070a382 100644 --- a/pixelgl/canvas.go +++ b/pixelgl/canvas.go @@ -285,8 +285,8 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, bounds pixel.Rect) { dstBounds := ct.dst.Bounds() shader.SetUniformAttr(canvasBounds, mgl32.Vec4{ - float32(dstBounds.Min.X()), - float32(dstBounds.Min.Y()), + float32(dstBounds.Min.X), + float32(dstBounds.Min.Y), float32(dstBounds.W()), float32(dstBounds.H()), }) diff --git a/pixelgl/glframe.go b/pixelgl/glframe.go index 790fe5c..ab35725 100644 --- a/pixelgl/glframe.go +++ b/pixelgl/glframe.go @@ -70,7 +70,7 @@ func (gf *GLFrame) Color(at pixel.Vec) pixel.RGBA { return pixel.Alpha(0) } 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 return pixel.RGBA{ R: float64(gf.pixels[off*4+0]) / 255, diff --git a/pixelgl/glpicture.go b/pixelgl/glpicture.go index c249b60..659f014 100644 --- a/pixelgl/glpicture.go +++ b/pixelgl/glpicture.go @@ -42,8 +42,8 @@ func NewGLPicture(p pixel.Picture) GLPicture { for y := 0; y < bh; y++ { for x := 0; x < bw; x++ { at := pixel.V( - math.Max(float64(bx+x), bounds.Min.X()), - math.Max(float64(by+y), bounds.Min.Y()), + math.Max(float64(bx+x), bounds.Min.X), + math.Max(float64(by+y), bounds.Min.Y), ) color := p.Color(at) off := (y*bw + x) * 4 @@ -87,7 +87,7 @@ func (gp *glPicture) Color(at pixel.Vec) pixel.RGBA { return pixel.Alpha(0) } 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 return pixel.RGBA{ R: float64(gp.pixels[off*4+0]) / 255, diff --git a/pixelgl/gltriangles.go b/pixelgl/gltriangles.go index 3e6879a..64b7355 100644 --- a/pixelgl/gltriangles.go +++ b/pixelgl/gltriangles.go @@ -135,8 +135,8 @@ func (gt *GLTriangles) updateData(t pixel.Triangles) { if t, ok := t.(pixel.TrianglesPicture); ok { for i := 0; i < gt.Len(); i++ { pic, intensity := t.Picture(i) - 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()+6] = float32(pic.X) + gt.data[i*gt.vs.Stride()+7] = float32(pic.Y) gt.data[i*gt.vs.Stride()+8] = float32(intensity) } } diff --git a/pixelgl/input.go b/pixelgl/input.go index ea6c7fd..ff98805 100644 --- a/pixelgl/input.go +++ b/pixelgl/input.go @@ -356,13 +356,14 @@ func (w *Window) initInput() { w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) { w.tempInp.mouse = pixel.V( - x+w.bounds.Min.X(), - (w.bounds.H()-y)+w.bounds.Min.Y(), + x+w.bounds.Min.X, + (w.bounds.H()-y)+w.bounds.Min.Y, ) }) 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) { @@ -380,6 +381,6 @@ func (w *Window) updateInput() { w.currInp = w.tempInp w.tempInp.repeat = [KeyLast + 1]bool{} - w.tempInp.scroll = 0 + w.tempInp.scroll = pixel.ZV w.tempInp.typed = "" } diff --git a/pixelgl/util.go b/pixelgl/util.go index a0ed593..c11ea3c 100644 --- a/pixelgl/util.go +++ b/pixelgl/util.go @@ -7,9 +7,9 @@ import ( ) func intBounds(bounds pixel.Rect) (x, y, w, h int) { - x0 := int(math.Floor(bounds.Min.X())) - y0 := int(math.Floor(bounds.Min.Y())) - x1 := int(math.Ceil(bounds.Max.X())) - y1 := int(math.Ceil(bounds.Max.Y())) + x0 := int(math.Floor(bounds.Min.X)) + y0 := int(math.Floor(bounds.Min.Y)) + x1 := int(math.Ceil(bounds.Max.X)) + y1 := int(math.Ceil(bounds.Max.Y)) return x0, y0, x1 - x0, y1 - y0 } diff --git a/pixelgl/window.go b/pixelgl/window.go index 29b28fd..afbd5f7 100644 --- a/pixelgl/window.go +++ b/pixelgl/window.go @@ -160,10 +160,10 @@ func (w *Window) Update() { mainthread.Call(func() { _, _, oldW, oldH := intBounds(w.bounds) 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(newH-oldH), - )) + ))) }) w.canvas.SetBounds(w.bounds) diff --git a/sprite.go b/sprite.go index ac12eac..0808759 100644 --- a/sprite.go +++ b/sprite.go @@ -90,20 +90,20 @@ func (s *Sprite) DrawColorMask(t Target, matrix Matrix, mask color.Color) { func (s *Sprite) calcData() { var ( center = s.frame.Center() - horizontal = X(s.frame.W() / 2) - vertical = Y(s.frame.H() / 2) + horizontal = V(s.frame.W()/2, 0) + vertical = V(0, s.frame.H()/2) ) - (*s.tri)[0].Position = -horizontal - vertical - (*s.tri)[1].Position = +horizontal - vertical - (*s.tri)[2].Position = +horizontal + vertical - (*s.tri)[3].Position = -horizontal - vertical - (*s.tri)[4].Position = +horizontal + vertical - (*s.tri)[5].Position = -horizontal + vertical + (*s.tri)[0].Position = Vec{}.Sub(horizontal).Sub(vertical) + (*s.tri)[1].Position = Vec{}.Add(horizontal).Sub(vertical) + (*s.tri)[2].Position = Vec{}.Add(horizontal).Add(vertical) + (*s.tri)[3].Position = Vec{}.Sub(horizontal).Sub(vertical) + (*s.tri)[4].Position = Vec{}.Add(horizontal).Add(vertical) + (*s.tri)[5].Position = Vec{}.Sub(horizontal).Add(vertical) for i := range *s.tri { (*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 } diff --git a/text/atlas.go b/text/atlas.go index c7e189e..cf9231c 100644 --- a/text/atlas.go +++ b/text/atlas.go @@ -73,13 +73,13 @@ func NewAtlas(face font.Face, runeSets ...[]rune) *Atlas { mapping[r] = Glyph{ Dot: pixel.V( 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( 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), - bounds.Max.Y()-(i2f(fg.frame.Max.Y)-bounds.Min.Y()), + bounds.Max.Y-(i2f(fg.frame.Max.Y)-bounds.Min.Y), ).Norm(), 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 { - dot += pixel.X(a.Kern(prevR, r)) + dot.X += a.Kern(prevR, r) } glyph := a.Glyph(r) - rect = glyph.Frame.Moved(dot - glyph.Dot) + rect = glyph.Frame.Moved(dot.Sub(glyph.Dot)) bounds = rect if bounds.W()*bounds.H() != 0 { bounds = pixel.R( - bounds.Min.X(), - dot.Y()-a.Descent(), - bounds.Max.X(), - dot.Y()+a.Ascent(), + bounds.Min.X, + dot.Y-a.Descent(), + bounds.Max.X, + dot.Y+a.Ascent(), ) } - dot += pixel.X(glyph.Advance) + dot.X += glyph.Advance return rect, glyph.Frame, bounds, dot } diff --git a/text/text.go b/text/text.go index 553bc74..ea6d194 100644 --- a/text/text.go +++ b/text/text.go @@ -39,7 +39,7 @@ func RangeTable(table *unicode.RangeTable) []rune { // Text allows for effiecient and convenient text drawing. // // 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 // 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) { switch r { case '\n': - dot -= pixel.Y(txt.LineHeight) - dot = dot.WithX(txt.Orig.X()) + dot.X = txt.Orig.X + dot.Y -= txt.LineHeight case '\r': - dot = dot.WithX(txt.Orig.X()) + dot.X = txt.Orig.X 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) if rem == 0 { rem = txt.TabWidth } - dot += pixel.X(rem) + dot.X += rem default: return dot, false } @@ -316,16 +316,18 @@ func (txt *Text) drawBuf() { txt.prevR = r - rv := [...]pixel.Vec{pixel.V(rect.Min.X(), rect.Min.Y()), - pixel.V(rect.Max.X(), rect.Min.Y()), - pixel.V(rect.Max.X(), rect.Max.Y()), - pixel.V(rect.Min.X(), rect.Max.Y()), + rv := [...]pixel.Vec{ + {X: rect.Min.X, Y: rect.Min.Y}, + {X: rect.Max.X, Y: rect.Min.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()), - pixel.V(frame.Max.X(), frame.Min.Y()), - pixel.V(frame.Max.X(), frame.Max.Y()), - pixel.V(frame.Min.X(), frame.Max.Y()), + fv := [...]pixel.Vec{ + {X: frame.Min.X, Y: frame.Min.Y}, + {X: frame.Max.X, Y: frame.Min.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} {