moved clipping to backend
This commit is contained in:
parent
cf788d55f3
commit
fe9d6e60e4
7 changed files with 107 additions and 133 deletions
|
@ -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
62
backend/gogl/clip.go
Normal 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)
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
16
canvas.go
16
canvas.go
|
@ -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
144
paths.go
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue