WIP moving ggfx stuff into xcanvas
This commit is contained in:
parent
8401b5d0f9
commit
2f0259d913
4
box.go
4
box.go
@ -282,7 +282,7 @@ func (this *box) Draw (can canvas.Canvas) {
|
|||||||
if can == nil { return }
|
if can == nil { return }
|
||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
if this.texture == nil || this.texture.transparent {
|
if this.texture == nil || !this.texture.Opaque() {
|
||||||
pen.Rectangle(this.bounds)
|
pen.Rectangle(this.bounds)
|
||||||
}
|
}
|
||||||
if this.texture != nil {
|
if this.texture != nil {
|
||||||
@ -431,7 +431,7 @@ func (this *box) determineFillTransparency () {
|
|||||||
_, _, _, a := this.color.RGBA()
|
_, _, _, a := this.color.RGBA()
|
||||||
this.fillTransparent =
|
this.fillTransparent =
|
||||||
a != 0xFFFF &&
|
a != 0xFFFF &&
|
||||||
!(this.texture != nil && !this.texture.transparent)
|
!(this.texture != nil && this.texture.Opaque())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *box) propagate (callback func (anyBox) bool) bool {
|
func (this *box) propagate (callback func (anyBox) bool) bool {
|
||||||
|
@ -4,22 +4,23 @@ 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/ggfx"
|
|
||||||
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"
|
||||||
|
|
||||||
// Canvas satisfies the canvas.Canvas interface. It draws to an xgraphics.Image.
|
// Canvas satisfies the canvas.Canvas interface. It draws to an xgraphics.Image.
|
||||||
|
// It must be closed after use.
|
||||||
type Canvas struct {
|
type Canvas struct {
|
||||||
*xgraphics.Image
|
*xgraphics.Image
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new canvas from a bounding rectangle.
|
// NewCanvas creates a new canvas from a bounding rectangle.
|
||||||
func New (x *xgbutil.XUtil, bounds image.Rectangle) *Canvas {
|
func NewCanvas (x *xgbutil.XUtil, bounds image.Rectangle) *Canvas {
|
||||||
return NewFrom(xgraphics.New(x, bounds))
|
return NewCanvasFrom(xgraphics.New(x, bounds))
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFrom creates a new canvas from an existing xgraphics.Image.
|
// NewCanvasFrom creates a new canvas from an existing xgraphics.Image. Note
|
||||||
func NewFrom (image *xgraphics.Image) *Canvas {
|
// that calling Close() on the resulting canvas will destroy this image.
|
||||||
|
func NewCanvasFrom (image *xgraphics.Image) *Canvas {
|
||||||
if image == nil { return nil }
|
if image == nil { return nil }
|
||||||
return &Canvas { image }
|
return &Canvas { image }
|
||||||
}
|
}
|
||||||
@ -28,12 +29,6 @@ func NewFrom (image *xgraphics.Image) *Canvas {
|
|||||||
func (this *Canvas) Pen () canvas.Pen {
|
func (this *Canvas) Pen () canvas.Pen {
|
||||||
return &pen {
|
return &pen {
|
||||||
image: this.Image,
|
image: this.Image,
|
||||||
gfx: ggfx.Image[uint8] {
|
|
||||||
Pix: this.Image.Pix,
|
|
||||||
Stride: this.Image.Stride,
|
|
||||||
Rect: this.Image.Rect,
|
|
||||||
Width: 4,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +48,12 @@ func (this *Canvas) Push (window xproto.Window) {
|
|||||||
this.XExpPaint(window, this.Bounds().Min.X, this.Bounds().Min.Y)
|
this.XExpPaint(window, this.Bounds().Min.X, this.Bounds().Min.Y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Close frees this canvas from the X server.
|
||||||
|
func (this *Canvas) Close () {
|
||||||
|
this.assert()
|
||||||
|
this.Image.Destroy()
|
||||||
|
}
|
||||||
|
|
||||||
func (this *Canvas) assert () {
|
func (this *Canvas) assert () {
|
||||||
if this == nil { panic("nil canvas") }
|
if this == nil { panic("nil canvas") }
|
||||||
}
|
}
|
||||||
@ -64,35 +65,34 @@ func (this *Canvas) assert () {
|
|||||||
|
|
||||||
type pen struct {
|
type pen struct {
|
||||||
image *xgraphics.Image
|
image *xgraphics.Image
|
||||||
gfx ggfx.Image[uint8]
|
|
||||||
|
|
||||||
closed bool
|
closed bool
|
||||||
endCap canvas.Cap
|
endCap canvas.Cap
|
||||||
joint canvas.Joint
|
joint canvas.Joint
|
||||||
weight int
|
weight int
|
||||||
align canvas.StrokeAlign
|
align canvas.StrokeAlign
|
||||||
stroke [4]uint8
|
stroke xgraphics.BGRA
|
||||||
fill [4]uint8
|
fill xgraphics.BGRA
|
||||||
}
|
}
|
||||||
|
|
||||||
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(this.fill[:], bounds)
|
this.gfx.fillRectangle(bounds)
|
||||||
} else {
|
} else {
|
||||||
this.gfx.StrokeRectangle(this.stroke[:], this.weight, bounds)
|
this.gfx.strokeRectangle(bounds)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *pen) Path (points ...image.Point) {
|
func (this *pen) Path (points ...image.Point) {
|
||||||
if this.weight == 0 {
|
if this.weight == 0 {
|
||||||
this.gfx.FillPolygon(this.fill[:], points...)
|
this.fillPolygon(points...)
|
||||||
} else if this.closed {
|
} else if this.closed {
|
||||||
this.gfx.StrokePolygon(this.stroke[:], this.weight, points...)
|
this.strokePolygon(points...)
|
||||||
} else {
|
} else {
|
||||||
this.gfx.PolyLine(this.stroke[:], this.weight, points...)
|
this.polyLine(points...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *pen) Closed (closed bool) { this.closed = closed }
|
func (this *pen) Closed (closed bool) { this.closed = closed }
|
||||||
func (this *pen) Cap (endCap canvas.Cap) { this.endCap = endCap }
|
func (this *pen) Cap (endCap canvas.Cap) { this.endCap = endCap }
|
||||||
func (this *pen) Joint (joint canvas.Joint) { this.joint = joint }
|
func (this *pen) Joint (joint canvas.Joint) { this.joint = joint }
|
||||||
@ -100,14 +100,14 @@ func (this *pen) StrokeWeight (weight int) { this.weight = weight
|
|||||||
func (this *pen) StrokeAlign (align canvas.StrokeAlign) { this.align = align }
|
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 convertColor (c color.Color) [4]uint8 {
|
func convertColor (c color.Color) xgraphics.BGRA {
|
||||||
r, g, b, a := c.RGBA()
|
r, g, b, a := c.RGBA()
|
||||||
return [4]uint8 {
|
return xgraphics.BGRA {
|
||||||
uint8(b >> 8),
|
B: uint8(b >> 8),
|
||||||
uint8(g >> 8),
|
G: uint8(g >> 8),
|
||||||
uint8(r >> 8),
|
R: uint8(r >> 8),
|
||||||
uint8(a >> 8),
|
A: uint8(a >> 8),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
canvas/draw.go
Normal file
5
canvas/draw.go
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
package xcanvas
|
||||||
|
|
||||||
|
func (this *pen) fillRectangle (bounds image.Rectangle) {
|
||||||
|
|
||||||
|
}
|
60
canvas/texture.go
Normal file
60
canvas/texture.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package xcanvas
|
||||||
|
|
||||||
|
import "image"
|
||||||
|
|
||||||
|
// Texture is a read-only image texture that can be quickly written to a canvas.
|
||||||
|
// It must be closed manually after use.
|
||||||
|
type Texture struct {
|
||||||
|
pix []uint8
|
||||||
|
stride int
|
||||||
|
rect image.Rectangle
|
||||||
|
transparent bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTextureFrom creates a new texture from a source image.
|
||||||
|
func NewTextureFrom (source image.Image) *Texture {
|
||||||
|
bounds := source.Bounds()
|
||||||
|
texture := &Texture {
|
||||||
|
pix: make([]uint8, bounds.Dx() * bounds.Dy() * 4),
|
||||||
|
stride: bounds.Dx(),
|
||||||
|
rect: bounds.Sub(bounds.Min),
|
||||||
|
}
|
||||||
|
|
||||||
|
index := 0
|
||||||
|
var point image.Point
|
||||||
|
for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y ++ {
|
||||||
|
for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ {
|
||||||
|
r, g, b, a := source.At(point.X, point.Y).RGBA()
|
||||||
|
texture.pix[index + 0] = uint8(b >> 8)
|
||||||
|
texture.pix[index + 1] = uint8(g >> 8)
|
||||||
|
texture.pix[index + 2] = uint8(r >> 8)
|
||||||
|
texture.pix[index + 3] = uint8(a >> 8)
|
||||||
|
index += 4
|
||||||
|
|
||||||
|
if a != 0xFFFF {
|
||||||
|
texture.transparent = true
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
return texture
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opaque reports whether or not the texture is fully opaque.
|
||||||
|
func (this *Texture) Opaque () bool {
|
||||||
|
return !this.transparent
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close frees the texture from memory.
|
||||||
|
func (this *Texture) Close () error {
|
||||||
|
// i lied we dont actually need to close this, but we will once this
|
||||||
|
// texture resides on the x server or in video memory.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clip returns a subset of this texture that points to the same data.
|
||||||
|
func (this *Texture) Clip (bounds image.Rectangle) *Texture {
|
||||||
|
clipped := *this
|
||||||
|
clipped.rect = bounds
|
||||||
|
return &clipped
|
||||||
|
}
|
||||||
|
|
@ -143,7 +143,7 @@ func (this *containerBox) Draw (can canvas.Canvas) {
|
|||||||
if this.fillTransparent && this.parent != nil {
|
if this.fillTransparent && this.parent != nil {
|
||||||
this.parent.drawBackgroundPart(can.Clip(tile))
|
this.parent.drawBackgroundPart(can.Clip(tile))
|
||||||
}
|
}
|
||||||
if this.texture == nil || this.texture.transparent {
|
if this.texture == nil || !this.texture.Opaque() {
|
||||||
pen.Rectangle(tile)
|
pen.Rectangle(tile)
|
||||||
}
|
}
|
||||||
if this.texture != nil {
|
if this.texture != nil {
|
||||||
@ -162,7 +162,7 @@ func (this *containerBox) drawBackgroundPart (can canvas.Canvas) {
|
|||||||
pen := can.Pen()
|
pen := can.Pen()
|
||||||
pen.Fill(this.color)
|
pen.Fill(this.color)
|
||||||
|
|
||||||
if this.texture == nil || this.texture.transparent {
|
if this.texture == nil || !this.texture.Opaque() {
|
||||||
pen.Rectangle(can.Bounds())
|
pen.Rectangle(can.Bounds())
|
||||||
}
|
}
|
||||||
if this.texture != nil {
|
if this.texture != nil {
|
||||||
|
45
texture.go
45
texture.go
@ -2,49 +2,22 @@ package x
|
|||||||
|
|
||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/tomo/tomo"
|
import "git.tebibyte.media/tomo/tomo"
|
||||||
|
import "git.tebibyte.media/tomo/x/canvas"
|
||||||
|
|
||||||
type texture struct {
|
type texture struct {
|
||||||
pix []uint8
|
*xcanvas.Texture
|
||||||
stride int
|
|
||||||
rect image.Rectangle
|
|
||||||
transparent bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) NewTexture (source image.Image) tomo.Texture {
|
func (backend Backend) NewTexture (source image.Image) tomo.Texture {
|
||||||
bounds := source.Bounds()
|
return texture {
|
||||||
texture := &texture {
|
Texture: xcanvas.NewTextureFrom(source),
|
||||||
pix: make([]uint8, bounds.Dx() * bounds.Dy() * 4),
|
|
||||||
stride: bounds.Dx(),
|
|
||||||
rect: bounds.Sub(bounds.Min),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
index := 0
|
|
||||||
var point image.Point
|
|
||||||
for point.Y = bounds.Min.Y; point.Y < bounds.Max.Y; point.Y ++ {
|
|
||||||
for point.X = bounds.Min.X; point.X < bounds.Max.X; point.X ++ {
|
|
||||||
r, g, b, a := source.At(point.X, point.Y).RGBA()
|
|
||||||
texture.pix[index + 0] = uint8(b >> 8)
|
|
||||||
texture.pix[index + 1] = uint8(g >> 8)
|
|
||||||
texture.pix[index + 2] = uint8(r >> 8)
|
|
||||||
texture.pix[index + 3] = uint8(a >> 8)
|
|
||||||
index += 4
|
|
||||||
|
|
||||||
if a != 0xFFFF {
|
|
||||||
texture.transparent = true
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
return texture
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (this *texture) Clip (bounds image.Rectangle) tomo.Texture {
|
func (this texture) Clip (bounds image.Rectangle) tomo.Texture {
|
||||||
clipped := *this
|
return texture {
|
||||||
clipped.rect = bounds
|
Texture: this.Texture.Clip(bounds),
|
||||||
return &clipped
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func (this *texture) Close () error {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertTexture (unknown tomo.Texture) *texture {
|
func assertTexture (unknown tomo.Texture) *texture {
|
||||||
|
@ -332,7 +332,7 @@ func (window *window) reallocateCanvas () {
|
|||||||
if window.xCanvas != nil {
|
if window.xCanvas != nil {
|
||||||
window.xCanvas.Destroy()
|
window.xCanvas.Destroy()
|
||||||
}
|
}
|
||||||
window.xCanvas = xcanvas.NewFrom(xgraphics.New (
|
window.xCanvas = xcanvas.NewCanvasFrom(xgraphics.New (
|
||||||
window.backend.x,
|
window.backend.x,
|
||||||
image.Rect (
|
image.Rect (
|
||||||
0, 0,
|
0, 0,
|
||||||
|
Reference in New Issue
Block a user