moved clipping to backend

This commit is contained in:
Thomas Friedel 2019-02-22 12:08:34 +01:00
parent cf788d55f3
commit fe9d6e60e4
7 changed files with 107 additions and 133 deletions

View file

@ -20,6 +20,9 @@ type Backend interface {
DrawImage(dimg Image, sx, sy, sw, sh, dx, dy, dw, dh float64, alpha float64)
FillImageMask(style *FillStyle, mask *image.Alpha, pts [][2]float64) // pts must have four points
ClearClip()
Clip(pts [][2]float64)
GetImageData(x, y, w, h int) *image.RGBA
PutImageData(img *image.RGBA, x, y int)
}

62
backend/gogl/clip.go Normal file
View file

@ -0,0 +1,62 @@
package goglbackend
import (
"unsafe"
"github.com/go-gl/gl/v3.2-core/gl"
)
func (b *GoGLBackend) ClearClip() {
gl.StencilMask(0xFF)
gl.Clear(gl.STENCIL_BUFFER_BIT)
}
func (b *GoGLBackend) Clip(pts [][2]float64) {
b.ptsBuf = b.ptsBuf[:0]
b.ptsBuf = append(b.ptsBuf,
0, 0,
0, float32(b.fh),
float32(b.fw), float32(b.fh),
float32(b.fw), 0)
for _, pt := range pts {
b.ptsBuf = append(b.ptsBuf, float32(pt[0]), float32(pt[1]))
}
mode := uint32(gl.TRIANGLES)
if len(pts) == 4 {
mode = gl.TRIANGLE_FAN
}
gl.BindBuffer(gl.ARRAY_BUFFER, b.buf)
gl.BufferData(gl.ARRAY_BUFFER, len(b.ptsBuf)*4, unsafe.Pointer(&b.ptsBuf[0]), gl.STREAM_DRAW)
gl.VertexAttribPointer(b.sr.Vertex, 2, gl.FLOAT, false, 0, nil)
gl.UseProgram(b.sr.ID)
gl.Uniform4f(b.sr.Color, 1, 1, 1, 1)
gl.Uniform2f(b.sr.CanvasSize, float32(b.fw), float32(b.fh))
gl.EnableVertexAttribArray(b.sr.Vertex)
gl.ColorMask(false, false, false, false)
gl.StencilMask(0x04)
gl.StencilFunc(gl.ALWAYS, 4, 0x04)
gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
gl.DrawArrays(mode, 4, int32(len(pts)))
gl.StencilMask(0x02)
gl.StencilFunc(gl.EQUAL, 0, 0x06)
gl.StencilOp(gl.KEEP, gl.INVERT, gl.INVERT)
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
gl.StencilMask(0x04)
gl.StencilFunc(gl.ALWAYS, 0, 0x04)
gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
gl.DisableVertexAttribArray(b.sr.Vertex)
gl.ColorMask(true, true, true, true)
gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
gl.StencilMask(0xFF)
gl.StencilFunc(gl.EQUAL, 0, 0xFF)
}

View file

