diff --git a/canvas/draw.go b/canvas/draw.go index 827d8e4..187528e 100644 --- a/canvas/draw.go +++ b/canvas/draw.go @@ -13,34 +13,53 @@ func (this *pen) textureRectangle (bounds image.Rectangle) { } func (this *pen) textureRectangleOpaque (bounds image.Rectangle) { - dstBounds := bounds.Intersect(this.image.Bounds()) - srcBounds := this.texture.rect - - offset := dstBounds.Min.Sub(bounds.Min) - + var pos image.Point - dstStep := this.image.Stride - bounds.Dx() * 4 - srcStep := this.texture.stride - srcBounds.Dx() * 4 + dst := this.image.Pix + 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) { - bounds = bounds.Intersect(this.image.Bounds()) + dstBounds := bounds.Intersect(this.image.Bounds()) var pos image.Point - for pos.Y = bounds.Min.Y; pos.Y < bounds.Max.Y; pos.Y ++ { - for pos.X = bounds.Min.X; pos.X < bounds.Max.X; pos.X ++ { - index := this.image.PixOffset(pos.X, pos.Y) + dst := this.image.Pix + 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) pixel := xgraphics.BlendBGRA(xgraphics.BGRA { - B: this.image.Pix[index + 0], - G: this.image.Pix[index + 1], - R: this.image.Pix[index + 2], - A: this.image.Pix[index + 3], - }, c) - this.image.Pix[index + 0] = pixel.B - this.image.Pix[index + 1] = pixel.G - this.image.Pix[index + 2] = pixel.R - this.image.Pix[index + 3] = pixel.A + B: dst[dstIndex + 0], + G: dst[dstIndex + 1], + R: dst[dstIndex + 2], + A: dst[dstIndex + 3], + }, xgraphics.BGRA { + B: src[srcIndex + 0], + G: src[srcIndex + 1], + R: src[srcIndex + 2], + 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) return } - + top := image.Rect ( bounds.Min.X, bounds.Min.Y, @@ -122,7 +141,7 @@ func (this *pen) strokeRectangle (c xgraphics.BGRA, bounds image.Rectangle) { // the polygon filling algorithm is adapted from: // https://www.alienryderflex.com/polygon_fill/ // (if you write C like that i will disassemble you) - + func (this *pen) fillPolygon (c xgraphics.BGRA, points ...image.Point) { if len(points) < 3 { return } @@ -183,7 +202,7 @@ func (this *pen) fillPolygon (c xgraphics.BGRA, points ...image.Point) { context.fillPolygonHotTransparent() } } - + } type fillingContext struct { @@ -207,7 +226,7 @@ func (context *fillingContext) fillPolygonHotOpaque () { // constrain boundaries to image size if left < context.min { left = context.min } if right > context.max { right = context.max } - + // fill pixels in between for x := left; x < right; x ++ { index := context.image.PixOffset(x, context.y) @@ -232,7 +251,7 @@ func (context *fillingContext) fillPolygonHotTransparent () { // constrain boundaries to image size if left < context.min { left = context.min } if right > context.max { right = context.max } - + // fill pixels in between for x := left; x < right; x ++ { index := context.image.PixOffset(x, context.y) diff --git a/canvas/texture.go b/canvas/texture.go index 5a6d023..fda2379 100644 --- a/canvas/texture.go +++ b/canvas/texture.go @@ -36,7 +36,7 @@ func NewTextureFrom (source image.Image) *Texture { texture.transparent = true } }} - + return texture } @@ -59,7 +59,11 @@ func (this *Texture) Clip (bounds image.Rectangle) canvas.Texture { 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. func AssertTexture (unknown canvas.Texture) *Texture {