diff --git a/backend/backendbase/base.go b/backend/backendbase/base.go index c0e224c..2471dad 100644 --- a/backend/backendbase/base.go +++ b/backend/backendbase/base.go @@ -18,6 +18,7 @@ type Backend interface { Clear(pts [4][2]float64) Fill(style *FillStyle, pts [][2]float64) DrawImage(dimg Image, sx, sy, sw, sh, dx, dy, dw, dh float64, alpha float64) + FillImageMask(style *FillStyle, mask *image.Alpha, pts [4][2]float64) } // FillStyle is the color and other details on how to fill diff --git a/backend/gogl/fill.go b/backend/gogl/fill.go index a04b448..158d7b2 100644 --- a/backend/gogl/fill.go +++ b/backend/gogl/fill.go @@ -1,6 +1,7 @@ package goglbackend import ( + "image" "math" "unsafe" @@ -117,6 +118,57 @@ func (b *GoGLBackend) Fill(style *backendbase.FillStyle, pts [][2]float64) { } } +func (b *GoGLBackend) FillImageMask(style *backendbase.FillStyle, mask *image.Alpha, pts [4][2]float64) { + w, h := mask.Rect.Dx(), mask.Rect.Dy() + + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, b.alphaTex) + for y := 0; y < h; y++ { + off := y * mask.Stride + gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl.ALPHA, gl.UNSIGNED_BYTE, gl.Ptr(&mask.Pix[off])) + } + + // b.drawTextShadow(textOffset, w, h, x, y) + + gl.StencilFunc(gl.EQUAL, 0, 0xFF) + + gl.BindBuffer(gl.ARRAY_BUFFER, b.buf) + + vertex, alphaTexCoord := b.useAlphaShader(style, 1) + + gl.EnableVertexAttribArray(vertex) + gl.EnableVertexAttribArray(alphaTexCoord) + + tw := float64(w) / alphaTexSize + th := float64(h) / alphaTexSize + var buf [16]float32 + data := buf[:0] + for _, pt := range pts { + data = append(data, float32(pt[0]), float32(pt[1])) + } + data = append(data, 0, 1, 0, float32(1-th), float32(tw), float32(1-th), float32(tw), 1) + + gl.BufferData(gl.ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl.STREAM_DRAW) + + gl.VertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, nil) + gl.VertexAttribPointer(alphaTexCoord, 2, gl.FLOAT, false, 0, gl.PtrOffset(8*4)) + gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) + + gl.DisableVertexAttribArray(vertex) + gl.DisableVertexAttribArray(alphaTexCoord) + + gl.ActiveTexture(gl.TEXTURE1) + gl.BindTexture(gl.TEXTURE_2D, b.alphaTex) + + gl.StencilFunc(gl.ALWAYS, 0, 0xFF) + + for y := 0; y < h; y++ { + gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl.ALPHA, gl.UNSIGNED_BYTE, gl.Ptr(&zeroes[0])) + } + + gl.ActiveTexture(gl.TEXTURE0) +} + func (b *GoGLBackend) drawBlurred(blur float64) { gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA) diff --git a/backend/gogl/gogl.go b/backend/gogl/gogl.go index 579ef81..594df28 100644 --- a/backend/gogl/gogl.go +++ b/backend/gogl/gogl.go @@ -11,6 +11,8 @@ import ( const alphaTexSize = 2048 +var zeroes [alphaTexSize]byte + type GoGLBackend struct { x, y, w, h int fx, fy, fw, fh float64 diff --git a/text.go b/text.go index 54112bd..2496857 100644 --- a/text.go +++ b/text.go @@ -5,7 +5,6 @@ import ( "image" "image/draw" "io/ioutil" - "unsafe" "github.com/golang/freetype" "github.com/golang/freetype/truetype" @@ -210,52 +209,14 @@ func (cv *Canvas) FillText(str string, x, y float64) { yOff = -float64(metrics.Descent) / 64 } - gli.ActiveTexture(gl_TEXTURE1) - gli.BindTexture(gl_TEXTURE_2D, alphaTex) - for y := 0; y < strHeight; y++ { - off := y * textImage.Stride - gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(strWidth), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&textImage.Pix[off])) - } + var pts [4][2]float64 + pts[0] = cv.tf(vec{float64(textOffset.X) + x, float64(textOffset.Y) + y + yOff}) + pts[1] = cv.tf(vec{float64(textOffset.X) + x, float64(textOffset.Y+strHeight) + y + yOff}) + pts[2] = cv.tf(vec{float64(textOffset.X+strWidth) + x, float64(textOffset.Y+strHeight) + y + yOff}) + pts[3] = cv.tf(vec{float64(textOffset.X+strWidth) + x, float64(textOffset.Y) + y + yOff}) - cv.drawTextShadow(textOffset, strWidth, strHeight, x, y) - - gli.StencilFunc(gl_EQUAL, 0, 0xFF) - - gli.BindBuffer(gl_ARRAY_BUFFER, buf) - - vertex, alphaTexCoord := cv.useAlphaShader(&cv.state.fill, 1) - - gli.EnableVertexAttribArray(vertex) - gli.EnableVertexAttribArray(alphaTexCoord) - - p0 := cv.tf(vec{float64(textOffset.X) + x, float64(textOffset.Y) + y + yOff}) - p1 := cv.tf(vec{float64(textOffset.X) + x, float64(textOffset.Y+strHeight) + y + yOff}) - p2 := cv.tf(vec{float64(textOffset.X+strWidth) + x, float64(textOffset.Y+strHeight) + y + yOff}) - p3 := cv.tf(vec{float64(textOffset.X+strWidth) + x, float64(textOffset.Y) + y + yOff}) - - tw := float64(strWidth) / alphaTexSize - th := float64(strHeight) / alphaTexSize - data := [16]float32{float32(p0[0]), float32(p0[1]), float32(p1[0]), float32(p1[1]), float32(p2[0]), float32(p2[1]), float32(p3[0]), float32(p3[1]), - 0, 1, 0, float32(1 - th), float32(tw), float32(1 - th), float32(tw), 1} - gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) - - gli.VertexAttribPointer(vertex, 2, gl_FLOAT, false, 0, 0) - gli.VertexAttribPointer(alphaTexCoord, 2, gl_FLOAT, false, 0, 8*4) - gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) - - gli.DisableVertexAttribArray(vertex) - gli.DisableVertexAttribArray(alphaTexCoord) - - gli.ActiveTexture(gl_TEXTURE1) - gli.BindTexture(gl_TEXTURE_2D, alphaTex) - - gli.StencilFunc(gl_ALWAYS, 0, 0xFF) - - for y := 0; y < strHeight; y++ { - gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(strWidth), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&zeroes[0])) - } - - gli.ActiveTexture(gl_TEXTURE0) + stl := cv.backendFillStyle(&cv.state.fill, 1) + cv.b.FillImageMask(&stl, textImage.SubImage(image.Rect(0, 0, strWidth, strHeight)).(*image.Alpha), pts) } // StrokeText draws the given string at the given coordinates