mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
gpu: separate the construction and placing of material quads
We're about to cache the transformed materials. It's easier to do when quads can be constructed before determining their atlas position. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
+23
-26
@@ -507,9 +507,9 @@ func pow2Ceil(v int) int {
|
|||||||
return 1 << exp
|
return 1 << exp
|
||||||
}
|
}
|
||||||
|
|
||||||
// addMaterialQuad appends a render of an image to materials and returns the pixel offset
|
// materialQuad constructs a quad that represents the transformed image. It returns the quad
|
||||||
// that maps the material texture to the correct position in the rendered image.
|
// and its bounds.
|
||||||
func (g *compute) addMaterialQuad(M f32.Affine2D, img imageOpData) (image.Point, error) {
|
func (g *compute) materialQuad(M f32.Affine2D, img imageOpData) ([4]materialVertex, image.Rectangle) {
|
||||||
imgSize := layout.FPt(img.src.Bounds().Size())
|
imgSize := layout.FPt(img.src.Bounds().Size())
|
||||||
sx, hx, ox, hy, sy, oy := M.Elems()
|
sx, hx, ox, hy, sy, oy := M.Elems()
|
||||||
transOff := f32.Pt(ox, oy)
|
transOff := f32.Pt(ox, oy)
|
||||||
@@ -534,21 +534,6 @@ func (g *compute) addMaterialQuad(M f32.Affine2D, img imageOpData) (image.Point,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bounds := boundRectF(boundsf)
|
bounds := boundRectF(boundsf)
|
||||||
size := bounds.Size()
|
|
||||||
// A material is clipped to avoid drawing outside its bounds inside the atlas. However,
|
|
||||||
// imprecision in the clipping may cause a single pixel overflow. Be safe.
|
|
||||||
size = size.Add(image.Pt(1, 1))
|
|
||||||
place, fits := g.materials.packer.tryAdd(size)
|
|
||||||
if !fits {
|
|
||||||
return image.Point{}, errors.New("compute: no space left in image atlas")
|
|
||||||
}
|
|
||||||
// Position quad to match place.
|
|
||||||
offset := place.Pos.Sub(bounds.Min)
|
|
||||||
offsetf := layout.FPt(offset)
|
|
||||||
q0 = q0.Add(offsetf)
|
|
||||||
q1 = q1.Add(offsetf)
|
|
||||||
q2 = q2.Add(offsetf)
|
|
||||||
q3 = q3.Add(offsetf)
|
|
||||||
uvPos, ok := g.images.positions[img.handle]
|
uvPos, ok := g.images.positions[img.handle]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("compute: internal error: image not placed")
|
panic("compute: internal error: image not placed")
|
||||||
@@ -565,9 +550,7 @@ func (g *compute) addMaterialQuad(M f32.Affine2D, img imageOpData) (image.Point,
|
|||||||
{posX: q2.X, posY: q2.Y, u: uvBounds.Max.X, v: uvBounds.Max.Y},
|
{posX: q2.X, posY: q2.Y, u: uvBounds.Max.X, v: uvBounds.Max.Y},
|
||||||
{posX: q3.X, posY: q3.Y, u: uvBounds.Max.X, v: uvBounds.Min.Y},
|
{posX: q3.X, posY: q3.Y, u: uvBounds.Max.X, v: uvBounds.Min.Y},
|
||||||
}
|
}
|
||||||
// Draw quad as two triangles.
|
return quad, bounds
|
||||||
g.materials.quads = append(g.materials.quads, quad[0], quad[1], quad[3], quad[3], quad[1], quad[2])
|
|
||||||
return offset, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func max(p1, p2 f32.Point) f32.Point {
|
func max(p1, p2 f32.Point) f32.Point {
|
||||||
@@ -603,12 +586,26 @@ func (g *compute) encodeOps(trans f32.Affine2D, viewport image.Point, ops []imag
|
|||||||
switch m.material {
|
switch m.material {
|
||||||
case materialTexture:
|
case materialTexture:
|
||||||
t := trans.Mul(m.trans)
|
t := trans.Mul(m.trans)
|
||||||
off, err := g.addMaterialQuad(t, m.data)
|
quad, bounds := g.materialQuad(t, m.data)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
g.enc.fillImage(0, off)
|
// A material is clipped to avoid drawing outside its bounds inside the atlas. However,
|
||||||
|
// imprecision in the clipping may cause a single pixel overflow. Be safe.
|
||||||
|
size := bounds.Size().Add(image.Pt(1, 1))
|
||||||
|
place, fits := g.materials.packer.tryAdd(size)
|
||||||
|
if !fits {
|
||||||
|
return errors.New("compute: no space left in image atlas")
|
||||||
|
}
|
||||||
|
// Position quad to match place.
|
||||||
|
offset := place.Pos.Sub(bounds.Min)
|
||||||
|
offsetf := layout.FPt(offset)
|
||||||
|
for i := range quad {
|
||||||
|
quad[i].posX += offsetf.X
|
||||||
|
quad[i].posY += offsetf.Y
|
||||||
|
}
|
||||||
|
// Draw quad as two triangles.
|
||||||
|
g.materials.quads = append(g.materials.quads, quad[0], quad[1], quad[3], quad[3], quad[1], quad[2])
|
||||||
|
|
||||||
|
g.enc.fillImage(0, offset)
|
||||||
case materialColor:
|
case materialColor:
|
||||||
g.enc.fill(f32color.NRGBAToRGBA(op.material.color.SRGB()))
|
g.enc.fill(f32color.NRGBAToRGBA(op.material.color.SRGB()))
|
||||||
case materialLinearGradient:
|
case materialLinearGradient:
|
||||||
|
|||||||
Reference in New Issue
Block a user