feat: primitive styling

This commit is contained in:
IliaDenisov
2026-03-07 17:01:22 +02:00
parent 477e656008
commit e4b956232f
18 changed files with 1264 additions and 175 deletions
+41 -29
View File
@@ -67,18 +67,13 @@ type PrimitiveDrawer interface {
// Fill renders the current path using the current fill state.
Fill()
// CopyShift shifts the current backing image by (dx, dy) in canvas pixels.
// dx > 0 shifts the image to the right, dy > 0 shifts the image down.
// Newly exposed areas are cleared to transparent.
// CopyShift shifts backing pixels by (dx,dy). Newly exposed areas become transparent/undefined;
// caller is expected to ClearRectTo() the dirty areas before drawing.
CopyShift(dx, dy int)
// ClearAll clears the entire backing canvas to transparent.
// Must NOT affect the current clip state.
ClearAll()
// ClearRect clears a pixel rectangle to transparent.
// Must NOT affect the current clip state.
ClearRect(x, y, w, h int)
// Clear operations must NOT change clip state.
ClearAllTo(bg color.Color)
ClearRectTo(x, y, w, h int, bg color.Color)
}
// ggClipRect stores one clip rectangle in canvas pixel coordinates.
@@ -283,44 +278,61 @@ func (d *GGDrawer) CopyShift(dx, dy int) {
copy(img.Pix, d.scratch.Pix)
}
// ClearAll clears the whole RGBA backing image to transparent.
// It does not touch gg clip state.
func (d *GGDrawer) ClearAll() {
func (d *GGDrawer) ClearAllTo(bg color.Color) {
img, ok := d.DC.Image().(*image.RGBA)
if !ok || img == nil {
panic("GGDrawer.ClearAll: backing image is not *image.RGBA")
panic("GGDrawer.ClearAllTo: backing image is not *image.RGBA")
}
for i := range img.Pix {
img.Pix[i] = 0
r, g, b, a := bg.RGBA()
// Convert from 16-bit range to 8-bit.
R := byte(r >> 8)
G := byte(g >> 8)
B := byte(b >> 8)
A := byte(a >> 8)
p := img.Pix
for i := 0; i+3 < len(p); i += 4 {
p[i+0] = R
p[i+1] = G
p[i+2] = B
p[i+3] = A
}
}
// ClearRect clears a region to transparent. It does not touch gg clip state.
// Rectangle is clamped to the image bounds.
func (d *GGDrawer) ClearRect(x, y, w, h int) {
func (d *GGDrawer) ClearRectTo(x, y, w, h int, bg color.Color) {
if w <= 0 || h <= 0 {
return
}
img, ok := d.DC.Image().(*image.RGBA)
if !ok || img == nil {
panic("GGDrawer.ClearRect: backing image is not *image.RGBA")
panic("GGDrawer.ClearRectTo: backing image is not *image.RGBA")
}
b := img.Bounds()
x0 := max(x, b.Min.X)
y0 := max(y, b.Min.Y)
x1 := min(x+w, b.Max.X)
y1 := min(y+h, b.Max.Y)
bounds := img.Bounds()
x0 := max(x, bounds.Min.X)
y0 := max(y, bounds.Min.Y)
x1 := min(x+w, bounds.Max.X)
y1 := min(y+h, bounds.Max.Y)
if x0 >= x1 || y0 >= y1 {
return
}
// Zero rows.
r, g, b, a := bg.RGBA()
R := byte(r >> 8)
G := byte(g >> 8)
B := byte(b >> 8)
A := byte(a >> 8)
rowBytes := (x1 - x0) * 4
for yy := y0; yy < y1; yy++ {
off := yy*img.Stride + x0*4
n := (x1 - x0) * 4
for i := 0; i < n; i++ {
img.Pix[off+i] = 0
for i := 0; i < rowBytes; i += 4 {
img.Pix[off+i+0] = R
img.Pix[off+i+1] = G
img.Pix[off+i+2] = B
img.Pix[off+i+3] = A
}
}
}