From 8502818b6f04e4e3f8e08ffcf23b055cd8b6128c Mon Sep 17 00:00:00 2001 From: Thomas Friedel Date: Wed, 4 Apr 2018 16:54:50 +0200 Subject: [PATCH] clipping with the rect function now uses scissor test instead of stencil --- canvas.go | 11 +++++++++- openglinterface.go | 1 + paths.go | 50 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/canvas.go b/canvas.go index efe1758..92aa5e2 100644 --- a/canvas.go +++ b/canvas.go @@ -38,7 +38,8 @@ type drawState struct { lineDashPoint int lineDashOffset float64 - clip []pathPoint + scissor scissor + clip []pathPoint /* The current transformation matrix. The current clipping region. @@ -57,6 +58,11 @@ type drawStyle struct { image *Image } +type scissor struct { + on bool + tl, br vec +} + type lineJoin uint8 type lineEnd uint8 @@ -261,6 +267,8 @@ func LoadGL(glimpl GL) (err error) { gli.StencilOp(gl_KEEP, gl_KEEP, gl_KEEP) gli.StencilFunc(gl_EQUAL, 0, 0xFF) + gli.Enable(gl_SCISSOR_TEST) + return } @@ -504,6 +512,7 @@ func (cv *Canvas) Restore() { } 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 diff --git a/openglinterface.go b/openglinterface.go index af40834..f4c0267 100644 --- a/openglinterface.go +++ b/openglinterface.go @@ -826,6 +826,7 @@ type GL interface { GetUniformLocation(program uint32, name *uint8) int32 LinkProgram(program uint32) ReadPixels(x int32, y int32, width int32, height int32, format uint32, xtype uint32, pixels unsafe.Pointer) + Scissor(x int32, y int32, width int32, height int32) ShaderSource(shader uint32, count int32, xstring **uint8, length *int32) StencilFunc(xfunc uint32, ref int32, mask uint32) StencilMask(mask uint32) diff --git a/paths.go b/paths.go index 487b84b..d198dbb 100644 --- a/paths.go +++ b/paths.go @@ -17,6 +17,7 @@ type pathPointFlag uint8 const ( pathMove pathPointFlag = 1 << iota pathAttach + pathIsRect ) func (cv *Canvas) BeginPath() { @@ -497,10 +498,26 @@ func (cv *Canvas) Clip() { return } - cv.clip(cv.polyPath) + path := cv.polyPath + 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) + return + } + cv.activate() var triBuf [1000]float32 @@ -549,6 +566,35 @@ func (cv *Canvas) clip(path []pathPoint) { copy(cv.state.clip, cv.polyPath) } +func (cv *Canvas) scissor(path []pathPoint) { + tl, br := vec{math.MaxFloat64, math.MaxFloat64}, vec{} + for _, p := range path { + tl[0] = math.Min(p.tf[0], tl[0]) + tl[1] = math.Min(p.tf[1], tl[1]) + br[0] = math.Max(p.tf[0], br[0]) + br[1] = math.Max(p.tf[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]) + } + + 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)) + } +} + // Rect creates a closed rectangle path for stroking or filling func (cv *Canvas) Rect(x, y, w, h float64) { cv.MoveTo(x, y) @@ -556,6 +602,8 @@ func (cv *Canvas) Rect(x, y, w, h float64) { cv.LineTo(x+w, y+h) cv.LineTo(x, y+h) cv.ClosePath() + cv.linePath[len(cv.linePath)-1].flags |= pathIsRect + cv.polyPath[len(cv.polyPath)-1].flags |= pathIsRect } // Rect creates a closed rectangle path for stroking or filling