change Rect to have Min, Max instead of Pos, Size
This commit is contained in:
parent
bca582815c
commit
203adc914b
24
data.go
24
data.go
|
@ -134,8 +134,8 @@ type PictureData struct {
|
|||
|
||||
// MakePictureData creates a zero-initialized PictureData covering the given rectangle.
|
||||
func MakePictureData(rect Rect) *PictureData {
|
||||
w := int(math.Ceil(rect.Pos.X()+rect.Size.X())) - int(math.Floor(rect.Pos.X()))
|
||||
h := int(math.Ceil(rect.Pos.Y()+rect.Size.Y())) - int(math.Floor(rect.Pos.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,
|
||||
|
@ -206,12 +206,12 @@ func PictureDataFromPicture(pic Picture) *PictureData {
|
|||
pd := MakePictureData(bounds)
|
||||
|
||||
if pic, ok := pic.(PictureColor); ok {
|
||||
for y := math.Floor(bounds.Pos.Y()); y < bounds.Pos.Y()+bounds.Size.Y(); y++ {
|
||||
for x := math.Floor(bounds.Pos.X()); x < bounds.Pos.X()+bounds.Size.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.Pos.X()),
|
||||
math.Max(y, bounds.Pos.Y()),
|
||||
math.Max(x, bounds.Min.X()),
|
||||
math.Max(y, bounds.Min.Y()),
|
||||
)
|
||||
pd.SetColor(at, pic.Color(at))
|
||||
}
|
||||
|
@ -226,10 +226,10 @@ func PictureDataFromPicture(pic Picture) *PictureData {
|
|||
// The resulting image.NRGBA's Bounds will be equivalent of the PictureData's Bounds.
|
||||
func (pd *PictureData) Image() *image.NRGBA {
|
||||
bounds := image.Rect(
|
||||
int(math.Floor(pd.Rect.Pos.X())),
|
||||
int(math.Floor(pd.Rect.Pos.Y())),
|
||||
int(math.Ceil(pd.Rect.Pos.X()+pd.Rect.Size.X())),
|
||||
int(math.Ceil(pd.Rect.Pos.Y()+pd.Rect.Size.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())),
|
||||
)
|
||||
nrgba := image.NewNRGBA(bounds)
|
||||
|
||||
|
@ -251,7 +251,7 @@ func (pd *PictureData) Image() *image.NRGBA {
|
|||
}
|
||||
|
||||
func (pd *PictureData) offset(at Vec) int {
|
||||
at -= pd.Rect.Pos.Map(math.Floor)
|
||||
at -= pd.Rect.Min.Map(math.Floor)
|
||||
x, y := int(at.X()), int(at.Y())
|
||||
return y*pd.Stride + x
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ func (pd *PictureData) Bounds() Rect {
|
|||
// Slice returns a sub-Picture of this PictureData inside the supplied rectangle.
|
||||
func (pd *PictureData) Slice(r Rect) Picture {
|
||||
return &PictureData{
|
||||
Pix: pd.Pix[pd.offset(r.Pos):],
|
||||
Pix: pd.Pix[pd.offset(r.Min):],
|
||||
Stride: pd.Stride,
|
||||
Rect: r,
|
||||
Orig: pd.Orig,
|
||||
|
|
112
geometry.go
112
geometry.go
|
@ -83,6 +83,11 @@ func (u Vec) Scaled(c float64) Vec {
|
|||
return u * V(c, 0)
|
||||
}
|
||||
|
||||
// ScaledXY returns the vector u multiplied by vector v component-wise.
|
||||
func (u Vec) ScaledXY(v Vec) Vec {
|
||||
return V(u.X()*v.X(), u.Y()*v.Y())
|
||||
}
|
||||
|
||||
// Rotated returns the vector u rotated by the given angle in radians.
|
||||
func (u Vec) Rotated(angle float64) Vec {
|
||||
sin, cos := math.Sincos(angle)
|
||||
|
@ -117,19 +122,34 @@ func Lerp(a, b Vec, t float64) Vec {
|
|||
return a.Scaled(1-t) + b.Scaled(t)
|
||||
}
|
||||
|
||||
// Rect is a 2D rectangle aligned with the axes of the coordinate system. It has a position
|
||||
// and a size.
|
||||
// Rect is a 2D rectangle aligned with the axes of the coordinate system. It is defined by two
|
||||
// points, Min and Max.
|
||||
//
|
||||
// You can manipulate the position and the size using the usual vector operations.
|
||||
// The invariant should hold, that Max's components are greater or equal than Min's components
|
||||
// respectively.
|
||||
type Rect struct {
|
||||
Pos, Size Vec
|
||||
Min, Max Vec
|
||||
}
|
||||
|
||||
// R returns a new Rect with given position (x, y) and size (w, h).
|
||||
func R(x, y, w, h float64) Rect {
|
||||
// R returns a new Rect with given the Min and Max coordinates.
|
||||
func R(minX, minY, maxX, maxY float64) Rect {
|
||||
return Rect{
|
||||
Pos: V(x, y),
|
||||
Size: V(w, h),
|
||||
Min: V(minX, minY),
|
||||
Max: V(maxX, maxY),
|
||||
}.Norm()
|
||||
}
|
||||
|
||||
// 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()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,43 +159,63 @@ func R(x, y, w, h 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.X(), r.Y(), r.W(), r.H())
|
||||
}
|
||||
|
||||
// X returns the x coordinate of the position of the rectangle.
|
||||
func (r Rect) X() float64 {
|
||||
return r.Pos.X()
|
||||
}
|
||||
|
||||
// Y returns the y coordinate of the position of the rectangle
|
||||
func (r Rect) Y() float64 {
|
||||
return r.Pos.Y()
|
||||
return fmt.Sprintf("Rect(%v, %v, %v, %v)", r.Min.X(), r.Min.Y(), r.Max.X(), r.Max.Y())
|
||||
}
|
||||
|
||||
// W returns the width of the rectangle.
|
||||
func (r Rect) W() float64 {
|
||||
return r.Size.X()
|
||||
return r.Max.X() - r.Min.X()
|
||||
}
|
||||
|
||||
// H returns the height of the rectangle.
|
||||
func (r Rect) H() float64 {
|
||||
return r.Size.Y()
|
||||
}
|
||||
|
||||
// XYWH returns all of the four components of the rectangle in four return values.
|
||||
func (r Rect) XYWH() (x, y, w, h float64) {
|
||||
return r.X(), r.Y(), r.W(), r.H()
|
||||
return r.Max.Y() - r.Min.Y()
|
||||
}
|
||||
|
||||
// Center returns the position of the center of the rectangle.
|
||||
func (r Rect) Center() Vec {
|
||||
return r.Pos + r.Size.Scaled(0.5)
|
||||
return (r.Min + r.Max) / 2
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
|
||||
// Resized returns the Rect resized to the given size while keeping the position of the given anchor.
|
||||
// r.Resized(r.Min, size) // resizes while keeping the position of the lower-left corner
|
||||
// r.Resized(r.Max, size) // same with the top-right corner
|
||||
// r.Resized(r.Center(), size) // resizes around the center
|
||||
// This function does not make sense for size of zero area and will panic. Use ResizeMin in the case
|
||||
// of zero area.
|
||||
func (r Rect) Resized(anchor, size Vec) Rect {
|
||||
if r.W()*r.H() == 0 || size.X()*size.Y() == 0 {
|
||||
panic(fmt.Errorf("(%T).Resize: zero area", r))
|
||||
}
|
||||
fraction := size.ScaledXY(V(1/r.W(), 1/r.H()))
|
||||
return Rect{
|
||||
Min: anchor + (r.Min - anchor).ScaledXY(fraction),
|
||||
Max: anchor + (r.Max - anchor).ScaledXY(fraction),
|
||||
}
|
||||
}
|
||||
|
||||
// ResizedMin returns the Rect resized to the given size while keeping the position of the Rect's
|
||||
// Min.
|
||||
//
|
||||
// Sizes of zero area are safe here.
|
||||
func (r Rect) ResizedMin(size Vec) Rect {
|
||||
return Rect{
|
||||
Min: r.Min,
|
||||
Max: r.Min + size,
|
||||
}
|
||||
}
|
||||
|
||||
// Contains checks whether a vector u is contained within this Rect (including it's borders).
|
||||
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()
|
||||
return r.Min.X() <= u.X() && u.X() <= r.Max.X() && r.Min.Y() <= u.Y() && u.Y() <= r.Max.Y()
|
||||
}
|
||||
|
||||
// Matrix is a 3x3 transformation matrix that can be used for all kinds of spacial transforms, such
|
||||
|
@ -200,8 +240,8 @@ func (m Matrix) Move(delta Vec) Matrix {
|
|||
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 {
|
||||
// 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.Scale2D(scale.XY()).Mul3(m3)
|
||||
|
@ -209,13 +249,13 @@ func (m Matrix) ScaleXY(around Vec, scale Vec) Matrix {
|
|||
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))
|
||||
// Scaled scales everything around a given point by the scale factor.
|
||||
func (m Matrix) Scaled(around Vec, scale float64) Matrix {
|
||||
return m.ScaledXY(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 {
|
||||
// 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.Rotate3DZ(angle).Mul3(m3)
|
||||
|
|
50
graphics.go
50
graphics.go
|
@ -79,10 +79,10 @@ type IM struct {
|
|||
}
|
||||
|
||||
type point struct {
|
||||
position Vec
|
||||
color NRGBA
|
||||
picture Vec
|
||||
intensity float64
|
||||
pos Vec
|
||||
col NRGBA
|
||||
pic Vec
|
||||
in float64
|
||||
width float64
|
||||
precision int
|
||||
endshape EndShape
|
||||
|
@ -130,25 +130,25 @@ func (im *IM) Draw(t Target) {
|
|||
func (im *IM) Push(pts ...Vec) {
|
||||
point := im.opts
|
||||
for _, pt := range pts {
|
||||
point.position = im.matrix.Project(pt)
|
||||
point.color = im.mask.Mul(im.opts.color)
|
||||
point.pos = im.matrix.Project(pt)
|
||||
point.col = im.mask.Mul(im.opts.col)
|
||||
im.points = append(im.points, point)
|
||||
}
|
||||
}
|
||||
|
||||
// Color sets the color of the next Pushed points.
|
||||
func (im *IM) Color(color color.Color) {
|
||||
im.opts.color = NRGBAModel.Convert(color).(NRGBA)
|
||||
im.opts.col = NRGBAModel.Convert(color).(NRGBA)
|
||||
}
|
||||
|
||||
// Picture sets the Picture coordinates of the next Pushed points.
|
||||
func (im *IM) Picture(pic Vec) {
|
||||
im.opts.picture = pic
|
||||
im.opts.pic = pic
|
||||
}
|
||||
|
||||
// Intensity sets the picture Intensity of the next Pushed points.
|
||||
func (im *IM) Intensity(in float64) {
|
||||
im.opts.intensity = in
|
||||
im.opts.in = in
|
||||
}
|
||||
|
||||
// Width sets the with property of the next Pushed points.
|
||||
|
@ -200,20 +200,20 @@ func (im *IM) FillConvexPolygon() {
|
|||
im.tri.SetLen(im.tri.Len() + 3*(len(points)-2))
|
||||
|
||||
for j := 1; j+1 < len(points); j++ {
|
||||
(*im.tri)[i].Position = points[0].position
|
||||
(*im.tri)[i].Color = points[0].color
|
||||
(*im.tri)[i].Picture = points[0].picture
|
||||
(*im.tri)[i].Intensity = points[0].intensity
|
||||
(*im.tri)[i].Position = points[0].pos
|
||||
(*im.tri)[i].Color = points[0].col
|
||||
(*im.tri)[i].Picture = points[0].pic
|
||||
(*im.tri)[i].Intensity = points[0].in
|
||||
|
||||
(*im.tri)[i+1].Position = points[j].position
|
||||
(*im.tri)[i+1].Color = points[j].color
|
||||
(*im.tri)[i+1].Picture = points[j].picture
|
||||
(*im.tri)[i+1].Intensity = points[j].intensity
|
||||
(*im.tri)[i+1].Position = points[j].pos
|
||||
(*im.tri)[i+1].Color = points[j].col
|
||||
(*im.tri)[i+1].Picture = points[j].pic
|
||||
(*im.tri)[i+1].Intensity = points[j].in
|
||||
|
||||
(*im.tri)[i+2].Position = points[j+1].position
|
||||
(*im.tri)[i+2].Color = points[j+1].color
|
||||
(*im.tri)[i+2].Picture = points[j+1].picture
|
||||
(*im.tri)[i+2].Intensity = points[j+1].intensity
|
||||
(*im.tri)[i+2].Position = points[j+1].pos
|
||||
(*im.tri)[i+2].Color = points[j+1].col
|
||||
(*im.tri)[i+2].Picture = points[j+1].pic
|
||||
(*im.tri)[i+2].Intensity = points[j+1].in
|
||||
|
||||
i += 3
|
||||
}
|
||||
|
@ -248,14 +248,14 @@ func (im *IM) FillEllipseArc(radius Vec, low, high float64) {
|
|||
}
|
||||
|
||||
for _, pt := range points {
|
||||
im.Push(pt.position) // center
|
||||
im.Push(pt.pos) // center
|
||||
|
||||
num := math.Ceil(math.Abs(high-low) / (2 * math.Pi) * float64(pt.precision))
|
||||
delta := (high - low) / num
|
||||
for i := range im.tmp[:int(num)+1] {
|
||||
angle := low + float64(i)*delta
|
||||
sin, cos := math.Sincos(angle)
|
||||
im.tmp[i] = pt.position + V(
|
||||
im.tmp[i] = pt.pos + V(
|
||||
radius.X()*cos,
|
||||
radius.Y()*sin,
|
||||
)
|
||||
|
@ -265,7 +265,3 @@ func (im *IM) FillEllipseArc(radius Vec, low, high float64) {
|
|||
im.FillConvexPolygon()
|
||||
}
|
||||
}
|
||||
|
||||
func (im *IM) Line() {
|
||||
|
||||
}
|
||||
|
|
|
@ -105,8 +105,8 @@ func (c *Canvas) MakePicture(p pixel.Picture) pixel.TargetPicture {
|
|||
for y := 0; y < bh; y++ {
|
||||
for x := 0; x < bw; x++ {
|
||||
at := pixel.V(
|
||||
math.Max(float64(bx+x), bounds.Pos.X()),
|
||||
math.Max(float64(by+y), bounds.Pos.Y()),
|
||||
math.Max(float64(bx+x), bounds.Min.X()),
|
||||
math.Max(float64(by+y), bounds.Min.Y()),
|
||||
)
|
||||
color := p.Color(at)
|
||||
pixels[(y*bw+x)*4+0] = uint8(color.R * 255)
|
||||
|
@ -179,7 +179,7 @@ func (c *Canvas) SetBounds(bounds pixel.Rect) {
|
|||
// preserve old content
|
||||
if oldF != nil {
|
||||
relBounds := bounds
|
||||
relBounds.Pos -= c.orig.borders.Pos
|
||||
relBounds = relBounds.Moved(-c.orig.borders.Min)
|
||||
ox, oy, ow, oh := intBounds(relBounds)
|
||||
oldF.Blit(
|
||||
c.f,
|
||||
|
@ -216,7 +216,7 @@ func (c *Canvas) Smooth() bool {
|
|||
// must be manually called inside mainthread
|
||||
func (c *Canvas) setGlhfBounds() {
|
||||
bounds := c.bounds
|
||||
bounds.Pos -= c.orig.borders.Pos
|
||||
bounds.Moved(c.orig.borders.Min)
|
||||
bx, by, bw, bh := intBounds(bounds)
|
||||
glhf.Bounds(bx, by, bw, bh)
|
||||
}
|
||||
|
@ -311,8 +311,8 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, borders, bounds pixel.Rect) {
|
|||
ct.dst.s.Begin()
|
||||
|
||||
ct.dst.s.SetUniformAttr(canvasBounds, mgl32.Vec4{
|
||||
float32(ct.dst.bounds.X()),
|
||||
float32(ct.dst.bounds.Y()),
|
||||
float32(ct.dst.bounds.Min.X()),
|
||||
float32(ct.dst.bounds.Min.Y()),
|
||||
float32(ct.dst.bounds.W()),
|
||||
float32(ct.dst.bounds.H()),
|
||||
})
|
||||
|
@ -327,14 +327,14 @@ func (ct *canvasTriangles) draw(tex *glhf.Texture, borders, bounds pixel.Rect) {
|
|||
tex.Begin()
|
||||
|
||||
ct.dst.s.SetUniformAttr(canvasTexBorders, mgl32.Vec4{
|
||||
float32(borders.X()),
|
||||
float32(borders.Y()),
|
||||
float32(borders.Min.X()),
|
||||
float32(borders.Min.Y()),
|
||||
float32(borders.W()),
|
||||
float32(borders.H()),
|
||||
})
|
||||
ct.dst.s.SetUniformAttr(canvasTexBounds, mgl32.Vec4{
|
||||
float32(bounds.X()),
|
||||
float32(bounds.Y()),
|
||||
float32(bounds.Min.X()),
|
||||
float32(bounds.Min.Y()),
|
||||
float32(bounds.W()),
|
||||
float32(bounds.H()),
|
||||
})
|
||||
|
|
|
@ -342,8 +342,8 @@ func (w *Window) initInput() {
|
|||
|
||||
w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
|
||||
w.currInp.mouse = pixel.V(
|
||||
x+w.bounds.X(),
|
||||
(w.bounds.H()-y)+w.bounds.Y(),
|
||||
x+w.bounds.Min.X(),
|
||||
(w.bounds.H()-y)+w.bounds.Min.Y(),
|
||||
)
|
||||
})
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@ import (
|
|||
)
|
||||
|
||||
func intBounds(bounds pixel.Rect) (x, y, w, h int) {
|
||||
x0 := int(math.Floor(bounds.Pos.X()))
|
||||
y0 := int(math.Floor(bounds.Pos.Y()))
|
||||
x1 := int(math.Ceil(bounds.Pos.X() + bounds.Size.X()))
|
||||
y1 := int(math.Ceil(bounds.Pos.Y() + bounds.Size.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
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package pixelgl
|
|||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
"runtime"
|
||||
|
||||
"github.com/faiface/glhf"
|
||||
|
@ -147,14 +146,7 @@ func (w *Window) Destroy() {
|
|||
func (w *Window) Update() {
|
||||
mainthread.Call(func() {
|
||||
wi, hi := w.window.GetSize()
|
||||
w.bounds.Size = pixel.V(float64(wi), float64(hi))
|
||||
// fractional positions end up covering more pixels with less size
|
||||
if w.bounds.X() != math.Floor(w.bounds.X()) {
|
||||
w.bounds.Size -= pixel.V(1, 0)
|
||||
}
|
||||
if w.bounds.Y() != math.Floor(w.bounds.Y()) {
|
||||
w.bounds.Size -= pixel.V(0, 1)
|
||||
}
|
||||
w.bounds = w.bounds.ResizedMin(pixel.V(float64(wi), float64(hi)))
|
||||
})
|
||||
|
||||
w.canvas.SetBounds(w.Bounds())
|
||||
|
|
Loading…
Reference in New Issue