added dashed lines
This commit is contained in:
parent
d9854d540e
commit
46c68ca5ad
2 changed files with 92 additions and 20 deletions
24
canvas.go
24
canvas.go
|
@ -14,7 +14,8 @@ type Canvas struct {
|
||||||
x, y, w, h int
|
x, y, w, h int
|
||||||
fx, fy, fw, fh float32
|
fx, fy, fw, fh float32
|
||||||
|
|
||||||
path []pathPoint
|
polyPath []pathPoint
|
||||||
|
linePath []pathPoint
|
||||||
text struct {
|
text struct {
|
||||||
target *image.RGBA
|
target *image.RGBA
|
||||||
tex uint32
|
tex uint32
|
||||||
|
@ -44,6 +45,10 @@ type drawState struct {
|
||||||
fontSize float32
|
fontSize float32
|
||||||
lineJoin lineJoin
|
lineJoin lineJoin
|
||||||
lineEnd lineEnd
|
lineEnd lineEnd
|
||||||
|
|
||||||
|
lineDash []float32
|
||||||
|
lineDashPoint int
|
||||||
|
lineDashOffset float32
|
||||||
/*
|
/*
|
||||||
The current transformation matrix.
|
The current transformation matrix.
|
||||||
The current clipping region.
|
The current clipping region.
|
||||||
|
@ -231,6 +236,23 @@ func (cv *Canvas) SetLineEnd(end lineEnd) {
|
||||||
cv.state.lineEnd = end
|
cv.state.lineEnd = end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetLineDash sets the line dash style
|
||||||
|
func (cv *Canvas) SetLineDash(dash []float32) {
|
||||||
|
l := len(dash)
|
||||||
|
if l%2 == 0 {
|
||||||
|
d2 := make([]float32, l)
|
||||||
|
copy(d2, dash)
|
||||||
|
cv.state.lineDash = d2
|
||||||
|
} else {
|
||||||
|
d2 := make([]float32, l*2)
|
||||||
|
copy(d2[:l], dash)
|
||||||
|
copy(d2[l:], dash)
|
||||||
|
cv.state.lineDash = d2
|
||||||
|
}
|
||||||
|
cv.state.lineDashPoint = 0
|
||||||
|
cv.state.lineDashOffset = 0
|
||||||
|
}
|
||||||
|
|
||||||
// Save saves the current draw state to a stack
|
// Save saves the current draw state to a stack
|
||||||
func (cv *Canvas) Save() {
|
func (cv *Canvas) Save() {
|
||||||
cv.stateStack = append(cv.stateStack, cv.state)
|
cv.stateStack = append(cv.stateStack, cv.state)
|
||||||
|
|
86
paths.go
86
paths.go
|
@ -9,24 +9,67 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func (cv *Canvas) BeginPath() {
|
func (cv *Canvas) BeginPath() {
|
||||||
if cv.path == nil {
|
if cv.linePath == nil {
|
||||||
cv.path = make([]pathPoint, 0, 100)
|
cv.linePath = make([]pathPoint, 0, 100)
|
||||||
}
|
}
|
||||||
cv.path = cv.path[:0]
|
if cv.polyPath == nil {
|
||||||
|
cv.polyPath = make([]pathPoint, 0, 100)
|
||||||
|
}
|
||||||
|
cv.linePath = cv.linePath[:0]
|
||||||
|
cv.polyPath = cv.polyPath[:0]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) MoveTo(x, y float32) {
|
func (cv *Canvas) MoveTo(x, y float32) {
|
||||||
cv.path = append(cv.path, pathPoint{pos: lm.Vec2{x, y}, move: true})
|
cv.linePath = append(cv.linePath, pathPoint{pos: lm.Vec2{x, y}, move: true})
|
||||||
|
cv.polyPath = append(cv.polyPath, pathPoint{pos: lm.Vec2{x, y}, move: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) LineTo(x, y float32) {
|
func (cv *Canvas) LineTo(x, y float32) {
|
||||||
if len(cv.path) == 0 {
|
if len(cv.linePath) == 0 {
|
||||||
cv.MoveTo(x, y)
|
cv.MoveTo(x, y)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cv.path[len(cv.path)-1].next = lm.Vec2{x, y}
|
if len(cv.state.lineDash) > 0 {
|
||||||
cv.path[len(cv.path)-1].attach = true
|
lp := cv.linePath[len(cv.linePath)-1].pos
|
||||||
cv.path = append(cv.path, pathPoint{pos: lm.Vec2{x, y}, move: false})
|
tp := lm.Vec2{x, y}
|
||||||
|
v := tp.Sub(lp)
|
||||||
|
vl := v.Len()
|
||||||
|
prev := cv.state.lineDashOffset
|
||||||
|
for vl > 0 {
|
||||||
|
draw := cv.state.lineDashPoint%2 == 0
|
||||||
|
p := tp
|
||||||
|
cv.state.lineDashOffset += vl
|
||||||
|
if cv.state.lineDashOffset > cv.state.lineDash[cv.state.lineDashPoint] {
|
||||||
|
cv.state.lineDashOffset = 0
|
||||||
|
dl := cv.state.lineDash[cv.state.lineDashPoint] - prev
|
||||||
|
p = lp.Add(v.MulF(dl / vl))
|
||||||
|
vl -= dl
|
||||||
|
cv.state.lineDashPoint++
|
||||||
|
cv.state.lineDashPoint %= len(cv.state.lineDash)
|
||||||
|
prev = 0
|
||||||
|
} else {
|
||||||
|
vl = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if draw {
|
||||||
|
cv.linePath[len(cv.linePath)-1].next = p
|
||||||
|
cv.linePath[len(cv.linePath)-1].attach = true
|
||||||
|
cv.linePath = append(cv.linePath, pathPoint{pos: p, move: false})
|
||||||
|
} else {
|
||||||
|
cv.linePath = append(cv.linePath, pathPoint{pos: p, move: true})
|
||||||
|
}
|
||||||
|
|
||||||
|
lp = p
|
||||||
|
v = tp.Sub(lp)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cv.linePath[len(cv.linePath)-1].next = lm.Vec2{x, y}
|
||||||
|
cv.linePath[len(cv.linePath)-1].attach = true
|
||||||
|
cv.linePath = append(cv.linePath, pathPoint{pos: lm.Vec2{x, y}, move: false})
|
||||||
|
}
|
||||||
|
cv.polyPath[len(cv.polyPath)-1].next = lm.Vec2{x, y}
|
||||||
|
cv.polyPath[len(cv.polyPath)-1].attach = true
|
||||||
|
cv.polyPath = append(cv.polyPath, pathPoint{pos: lm.Vec2{x, y}, move: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float32, anticlockwise bool) {
|
func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float32, anticlockwise bool) {
|
||||||
|
@ -53,16 +96,23 @@ func (cv *Canvas) Arc(x, y, radius, startAngle, endAngle float32, anticlockwise
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) ClosePath() {
|
func (cv *Canvas) ClosePath() {
|
||||||
if len(cv.path) < 2 {
|
if len(cv.linePath) < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cv.path[len(cv.path)-1].next = cv.path[0].pos
|
if len(cv.state.lineDash) > 0 {
|
||||||
cv.path[len(cv.path)-1].attach = true
|
cv.LineTo(cv.linePath[0].pos[0], cv.linePath[0].pos[1])
|
||||||
cv.path = append(cv.path, pathPoint{pos: cv.path[0].pos, move: false, next: cv.path[1].pos, attach: true})
|
return
|
||||||
|
}
|
||||||
|
cv.linePath[len(cv.linePath)-1].next = cv.linePath[0].pos
|
||||||
|
cv.linePath[len(cv.linePath)-1].attach = true
|
||||||
|
cv.linePath = append(cv.linePath, pathPoint{pos: cv.linePath[0].pos, move: false, next: cv.linePath[1].pos, attach: true})
|
||||||
|
cv.polyPath[len(cv.polyPath)-1].next = cv.polyPath[0].pos
|
||||||
|
cv.polyPath[len(cv.polyPath)-1].attach = true
|
||||||
|
cv.polyPath = append(cv.polyPath, pathPoint{pos: cv.polyPath[0].pos, move: false, next: cv.polyPath[1].pos, attach: true})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) Stroke() {
|
func (cv *Canvas) Stroke() {
|
||||||
if len(cv.path) == 0 {
|
if len(cv.linePath) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +137,7 @@ func (cv *Canvas) Stroke() {
|
||||||
|
|
||||||
start := true
|
start := true
|
||||||
var p0 lm.Vec2
|
var p0 lm.Vec2
|
||||||
for _, p := range cv.path {
|
for _, p := range cv.linePath {
|
||||||
if p.move {
|
if p.move {
|
||||||
p0 = p.pos
|
p0 = p.pos
|
||||||
start = true
|
start = true
|
||||||
|
@ -238,13 +288,13 @@ func lineIntersection(a0, a1, b0, b1 lm.Vec2) lm.Vec2 {
|
||||||
|
|
||||||
func (cv *Canvas) Fill() {
|
func (cv *Canvas) Fill() {
|
||||||
lastMove := 0
|
lastMove := 0
|
||||||
for i, p := range cv.path {
|
for i, p := range cv.polyPath {
|
||||||
if p.move {
|
if p.move {
|
||||||
lastMove = i
|
lastMove = i
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path := cv.path[lastMove:]
|
path := cv.polyPath[lastMove:]
|
||||||
|
|
||||||
if len(path) < 3 {
|
if len(path) < 3 {
|
||||||
return
|
return
|
||||||
|
@ -278,7 +328,7 @@ func (cv *Canvas) Fill() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cv *Canvas) Clip() {
|
func (cv *Canvas) Clip() {
|
||||||
if len(cv.path) < 3 {
|
if len(cv.polyPath) < 3 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +351,7 @@ func (cv *Canvas) Clip() {
|
||||||
tris := buf[:0]
|
tris := buf[:0]
|
||||||
tris = append(tris, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1)
|
tris = append(tris, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1)
|
||||||
|
|
||||||
tris = triangulatePath(cv.path, tris)
|
tris = triangulatePath(cv.polyPath, tris)
|
||||||
total := len(tris)
|
total := len(tris)
|
||||||
for i := 12; i < total; i += 2 {
|
for i := 12; i < total; i += 2 {
|
||||||
x, y := tris[i], tris[i+1]
|
x, y := tris[i], tris[i+1]
|
||||||
|
|
Loading…
Reference in a new issue