Transparency support!!
This commit is contained in:
parent
2f0259d913
commit
94db4e8ead
5
box.go
5
box.go
@ -3,6 +3,7 @@ package x
|
|||||||
import "image"
|
import "image"
|
||||||
import "image/color"
|
import "image/color"
|
||||||
import "git.tebibyte.media/tomo/tomo"
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
|
import "git.tebibyte.media/tomo/x/canvas"
|
||||||
import "git.tebibyte.media/tomo/tomo/data"
|
import "git.tebibyte.media/tomo/tomo/data"
|
||||||
import "git.tebibyte.media/tomo/tomo/input"
|
import "git.tebibyte.media/tomo/tomo/input"
|
||||||
import "git.tebibyte.media/tomo/tomo/event"
|
import "git.tebibyte.media/tomo/tomo/event"
|
||||||
@ -23,7 +24,7 @@ type box struct {
|
|||||||
padding tomo.Inset
|
padding tomo.Inset
|
||||||
border []tomo.Border
|
border []tomo.Border
|
||||||
color color.Color
|
color color.Color
|
||||||
texture *texture
|
texture *xcanvas.Texture
|
||||||
|
|
||||||
fillTransparent bool
|
fillTransparent bool
|
||||||
|
|
||||||
@ -122,7 +123,7 @@ func (this *box) SetColor (c color.Color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) SetTexture (texture tomo.Texture) {
|
func (this *box) SetTexture (texture tomo.Texture) {
|
||||||
this.texture = assertTexture(texture)
|
this.texture = xcanvas.AssertTexture(texture)
|
||||||
this.determineFillTransparency()
|
this.determineFillTransparency()
|
||||||
this.invalidateDraw()
|
this.invalidateDraw()
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import "image"
|
|||||||
import "image/color"
|
import "image/color"
|
||||||
import "github.com/jezek/xgbutil"
|
import "github.com/jezek/xgbutil"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
import "github.com/jezek/xgbutil/xgraphics"
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
import "git.tebibyte.media/tomo/tomo/canvas"
|
import "git.tebibyte.media/tomo/tomo/canvas"
|
||||||
|
|
||||||
@ -73,23 +74,34 @@ type pen struct {
|
|||||||
align canvas.StrokeAlign
|
align canvas.StrokeAlign
|
||||||
stroke xgraphics.BGRA
|
stroke xgraphics.BGRA
|
||||||
fill xgraphics.BGRA
|
fill xgraphics.BGRA
|
||||||
|
texture *Texture
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *pen) Rectangle (bounds image.Rectangle) {
|
func (this *pen) Rectangle (bounds image.Rectangle) {
|
||||||
if this.weight == 0 {
|
if this.weight == 0 {
|
||||||
this.gfx.fillRectangle(bounds)
|
if this.fill.A > 0 {
|
||||||
|
this.fillRectangle(this.fill, bounds)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.gfx.strokeRectangle(bounds)
|
if this.stroke.A > 0 {
|
||||||
|
this.strokeRectangle(this.stroke, bounds)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *pen) Path (points ...image.Point) {
|
func (this *pen) Path (points ...image.Point) {
|
||||||
if this.weight == 0 {
|
if this.weight == 0 {
|
||||||
this.fillPolygon(points...)
|
if this.fill.A > 0 {
|
||||||
|
this.fillPolygon(this.fill, points...)
|
||||||
|
}
|
||||||
} else if this.closed {
|
} else if this.closed {
|
||||||
this.strokePolygon(points...)
|
if this.stroke.A > 0 {
|
||||||
|
this.strokePolygon(this.stroke, points...)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.polyLine(points...)
|
if this.stroke.A > 0 {
|
||||||
|
this.polyLine(this.stroke, points...)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +113,7 @@ func (this *pen) StrokeAlign (align canvas.StrokeAlign) { this.align = align
|
|||||||
|
|
||||||
func (this *pen) Stroke (stroke color.Color) { this.stroke = convertColor(stroke) }
|
func (this *pen) Stroke (stroke color.Color) { this.stroke = convertColor(stroke) }
|
||||||
func (this *pen) Fill (fill color.Color) { this.fill = convertColor(fill) }
|
func (this *pen) Fill (fill color.Color) { this.fill = convertColor(fill) }
|
||||||
|
func (this *pen) Texture (texture tomo.Texture) { this.texture = AssertTexture(texture) }
|
||||||
|
|
||||||
func convertColor (c color.Color) xgraphics.BGRA {
|
func convertColor (c color.Color) xgraphics.BGRA {
|
||||||
r, g, b, a := c.RGBA()
|
r, g, b, a := c.RGBA()
|
||||||
|
226
canvas/draw.go
226
canvas/draw.go
@ -1,5 +1,229 @@
|
|||||||
package xcanvas
|
package xcanvas
|
||||||
|
|
||||||
func (this *pen) fillRectangle (bounds image.Rectangle) {
|
import "sort"
|
||||||
|
import "image"
|
||||||
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
|
|
||||||
|
func (this *pen) fillRectangle (c xgraphics.BGRA, bounds image.Rectangle) {
|
||||||
|
if c.A == 255 {
|
||||||
|
this.fillRectangleOpaque(c, bounds)
|
||||||
|
} else {
|
||||||
|
this.fillRectangleTransparent(c, bounds)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *pen) fillRectangleOpaque (c xgraphics.BGRA, bounds image.Rectangle) {
|
||||||
|
bounds = 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)
|
||||||
|
this.image.Pix[index + 0] = c.B
|
||||||
|
this.image.Pix[index + 1] = c.G
|
||||||
|
this.image.Pix[index + 2] = c.R
|
||||||
|
this.image.Pix[index + 3] = c.A
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *pen) fillRectangleTransparent (c xgraphics.BGRA, bounds image.Rectangle) {
|
||||||
|
bounds = 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)
|
||||||
|
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
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *pen) strokeRectangle (c xgraphics.BGRA, bounds image.Rectangle) {
|
||||||
|
if this.weight > bounds.Dx() / 2 || this.weight > bounds.Dy() / 2 {
|
||||||
|
this.fillRectangle(c, bounds)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
top := image.Rect (
|
||||||
|
bounds.Min.X,
|
||||||
|
bounds.Min.Y,
|
||||||
|
bounds.Max.X,
|
||||||
|
bounds.Min.Y + this.weight)
|
||||||
|
bottom := image.Rect (
|
||||||
|
bounds.Min.X,
|
||||||
|
bounds.Max.Y - this.weight,
|
||||||
|
bounds.Max.X,
|
||||||
|
bounds.Max.Y)
|
||||||
|
left := image.Rect (
|
||||||
|
bounds.Min.X,
|
||||||
|
bounds.Min.Y + this.weight,
|
||||||
|
bounds.Min.X + this.weight,
|
||||||
|
bounds.Max.Y - this.weight)
|
||||||
|
right := image.Rect (
|
||||||
|
bounds.Max.X - this.weight,
|
||||||
|
bounds.Min.Y + this.weight,
|
||||||
|
bounds.Max.X,
|
||||||
|
bounds.Max.Y - this.weight)
|
||||||
|
|
||||||
|
this.fillRectangle(c, top,)
|
||||||
|
this.fillRectangle(c, bottom,)
|
||||||
|
this.fillRectangle(c, left,)
|
||||||
|
this.fillRectangle(c, right,)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 }
|
||||||
|
|
||||||
|
// figure out the bounds of the polygon so we don't test empty space
|
||||||
|
var area image.Rectangle
|
||||||
|
area.Min = points[0]
|
||||||
|
area.Max = points[0]
|
||||||
|
for _, point := range points[1:] {
|
||||||
|
if point.X < area.Min.X { area.Min.X = point.X }
|
||||||
|
if point.Y < area.Min.Y { area.Min.Y = point.Y }
|
||||||
|
if point.X > area.Max.X { area.Max.X = point.X }
|
||||||
|
if point.Y > area.Max.Y { area.Max.Y = point.Y }
|
||||||
|
}
|
||||||
|
area = this.image.Bounds().Intersect(area)
|
||||||
|
if area.Empty() { return }
|
||||||
|
|
||||||
|
context := fillingContext {
|
||||||
|
image: this.image,
|
||||||
|
color: this.fill,
|
||||||
|
min: area.Min.X,
|
||||||
|
max: area.Max.X,
|
||||||
|
boundaries: make([]int, len(points)),
|
||||||
|
points: points,
|
||||||
|
}
|
||||||
|
|
||||||
|
for context.y = area.Min.Y; context.y < area.Max.Y; context.y ++ {
|
||||||
|
// build boundary list
|
||||||
|
boundaryCount := 0
|
||||||
|
prevPoint := points[len(points) - 1]
|
||||||
|
for _, point := range points {
|
||||||
|
fy := float64(context.y)
|
||||||
|
fPointX := float64(point.X)
|
||||||
|
fPointY := float64(point.Y)
|
||||||
|
fPrevX := float64(prevPoint.X)
|
||||||
|
fPrevY := float64(prevPoint.Y)
|
||||||
|
addboundary :=
|
||||||
|
(fPointY < fy && fPrevY >= fy) ||
|
||||||
|
(fPrevY < fy && fPointY >= fy)
|
||||||
|
if addboundary {
|
||||||
|
context.boundaries[boundaryCount] = int (
|
||||||
|
fPointX +
|
||||||
|
(fy - fPointY) /
|
||||||
|
(fPrevY - fPointY) *
|
||||||
|
(fPrevX - fPointX))
|
||||||
|
boundaryCount ++
|
||||||
|
}
|
||||||
|
prevPoint = point
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort boundary list
|
||||||
|
cutBoundaries := context.boundaries[:boundaryCount]
|
||||||
|
sort.Ints(cutBoundaries)
|
||||||
|
|
||||||
|
// fill pixels between boundary pairs
|
||||||
|
if c.A == 255 {
|
||||||
|
context.fillPolygonHotOpaque()
|
||||||
|
} else {
|
||||||
|
context.fillPolygonHotTransparent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type fillingContext struct {
|
||||||
|
image *xgraphics.Image
|
||||||
|
color xgraphics.BGRA
|
||||||
|
min, max int
|
||||||
|
y int
|
||||||
|
boundaries []int
|
||||||
|
points []image.Point
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *fillingContext) fillPolygonHotOpaque () {
|
||||||
|
for index := 0; index < len(context.boundaries); index += 2 {
|
||||||
|
left := context.boundaries[index]
|
||||||
|
right := context.boundaries[index + 1]
|
||||||
|
|
||||||
|
// stop if we have exited the polygon
|
||||||
|
if left >= context.max { break }
|
||||||
|
// begin filling if we are within the polygon
|
||||||
|
if right > context.min {
|
||||||
|
// 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)
|
||||||
|
context.image.Pix[index + 0] = context.color.B
|
||||||
|
context.image.Pix[index + 1] = context.color.G
|
||||||
|
context.image.Pix[index + 2] = context.color.R
|
||||||
|
context.image.Pix[index + 3] = context.color.A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *fillingContext) fillPolygonHotTransparent () {
|
||||||
|
for index := 0; index < len(context.boundaries); index += 2 {
|
||||||
|
left := context.boundaries[index]
|
||||||
|
right := context.boundaries[index + 1]
|
||||||
|
|
||||||
|
// stop if we have exited the polygon
|
||||||
|
if left >= context.max { break }
|
||||||
|
// begin filling if we are within the polygon
|
||||||
|
if right > context.min {
|
||||||
|
// 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)
|
||||||
|
pixel := xgraphics.BlendBGRA(xgraphics.BGRA {
|
||||||
|
B: context.image.Pix[index + 0],
|
||||||
|
G: context.image.Pix[index + 1],
|
||||||
|
R: context.image.Pix[index + 2],
|
||||||
|
A: context.image.Pix[index + 3],
|
||||||
|
}, context.color)
|
||||||
|
context.image.Pix[index + 0] = pixel.B
|
||||||
|
context.image.Pix[index + 1] = pixel.G
|
||||||
|
context.image.Pix[index + 2] = pixel.R
|
||||||
|
context.image.Pix[index + 3] = pixel.A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *pen) strokePolygon (c xgraphics.BGRA, points ...image.Point) {
|
||||||
|
prevPoint := points[len(points) - 1]
|
||||||
|
for _, point := range points {
|
||||||
|
this.line(c, prevPoint, point)
|
||||||
|
prevPoint = point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (this *pen) polyLine (c xgraphics.BGRA, points ...image.Point) {
|
||||||
|
if len(points) < 2 { return }
|
||||||
|
prevPoint := points[0]
|
||||||
|
for _, point := range points[1:] {
|
||||||
|
this.line(c, prevPoint, point)
|
||||||
|
prevPoint = point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
94
canvas/line.go
Normal file
94
canvas/line.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package xcanvas
|
||||||
|
|
||||||
|
import "image"
|
||||||
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
|
|
||||||
|
func (this *pen) line (
|
||||||
|
c xgraphics.BGRA,
|
||||||
|
min image.Point,
|
||||||
|
max image.Point,
|
||||||
|
) {
|
||||||
|
context := linePlottingContext {
|
||||||
|
plottingContext: plottingContext {
|
||||||
|
image: this.image,
|
||||||
|
color: c,
|
||||||
|
weight: this.weight,
|
||||||
|
},
|
||||||
|
min: min,
|
||||||
|
max: max,
|
||||||
|
}
|
||||||
|
|
||||||
|
if abs(max.Y - min.Y) < abs(max.X - min.X) {
|
||||||
|
if max.X < min.X { context.swap() }
|
||||||
|
context.lineLow()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if max.Y < min.Y { context.swap() }
|
||||||
|
context.lineHigh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type linePlottingContext struct {
|
||||||
|
plottingContext
|
||||||
|
min image.Point
|
||||||
|
max image.Point
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context *linePlottingContext) swap () {
|
||||||
|
temp := context.max
|
||||||
|
context.max = context.min
|
||||||
|
context.min = temp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context linePlottingContext) lineLow () {
|
||||||
|
deltaX := context.max.X - context.min.X
|
||||||
|
deltaY := context.max.Y - context.min.Y
|
||||||
|
yi := 1
|
||||||
|
|
||||||
|
if deltaY < 0 {
|
||||||
|
yi = -1
|
||||||
|
deltaY *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
D := (2 * deltaY) - deltaX
|
||||||
|
point := context.min
|
||||||
|
|
||||||
|
for ; point.X < context.max.X; point.X ++ {
|
||||||
|
context.plot(point)
|
||||||
|
if D > 0 {
|
||||||
|
D += 2 * (deltaY - deltaX)
|
||||||
|
point.Y += yi
|
||||||
|
} else {
|
||||||
|
D += 2 * deltaY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context linePlottingContext) lineHigh () {
|
||||||
|
deltaX := context.max.X - context.min.X
|
||||||
|
deltaY := context.max.Y - context.min.Y
|
||||||
|
xi := 1
|
||||||
|
|
||||||
|
if deltaX < 0 {
|
||||||
|
xi = -1
|
||||||
|
deltaX *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
D := (2 * deltaX) - deltaY
|
||||||
|
point := context.min
|
||||||
|
|
||||||
|
for ; point.Y < context.max.Y; point.Y ++ {
|
||||||
|
context.plot(point)
|
||||||
|
if D > 0 {
|
||||||
|
point.X += xi
|
||||||
|
D += 2 * (deltaX - deltaY)
|
||||||
|
} else {
|
||||||
|
D += 2 * deltaX
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func abs (n int) int {
|
||||||
|
if n < 0 { n *= -1}
|
||||||
|
return n
|
||||||
|
}
|
47
canvas/plot.go
Normal file
47
canvas/plot.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package xcanvas
|
||||||
|
|
||||||
|
import "image"
|
||||||
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
|
|
||||||
|
type plottingContext struct {
|
||||||
|
image *xgraphics.Image
|
||||||
|
color xgraphics.BGRA
|
||||||
|
weight int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context plottingContext) square (center image.Point) (square image.Rectangle) {
|
||||||
|
return image.Rect(0, 0, context.weight, context.weight).
|
||||||
|
Sub(image.Pt(context.weight / 2, context.weight / 2)).
|
||||||
|
Add(center).
|
||||||
|
Intersect(context.image.Bounds())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (context plottingContext) plot (center image.Point) {
|
||||||
|
square := context.square(center)
|
||||||
|
|
||||||
|
if context.color.A == 255 {
|
||||||
|
for y := square.Min.Y; y < square.Max.Y; y ++ {
|
||||||
|
for x := square.Min.X; x < square.Max.X; x ++ {
|
||||||
|
index := context.image.PixOffset(x, y)
|
||||||
|
context.image.Pix[index + 0] = context.color.B
|
||||||
|
context.image.Pix[index + 1] = context.color.G
|
||||||
|
context.image.Pix[index + 2] = context.color.R
|
||||||
|
context.image.Pix[index + 3] = context.color.A
|
||||||
|
}}
|
||||||
|
} else {
|
||||||
|
for y := square.Min.Y; y < square.Max.Y; y ++ {
|
||||||
|
for x := square.Min.X; x < square.Max.X; x ++ {
|
||||||
|
index := context.image.PixOffset(x, y)
|
||||||
|
pixel := xgraphics.BlendBGRA(xgraphics.BGRA {
|
||||||
|
B: context.image.Pix[index + 0],
|
||||||
|
G: context.image.Pix[index + 1],
|
||||||
|
R: context.image.Pix[index + 2],
|
||||||
|
A: context.image.Pix[index + 3],
|
||||||
|
}, context.color)
|
||||||
|
context.image.Pix[index + 0] = pixel.B
|
||||||
|
context.image.Pix[index + 1] = pixel.G
|
||||||
|
context.image.Pix[index + 2] = pixel.R
|
||||||
|
context.image.Pix[index + 3] = pixel.A
|
||||||
|
}}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package xcanvas
|
package xcanvas
|
||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
|
|
||||||
// Texture is a read-only image texture that can be quickly written to a canvas.
|
// Texture is a read-only image texture that can be quickly written to a canvas.
|
||||||
// It must be closed manually after use.
|
// It must be closed manually after use.
|
||||||
@ -52,9 +53,17 @@ func (this *Texture) Close () error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clip returns a subset of this texture that points to the same data.
|
// Clip returns a subset of this texture that points to the same data.
|
||||||
func (this *Texture) Clip (bounds image.Rectangle) *Texture {
|
func (this *Texture) Clip (bounds image.Rectangle) tomo.Texture {
|
||||||
clipped := *this
|
clipped := *this
|
||||||
clipped.rect = bounds
|
clipped.rect = bounds
|
||||||
return &clipped
|
return &clipped
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertTexture checks if a given tomo.Texture is a texture from this package.
|
||||||
|
func AssertTexture (unknown tomo.Texture) *Texture {
|
||||||
|
if tx, ok := unknown.(*Texture); ok {
|
||||||
|
return tx
|
||||||
|
} else {
|
||||||
|
panic("foregin texture implementation, i did not make this!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
22
texture.go
22
texture.go
@ -4,26 +4,6 @@ import "image"
|
|||||||
import "git.tebibyte.media/tomo/tomo"
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
import "git.tebibyte.media/tomo/x/canvas"
|
import "git.tebibyte.media/tomo/x/canvas"
|
||||||
|
|
||||||
type texture struct {
|
|
||||||
*xcanvas.Texture
|
|
||||||
}
|
|
||||||
|
|
||||||
func (backend Backend) NewTexture (source image.Image) tomo.Texture {
|
func (backend Backend) NewTexture (source image.Image) tomo.Texture {
|
||||||
return texture {
|
return xcanvas.NewTextureFrom(source)
|
||||||
Texture: xcanvas.NewTextureFrom(source),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (this texture) Clip (bounds image.Rectangle) tomo.Texture {
|
|
||||||
return texture {
|
|
||||||
Texture: this.Texture.Clip(bounds),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertTexture (unknown tomo.Texture) *texture {
|
|
||||||
if tx, ok := unknown.(*texture); ok {
|
|
||||||
return tx
|
|
||||||
} else {
|
|
||||||
panic("foregin texture implementation, i did not make this!")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user