From fc79ec5c940584276a623c863f04607622ad1eec Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Tue, 26 Apr 2022 10:46:20 +0200 Subject: [PATCH] layout: [API] remove FRect We're about to unexport f32.Rectangle, this change removes the only public API for it. Signed-off-by: Elias Naur --- gpu/compute.go | 4 +- gpu/gpu.go | 22 ++++- internal/f32/f32.go | 204 ++++++++++++++++++++++++++++++++++++++++++++ layout/layout.go | 7 -- 4 files changed, 224 insertions(+), 13 deletions(-) create mode 100644 internal/f32/f32.go diff --git a/gpu/compute.go b/gpu/compute.go index a4e6fbc2..7afb179c 100644 --- a/gpu/compute.go +++ b/gpu/compute.go @@ -855,7 +855,7 @@ func (g *compute) blitLayers(d driver.LoadDesc, fbo driver.Texture, viewport ima for _, l := range layers { placef := layout.FPt(l.alloc.rect.Min) sizef := layout.FPt(l.rect.Size()) - r := layout.FRect(l.rect) + r := frect(l.rect) quad := [4]layerVertex{ {posX: float32(r.Min.X), posY: float32(r.Min.Y), u: placef.X, v: placef.Y}, {posX: float32(r.Max.X), posY: float32(r.Min.Y), u: placef.X + sizef.X, v: placef.Y}, @@ -1782,7 +1782,7 @@ func (c *collector) collect(root *op.Ops, viewport image.Point, texOps *[]textur case ops.TypeClip: var op ops.ClipOp op.Decode(encOp.Data) - bounds := layout.FRect(op.Bounds) + bounds := frect(op.Bounds) c.addClip(&state, fview, bounds, pathData.data, pathData.key, pathData.hash, strWidth, true) pathData.data = nil strWidth = 0 diff --git a/gpu/gpu.go b/gpu/gpu.go index 213850c5..8bb6fa69 100644 --- a/gpu/gpu.go +++ b/gpu/gpu.go @@ -695,8 +695,8 @@ func (r *renderer) intersectPath(p *pathOp, clip image.Rectangle) { } fbo := r.pather.stenciler.cover(p.place.Idx) r.ctx.BindTexture(0, fbo.tex) - coverScale, coverOff := texSpaceTransform(layout.FRect(uv), fbo.size) - subScale, subOff := texSpaceTransform(layout.FRect(sub), p.clip.Size()) + coverScale, coverOff := texSpaceTransform(frect(uv), fbo.size) + subScale, subOff := texSpaceTransform(frect(sub), p.clip.Size()) r.pather.stenciler.ipipeline.uniforms.vert.uvTransform = [4]float32{coverScale.X, coverScale.Y, coverOff.X, coverOff.Y} r.pather.stenciler.ipipeline.uniforms.vert.subUVTransform = [4]float32{subScale.X, subScale.Y, subOff.X, subOff.Y} r.pather.stenciler.ipipeline.pipeline.UploadUniforms(r.ctx) @@ -888,7 +888,7 @@ loop: var op ops.ClipOp op.Decode(encOp.Data) quads.key.outline = op.Outline - bounds := layout.FRect(op.Bounds) + bounds := frect(op.Bounds) trans, off := splitTransform(state.t) if len(quads.aux) > 0 { // There is a clipping path, build the gpu data and update the @@ -1108,7 +1108,7 @@ func (r *renderer) drawOps(cache *resourceCache, ops []imageOp) { Min: img.place.Pos, Max: img.place.Pos.Add(drc.Size()), } - coverScale, coverOff := texSpaceTransform(layout.FRect(uv), fbo.size) + coverScale, coverOff := texSpaceTransform(frect(uv), fbo.size) p := r.pather.coverer.pipelines[m.material] r.ctx.BindPipeline(p.pipeline) r.ctx.BindVertexBuffer(r.blitter.quadVerts, 0) @@ -1406,3 +1406,17 @@ func isPureOffset(t f32.Affine2D) bool { a, b, _, d, e, _ := t.Elems() return a == 1 && b == 0 && d == 0 && e == 1 } + +// frect converts a rectangle to a f32.Rectangle. +func frect(r image.Rectangle) f32.Rectangle { + return f32.Rectangle{ + Min: fpt(r.Min), Max: fpt(r.Max), + } +} + +// fpt converts an point to a f32.Point. +func fpt(p image.Point) f32.Point { + return f32.Point{ + X: float32(p.X), Y: float32(p.Y), + } +} diff --git a/internal/f32/f32.go b/internal/f32/f32.go new file mode 100644 index 00000000..044cc51b --- /dev/null +++ b/internal/f32/f32.go @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +/* +Package f32 is a float32 implementation of package image's +Point and Rectangle. + +The coordinate space has the origin in the top left +corner with the axes extending right and down. +*/ +package f32 + +import ( + "image" + "math" + "strconv" +) + +// A Point is a two dimensional point. +type Point struct { + X, Y float32 +} + +// String return a string representation of p. +func (p Point) String() string { + return "(" + strconv.FormatFloat(float64(p.X), 'f', -1, 32) + + "," + strconv.FormatFloat(float64(p.Y), 'f', -1, 32) + ")" +} + +// A Rectangle contains the points (X, Y) where Min.X <= X < Max.X, +// Min.Y <= Y < Max.Y. +type Rectangle struct { + Min, Max Point +} + +// String return a string representation of r. +func (r Rectangle) String() string { + return r.Min.String() + "-" + r.Max.String() +} + +// Rect is a shorthand for Rectangle{Point{x0, y0}, Point{x1, y1}}. +// The returned Rectangle has x0 and y0 swapped if necessary so that +// it's correctly formed. +func Rect(x0, y0, x1, y1 float32) Rectangle { + if x0 > x1 { + x0, x1 = x1, x0 + } + if y0 > y1 { + y0, y1 = y1, y0 + } + return Rectangle{Point{x0, y0}, Point{x1, y1}} +} + +// Pt is shorthand for Point{X: x, Y: y}. +func Pt(x, y float32) Point { + return Point{X: x, Y: y} +} + +// Add return the point p+p2. +func (p Point) Add(p2 Point) Point { + return Point{X: p.X + p2.X, Y: p.Y + p2.Y} +} + +// Sub returns the vector p-p2. +func (p Point) Sub(p2 Point) Point { + return Point{X: p.X - p2.X, Y: p.Y - p2.Y} +} + +// Mul returns p scaled by s. +func (p Point) Mul(s float32) Point { + return Point{X: p.X * s, Y: p.Y * s} +} + +// Div returns the vector p/s. +func (p Point) Div(s float32) Point { + return Point{X: p.X / s, Y: p.Y / s} +} + +// In reports whether p is in r. +func (p Point) In(r Rectangle) bool { + return r.Min.X <= p.X && p.X < r.Max.X && + r.Min.Y <= p.Y && p.Y < r.Max.Y +} + +// Round returns the integer point closest to p. +func (p Point) Round() image.Point { + return image.Point{ + X: int(math.Round(float64(p.X))), + Y: int(math.Round(float64(p.Y))), + } +} + +// Size returns r's width and height. +func (r Rectangle) Size() Point { + return Point{X: r.Dx(), Y: r.Dy()} +} + +// Dx returns r's width. +func (r Rectangle) Dx() float32 { + return r.Max.X - r.Min.X +} + +// Dy returns r's Height. +func (r Rectangle) Dy() float32 { + return r.Max.Y - r.Min.Y +} + +// Intersect returns the intersection of r and s. +func (r Rectangle) Intersect(s Rectangle) Rectangle { + if r.Min.X < s.Min.X { + r.Min.X = s.Min.X + } + if r.Min.Y < s.Min.Y { + r.Min.Y = s.Min.Y + } + if r.Max.X > s.Max.X { + r.Max.X = s.Max.X + } + if r.Max.Y > s.Max.Y { + r.Max.Y = s.Max.Y + } + if r.Empty() { + return Rectangle{} + } + return r +} + +// Union returns the union of r and s. +func (r Rectangle) Union(s Rectangle) Rectangle { + if r.Empty() { + return s + } + if s.Empty() { + return r + } + if r.Min.X > s.Min.X { + r.Min.X = s.Min.X + } + if r.Min.Y > s.Min.Y { + r.Min.Y = s.Min.Y + } + if r.Max.X < s.Max.X { + r.Max.X = s.Max.X + } + if r.Max.Y < s.Max.Y { + r.Max.Y = s.Max.Y + } + return r +} + +// Canon returns the canonical version of r, where Min is to +// the upper left of Max. +func (r Rectangle) Canon() Rectangle { + if r.Max.X < r.Min.X { + r.Min.X, r.Max.X = r.Max.X, r.Min.X + } + if r.Max.Y < r.Min.Y { + r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y + } + return r +} + +// Empty reports whether r represents the empty area. +func (r Rectangle) Empty() bool { + return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y +} + +// Add offsets r with the vector p. +func (r Rectangle) Add(p Point) Rectangle { + return Rectangle{ + Point{r.Min.X + p.X, r.Min.Y + p.Y}, + Point{r.Max.X + p.X, r.Max.Y + p.Y}, + } +} + +// Sub offsets r with the vector -p. +func (r Rectangle) Sub(p Point) Rectangle { + return Rectangle{ + Point{r.Min.X - p.X, r.Min.Y - p.Y}, + Point{r.Max.X - p.X, r.Max.Y - p.Y}, + } +} + +// Round returns the smallest integer rectangle that +// contains r. +func (r Rectangle) Round() image.Rectangle { + return image.Rectangle{ + Min: image.Point{ + X: int(floor(r.Min.X)), + Y: int(floor(r.Min.Y)), + }, + Max: image.Point{ + X: int(ceil(r.Max.X)), + Y: int(ceil(r.Max.Y)), + }, + } +} + +func ceil(v float32) int { + return int(math.Ceil(float64(v))) +} + +func floor(v float32) int { + return int(math.Floor(float64(v))) +} diff --git a/layout/layout.go b/layout/layout.go index 7f873406..f36dbd5c 100644 --- a/layout/layout.go +++ b/layout/layout.go @@ -85,13 +85,6 @@ func FPt(p image.Point) f32.Point { } } -// FRect converts a rectangle to a f32.Rectangle. -func FRect(r image.Rectangle) f32.Rectangle { - return f32.Rectangle{ - Min: FPt(r.Min), Max: FPt(r.Max), - } -} - // Constrain a size so each dimension is in the range [min;max]. func (c Constraints) Constrain(size image.Point) image.Point { if min := c.Min.X; size.X < min {