@ -54,10 +54,17 @@ func (b *GoGLBackend) Clear(pts [4][2]float64) {
}
func (b *GoGLBackend) clearRect(x, y, w, h int) {
gl.Enable(gl.SCISSOR_TEST)
var box [4]int32
gl.GetIntegerv(gl.SCISSOR_BOX, &box[0])
gl.Scissor(int32(x), int32(b.h-y-h), int32(w), int32(h))
gl.ClearColor(0, 0, 0, 0)
gl.Clear(gl.COLOR_BUFFER_BIT)
// cv.applyScissor()
gl.Scissor(box[0], box[1], box[2], box[3])
gl.Disable(gl.SCISSOR_TEST)
}
func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) {

View file

@ -205,7 +205,7 @@ func New(x, y, w, h int) (backendbase.Backend, error) {
gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
gl.StencilFunc(gl.EQUAL, 0, 0xFF)
gl.Enable(gl.SCISSOR_TEST)
gl.Disable(gl.SCISSOR_TEST)
return b, nil
}

View file

@ -59,7 +59,6 @@ type drawState struct {
lineDashPoint int
lineDashOffset float64
scissor scissor
clip Path2D
shadowColor color.RGBA
@ -85,11 +84,6 @@ type drawStyle struct {
image *Image
}
type scissor struct {
on bool
tl, br vec
}
type lineJoin uint8
type lineCap uint8
@ -221,8 +215,6 @@ func (cv *Canvas) Activate() {
gli.Viewport(int32(cv.x), int32(cv.y), int32(cv.w), int32(cv.h))
cv.disableTextureRenderTarget()
}
cv.applyScissor()
gli.Clear(gl_STENCIL_BUFFER_BIT)
}
var activeCanvas *Canvas
@ -535,18 +527,14 @@ func (cv *Canvas) Restore() {
if l <= 0 {
return
}
cv.state.scissor = scissor{}
cv.applyScissor()
gli.StencilMask(0xFF)
gli.Clear(gl_STENCIL_BUFFER_BIT)
cv.b.ClearClip()
for _, st := range cv.stateStack {
if len(st.clip.p) > 0 {
cv.clip(st.clip.p)
cv.clip(&st.clip)
}
}
cv.state = cv.stateStack[l-1]
cv.stateStack = cv.stateStack[:l-1]
cv.applyScissor()
}
// Scale updates the current transformation with a scaling by the given values

144
paths.go
View file

@ -331,21 +331,7 @@ func (cv *Canvas) FillPath(path *Path2D) {
cv.activate()
var triBuf [500][2]float64
tris := triBuf[:0]
start := 0
for i, p := range path.p {
if p.flags&pathMove == 0 {
continue
}
if i >= start+3 {
tris = cv.appendSubPathTriangles(tris, path.p[start:i])
}
start = i
}
if len(path.p) >= start+3 {
tris = cv.appendSubPathTriangles(tris, path.p[start:])
}
tris := buildFillTriangles(path, triBuf[:0])
if len(tris) == 0 {
return
}
@ -356,7 +342,24 @@ func (cv *Canvas) FillPath(path *Path2D) {
cv.b.Fill(&stl, tris)
}
func (cv *Canvas) appendSubPathTriangles(tris [][2]float64, path []pathPoint) [][2]float64 {
func buildFillTriangles(path *Path2D, tris [][2]float64) [][2]float64 {
start := 0
for i, p := range path.p {
if p.flags&pathMove == 0 {
continue
}
if i >= start+3 {
tris = appendSubPathTriangles(tris, path.p[start:i])
}
start = i
}
if len(path.p) >= start+3 {
tris = appendSubPathTriangles(tris, path.p[start:])
}
return tris
}
func appendSubPathTriangles(tris [][2]float64, path []pathPoint) [][2]float64 {
last := path[len(path)-1]
if last.flags&pathIsConvex != 0 {
p0, p1 := path[0].pos, path[1].pos
@ -367,7 +370,7 @@ func (cv *Canvas) appendSubPathTriangles(tris [][2]float64, path []pathPoint) []
p1 = p2
}
} else if last.flags&pathSelfIntersects != 0 {
path = cv.cutIntersections(path)
path = cutIntersections(path)
tris = triangulatePath(path, tris)
} else {
tris = triangulatePath(path, tris)
@ -378,110 +381,21 @@ func (cv *Canvas) appendSubPathTriangles(tris [][2]float64, path []pathPoint) []
// Clip uses the current path to clip any further drawing. Use Save/Restore to
// remove the clipping again
func (cv *Canvas) Clip() {
if len(cv.path.p) < 3 {
cv.clip(&cv.path)
}
func (cv *Canvas) clip(path *Path2D) {
if len(path.p) < 3 {
return
}
path := cv.path.p
for i := len(path) - 1; i >= 0; i-- {
if path[i].flags&pathMove != 0 {
path = path[i:]
break
}
}
cv.clip(path)
}
func (cv *Canvas) clip(path []pathPoint) {
if len(path) < 3 {
return
}
if path[len(path)-1].flags&pathIsRect != 0 {
cv.scissor(path)
var triBuf [500][2]float64
tris := buildFillTriangles(path, triBuf[:0])
if len(tris) == 0 {
return
}
// cv.activate()
// var triBuf [1000]float32
// tris := triBuf[:0]
// tris = append(tris, 0, 0, float32(cv.fw), 0, float32(cv.fw), float32(cv.fh), 0, 0, float32(cv.fw), float32(cv.fh), 0, float32(cv.fh))
// baseLen := len(tris)
// tris = triangulatePath(path, tris)
// if len(tris) <= baseLen {
// return
// }
// gli.BindBuffer(gl_ARRAY_BUFFER, buf)
// gli.BufferData(gl_ARRAY_BUFFER, len(tris)*4, unsafe.Pointer(&tris[0]), gl_STREAM_DRAW)
// gli.VertexAttribPointer(sr.vertex, 2, gl_FLOAT, false, 0, 0)
// gli.UseProgram(sr.id)
// gli.Uniform4f(sr.color, 1, 1, 1, 1)
// gli.Uniform2f(sr.canvasSize, float32(cv.fw), float32(cv.fh))
// gli.EnableVertexAttribArray(sr.vertex)
// gli.ColorMask(false, false, false, false)
// gli.StencilMask(0x04)
// gli.StencilFunc(gl_ALWAYS, 4, 0x04)
// gli.StencilOp(gl_REPLACE, gl_REPLACE, gl_REPLACE)
// gli.DrawArrays(gl_TRIANGLES, 6, int32(len(tris)/2-6))
// gli.StencilMask(0x02)
// gli.StencilFunc(gl_EQUAL, 0, 0x06)
// gli.StencilOp(gl_KEEP, gl_INVERT, gl_INVERT)
// gli.DrawArrays(gl_TRIANGLES, 0, 6)
// gli.StencilMask(0x04)
// gli.StencilFunc(gl_ALWAYS, 0, 0x04)
// gli.StencilOp(gl_ZERO, gl_ZERO, gl_ZERO)
// gli.DrawArrays(gl_TRIANGLES, 0, 6)
// gli.DisableVertexAttribArray(sr.vertex)
// gli.ColorMask(true, true, true, true)
// gli.StencilOp(gl_KEEP, gl_KEEP, gl_KEEP)
// gli.StencilMask(0xFF)
// gli.StencilFunc(gl_EQUAL, 0, 0xFF)
// cv.state.clip = cv.path
// cv.state.clip.p = make([]pathPoint, len(cv.path.p))
// copy(cv.state.clip.p, cv.path.p)
}
func (cv *Canvas) scissor(path []pathPoint) {
tl, br := vec{math.MaxFloat64, math.MaxFloat64}, vec{}
for _, p := range path {
tl[0] = math.Min(p.pos[0], tl[0])
tl[1] = math.Min(p.pos[1], tl[1])
br[0] = math.Max(p.pos[0], br[0])
br[1] = math.Max(p.pos[1], br[1])
}
if cv.state.scissor.on {
tl[0] = math.Max(tl[0], cv.state.scissor.tl[0])
tl[1] = math.Max(tl[1], cv.state.scissor.tl[1])
br[0] = math.Min(br[0], cv.state.scissor.br[0])
br[1] = math.Min(br[1], cv.state.scissor.br[1])
}
if tl[0] >= br[0] || tl[1] >= br[1] {
tl, br = vec{}, vec{}
}
cv.state.scissor = scissor{tl: tl, br: br, on: true}
cv.applyScissor()
}
func (cv *Canvas) applyScissor() {
s := &cv.state.scissor
if s.on {
gli.Scissor(int32(s.tl[0]+0.5), int32(cv.fh-s.br[1]+0.5), int32(s.br[0]-s.tl[0]+0.5), int32(s.br[1]-s.tl[1]+0.5))
} else {
gli.Scissor(0, 0, int32(cv.w), int32(cv.h))
}
cv.b.Clip(tris)
}
// Rect creates a closed rectangle path for stroking or filling

View file

@ -102,7 +102,7 @@ func triangulatePath(path []pathPoint, target [][2]float64) [][2]float64 {
return target
}
func (cv *Canvas) cutIntersections(path []pathPoint) []pathPoint {
func cutIntersections(path []pathPoint) []pathPoint {
type cut struct {
from, to int
j int