added polygon filling
This commit is contained in:
parent
c1de2f2b7d
commit
97615b7595
2 changed files with 136 additions and 7 deletions
46
canvas.go
46
canvas.go
|
@ -155,13 +155,14 @@ func (cv *Canvas) Stroke() {
|
|||
}
|
||||
p1 := p.pos
|
||||
|
||||
v := p1.Sub(p0).Norm()
|
||||
v = lm.Vec2{v[1], -v[0]}.MulF(cv.stroke.lineWidth * 0.5)
|
||||
v1 := p1.Sub(p0).Norm()
|
||||
v2 := lm.Vec2{v1[1], -v1[0]}.MulF(cv.stroke.lineWidth * 0.5)
|
||||
v1 = v1.MulF(cv.stroke.lineWidth * 0.5)
|
||||
|
||||
x0f, y0f := cv.vecToGL(p0.Add(v))
|
||||
x1f, y1f := cv.vecToGL(p1.Add(v))
|
||||
x2f, y2f := cv.vecToGL(p1.Sub(v))
|
||||
x3f, y3f := cv.vecToGL(p0.Sub(v))
|
||||
x0f, y0f := cv.vecToGL(p0.Sub(v1).Add(v2))
|
||||
x1f, y1f := cv.vecToGL(p1.Add(v1).Add(v2))
|
||||
x2f, y2f := cv.vecToGL(p1.Add(v1).Sub(v2))
|
||||
x3f, y3f := cv.vecToGL(p0.Sub(v1).Sub(v2))
|
||||
|
||||
tris = append(tris, x0f, y0f, x1f, y1f, x2f, y2f, x0f, y0f, x2f, y2f, x3f, y3f)
|
||||
|
||||
|
@ -170,7 +171,7 @@ func (cv *Canvas) Stroke() {
|
|||
|
||||
gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW)
|
||||
gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil)
|
||||
gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2))
|
||||
gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2-6))
|
||||
|
||||
gli.ColorMask(true, true, true, true)
|
||||
gli.StencilFunc(gl_EQUAL, 1, 0xFF)
|
||||
|
@ -182,3 +183,34 @@ func (cv *Canvas) Stroke() {
|
|||
|
||||
gli.Disable(gl_STENCIL_TEST)
|
||||
}
|
||||
|
||||
func (cv *Canvas) Fill() {
|
||||
if len(cv.path) < 3 {
|
||||
return
|
||||
}
|
||||
|
||||
cv.activate()
|
||||
|
||||
gli.UseProgram(sr.id)
|
||||
gli.Uniform4f(sr.color, cv.fill.r, cv.fill.g, cv.fill.b, cv.fill.a)
|
||||
gli.EnableVertexAttribArray(sr.vertex)
|
||||
|
||||
gli.BindBuffer(gl_ARRAY_BUFFER, buf)
|
||||
|
||||
var buf [1000]float32
|
||||
tris := buf[:0]
|
||||
tris = append(tris, -1, -1, -1, 1, 1, 1, -1, -1, 1, 1, 1, -1)
|
||||
|
||||
tris = triangulatePath(cv.path, tris)
|
||||
total := len(tris)
|
||||
for i := 12; i < total; i += 2 {
|
||||
x, y := tris[i], tris[i+1]
|
||||
tris[i], tris[i+1] = cv.ptToGL(x, y)
|
||||
}
|
||||
|
||||
gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW)
|
||||
gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, nil)
|
||||
gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2-6))
|
||||
|
||||
gli.DisableVertexAttribArray(sr.vertex)
|
||||
}
|
||||
|
|
97
triangulation.go
Normal file
97
triangulation.go
Normal file
|
@ -0,0 +1,97 @@
|
|||
package canvas
|
||||
|
||||
import (
|
||||
"github.com/void6/lm"
|
||||
)
|
||||
|
||||
func pointIsRightOfLine(a, b, p lm.Vec2) bool {
|
||||
if a[1] == b[1] {
|
||||
return false
|
||||
}
|
||||
if a[1] > b[1] {
|
||||
a, b = b, a
|
||||
}
|
||||
if p[1] < a[1] || p[1] > b[1] {
|
||||
return false
|
||||
}
|
||||
v := b.Sub(a)
|
||||
r := (p[1] - a[1]) / v[1]
|
||||
x := a[0] + r*v[0]
|
||||
return p[0] > x
|
||||
}
|
||||
|
||||
func triangleContainsPoint(a, b, c, p lm.Vec2) bool {
|
||||
// if point is outside triangle bounds, return false
|
||||
if p[0] < a[0] && p[0] < b[0] && p[0] < c[0] {
|
||||
return false
|
||||
}
|
||||
if p[0] > a[0] && p[0] > b[0] && p[0] > c[0] {
|
||||
return false
|
||||
}
|
||||
if p[1] < a[1] && p[1] < b[1] && p[1] < c[1] {
|
||||
return false
|
||||
}
|
||||
if p[1] > a[1] && p[1] > b[1] && p[1] > c[1] {
|
||||
return false
|
||||
}
|
||||
// check whether the point is to the right of each triangle line.
|
||||
// if the total is 1, it is inside the triangle
|
||||
count := 0
|
||||
if pointIsRightOfLine(a, b, p) {
|
||||
count++
|
||||
}
|
||||
if pointIsRightOfLine(b, c, p) {
|
||||
count++
|
||||
}
|
||||
if pointIsRightOfLine(c, a, p) {
|
||||
count++
|
||||
}
|
||||
return count == 1
|
||||
}
|
||||
|
||||
func polygonContainsPoint(polygon []lm.Vec2, p lm.Vec2) bool {
|
||||
a := polygon[len(polygon)-1]
|
||||
count := 0
|
||||
for _, b := range polygon {
|
||||
if pointIsRightOfLine(a, b, p) {
|
||||
count++
|
||||
}
|
||||
a = b
|
||||
}
|
||||
return count%2 == 1
|
||||
}
|
||||
|
||||
func triangulatePath(path []pathPoint, target []float32) []float32 {
|
||||
var buf [500]lm.Vec2
|
||||
polygon := buf[:0]
|
||||
for _, p := range path {
|
||||
polygon = append(polygon, p.pos)
|
||||
}
|
||||
|
||||
for len(polygon) > 2 {
|
||||
var i int
|
||||
triangles:
|
||||
for i = range polygon {
|
||||
a := polygon[i]
|
||||
b := polygon[(i+1)%len(polygon)]
|
||||
c := polygon[(i+2)%len(polygon)]
|
||||
for i2, p := range polygon {
|
||||
if i2 >= i && i2 <= i+2 {
|
||||
continue
|
||||
}
|
||||
if triangleContainsPoint(a, b, c, p) {
|
||||
continue triangles
|
||||
}
|
||||
center := a.Add(b).Add(c).DivF(3)
|
||||
if !polygonContainsPoint(polygon, center) {
|
||||
continue triangles
|
||||
}
|
||||
}
|
||||
target = append(target, a[0], a[1], b[0], b[1], c[0], c[1])
|
||||
break
|
||||
}
|
||||
remove := (i + 1) % len(polygon)
|
||||
polygon = append(polygon[:remove], polygon[remove+1:]...)
|
||||
}
|
||||
return target
|
||||
}
|
Loading…
Reference in a new issue