Textured rectangles are working (if a bit slow)

This commit is contained in:
Sasha Koshka 2023-08-29 17:23:24 -04:00
parent e2a370259b
commit ab80658cd9
2 changed files with 50 additions and 27 deletions

View File

@ -13,34 +13,53 @@ func (this *pen) textureRectangle (bounds image.Rectangle) {
} }
func (this *pen) textureRectangleOpaque (bounds image.Rectangle) { func (this *pen) textureRectangleOpaque (bounds image.Rectangle) {
dstBounds := bounds.Intersect(this.image.Bounds()) dstBounds := bounds.Intersect(this.image.Bounds())
srcBounds := this.texture.rect var pos image.Point
offset := dstBounds.Min.Sub(bounds.Min)
dstStep := this.image.Stride - bounds.Dx() * 4 dst := this.image.Pix
srcStep := this.texture.stride - srcBounds.Dx() * 4 src := this.texture.pix
offset := this.texture.rect.Min.Sub(bounds.Min)
for pos.Y = dstBounds.Min.Y; pos.Y < dstBounds.Max.Y; pos.Y ++ {
for pos.X = dstBounds.Min.X; pos.X < dstBounds.Max.X; pos.X ++ {
srcPos := pos.Add(offset)
dstIndex := this.image.PixOffset(pos.X, pos.Y)
srcIndex := this.texture.PixOffset(srcPos.X, srcPos.Y)
dst[dstIndex + 0] = src[srcIndex + 0]
dst[dstIndex + 1] = src[srcIndex + 1]
dst[dstIndex + 2] = src[srcIndex + 2]
dst[dstIndex + 3] = src[srcIndex + 3]
}}
} }
func (this *pen) textureRectangleTransparent (bounds image.Rectangle) { func (this *pen) textureRectangleTransparent (bounds image.Rectangle) {
bounds = bounds.Intersect(this.image.Bounds()) dstBounds := bounds.Intersect(this.image.Bounds())
var pos image.Point var pos image.Point
for pos.Y = bounds.Min.Y; pos.Y < bounds.Max.Y; pos.Y ++ { dst := this.image.Pix
for pos.X = bounds.Min.X; pos.X < bounds.Max.X; pos.X ++ { src := this.texture.pix
index := this.image.PixOffset(pos.X, pos.Y) offset := this.texture.rect.Min.Sub(bounds.Min)
for pos.Y = dstBounds.Min.Y; pos.Y < dstBounds.Max.Y; pos.Y ++ {
for pos.X = dstBounds.Min.X; pos.X < dstBounds.Max.X; pos.X ++ {
srcPos := pos.Add(offset)
dstIndex := this.image.PixOffset(pos.X, pos.Y)
srcIndex := this.texture.PixOffset(srcPos.X, srcPos.Y)
pixel := xgraphics.BlendBGRA(xgraphics.BGRA { pixel := xgraphics.BlendBGRA(xgraphics.BGRA {
B: this.image.Pix[index + 0], B: dst[dstIndex + 0],
G: this.image.Pix[index + 1], G: dst[dstIndex + 1],
R: this.image.Pix[index + 2], R: dst[dstIndex + 2],
A: this.image.Pix[index + 3], A: dst[dstIndex + 3],
}, c) }, xgraphics.BGRA {
this.image.Pix[index + 0] = pixel.B B: src[srcIndex + 0],
this.image.Pix[index + 1] = pixel.G G: src[srcIndex + 1],
this.image.Pix[index + 2] = pixel.R R: src[srcIndex + 2],
this.image.Pix[index + 3] = pixel.A A: src[srcIndex + 3],
})
dst[dstIndex + 0] = pixel.B
dst[dstIndex + 1] = pixel.G
dst[dstIndex + 2] = pixel.R
dst[dstIndex + 3] = pixel.A
}} }}
} }
@ -91,7 +110,7 @@ func (this *pen) strokeRectangle (c xgraphics.BGRA, bounds image.Rectangle) {
this.fillRectangle(c, bounds) this.fillRectangle(c, bounds)
return return
} }
top := image.Rect ( top := image.Rect (
bounds.Min.X, bounds.Min.X,
bounds.Min.Y, bounds.Min.Y,
@ -122,7 +141,7 @@ func (this *pen) strokeRectangle (c xgraphics.BGRA, bounds image.Rectangle) {
// the polygon filling algorithm is adapted from: // the polygon filling algorithm is adapted from:
// https://www.alienryderflex.com/polygon_fill/ // https://www.alienryderflex.com/polygon_fill/
// (if you write C like that i will disassemble you) // (if you write C like that i will disassemble you)
func (this *pen) fillPolygon (c xgraphics.BGRA, points ...image.Point) { func (this *pen) fillPolygon (c xgraphics.BGRA, points ...image.Point) {
if len(points) < 3 { return } if len(points) < 3 { return }
@ -183,7 +202,7 @@ func (this *pen) fillPolygon (c xgraphics.BGRA, points ...image.Point) {
context.fillPolygonHotTransparent() context.fillPolygonHotTransparent()
} }
} }
} }
type fillingContext struct { type fillingContext struct {
@ -207,7 +226,7 @@ func (context *fillingContext) fillPolygonHotOpaque () {
// constrain boundaries to image size // constrain boundaries to image size
if left < context.min { left = context.min } if left < context.min { left = context.min }
if right > context.max { right = context.max } if right > context.max { right = context.max }
// fill pixels in between // fill pixels in between
for x := left; x < right; x ++ { for x := left; x < right; x ++ {
index := context.image.PixOffset(x, context.y) index := context.image.PixOffset(x, context.y)
@ -232,7 +251,7 @@ func (context *fillingContext) fillPolygonHotTransparent () {
// constrain boundaries to image size // constrain boundaries to image size
if left < context.min { left = context.min } if left < context.min { left = context.min }
if right > context.max { right = context.max } if right > context.max { right = context.max }
// fill pixels in between // fill pixels in between
for x := left; x < right; x ++ { for x := left; x < right; x ++ {
index := context.image.PixOffset(x, context.y) index := context.image.PixOffset(x, context.y)

View File

@ -36,7 +36,7 @@ func NewTextureFrom (source image.Image) *Texture {
texture.transparent = true texture.transparent = true
} }
}} }}
return texture return texture
} }
@ -59,7 +59,11 @@ func (this *Texture) Clip (bounds image.Rectangle) canvas.Texture {
return &clipped return &clipped
} }
func (this *Texture) pixOffset func (this *Texture) PixOffset (x, y int) int {
x = wrap(x, this.rect.Min.X, this.rect.Max.X)
y = wrap(y, this.rect.Min.Y, this.rect.Max.Y)
return x * 4 + y * this.stride
}
// AssertTexture checks if a given canvas.Texture is a texture from this package. // AssertTexture checks if a given canvas.Texture is a texture from this package.
func AssertTexture (unknown canvas.Texture) *Texture { func AssertTexture (unknown canvas.Texture) *Texture {