don't draw text that is outside the screen bounds

This commit is contained in:
Thomas Friedel 2018-04-14 11:56:42 +02:00
parent 489a758c3c
commit 0913a92782
2 changed files with 52 additions and 22 deletions

View file

@ -202,6 +202,24 @@ func (c *frContext) glyphAdvance(glyph truetype.Index) (fixed.Int26_6, error) {
return c.glyphBuf.AdvanceWidth, nil return c.glyphBuf.AdvanceWidth, nil
} }
func (c *frContext) glyphBounds(glyph truetype.Index, p fixed.Point26_6) (image.Rectangle, error) {
if err := c.glyphBuf.Load(c.f, c.scale, glyph, c.hinting); err != nil {
return image.Rectangle{}, err
}
fx := p.X & 0x3f
fy := p.Y & 0x3f
xmin := int(fx+c.glyphBuf.Bounds.Min.X) >> 6
ymin := int(fy-c.glyphBuf.Bounds.Max.Y) >> 6
xmax := int(fx+c.glyphBuf.Bounds.Max.X+0x3f) >> 6
ymax := int(fy-c.glyphBuf.Bounds.Min.Y+0x3f) >> 6
bounds := image.Rectangle{
Min: image.Point{X: xmin, Y: ymin},
Max: image.Point{X: xmax, Y: ymax}}
return bounds, nil
}
const maxInt = int(^uint(0) >> 1) const maxInt = int(^uint(0) >> 1)
// DrawString draws s at p and returns p advanced by the text extent. The text // DrawString draws s at p and returns p advanced by the text extent. The text

56
text.go
View file

@ -2,6 +2,7 @@ package canvas
import ( import (
"errors" "errors"
"image"
"io/ioutil" "io/ioutil"
"unsafe" "unsafe"
@ -90,35 +91,46 @@ func (cv *Canvas) FillText(str string, x, y float64) {
} }
x += float64(kern) / 64 x += float64(kern) / 64
} }
advance, mask, offset, err := frc.glyph(idx, fixed.Point26_6{})
if err != nil {
prev = 0
hasPrev = false
continue
}
bounds := mask.Bounds().Add(offset)
for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ {
off := y * mask.Stride
gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&mask.Pix[off]))
}
bounds, err := frc.glyphBounds(idx, fixed.Point26_6{})
var advance fixed.Int26_6
p0 := cv.tf(vec{float64(bounds.Min.X) + x, float64(bounds.Min.Y) + y}) p0 := cv.tf(vec{float64(bounds.Min.X) + x, float64(bounds.Min.Y) + y})
p1 := cv.tf(vec{float64(bounds.Min.X) + x, float64(bounds.Max.Y) + y}) p1 := cv.tf(vec{float64(bounds.Min.X) + x, float64(bounds.Max.Y) + y})
p2 := cv.tf(vec{float64(bounds.Max.X) + x, float64(bounds.Max.Y) + y}) p2 := cv.tf(vec{float64(bounds.Max.X) + x, float64(bounds.Max.Y) + y})
p3 := cv.tf(vec{float64(bounds.Max.X) + x, float64(bounds.Min.Y) + y}) p3 := cv.tf(vec{float64(bounds.Max.X) + x, float64(bounds.Min.Y) + y})
tw := float64(bounds.Dx()) / alphaTexSize inside := (p0[0] >= 0 || p1[0] >= 0 || p2[0] >= 0 || p3[0] >= 0) &&
th := float64(bounds.Dy()) / alphaTexSize (p0[1] >= 0 || p1[1] >= 0 || p2[1] >= 0 || p3[1] >= 0) &&
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]), (p0[0] < cv.fw || p1[0] < cv.fw || p2[0] < cv.fw || p3[0] < cv.fw) &&
0, 1, 0, float32(1 - th), float32(tw), float32(1 - th), float32(tw), 1} (p0[1] < cv.fh || p1[1] < cv.fh || p2[1] < cv.fh || p3[1] < cv.fh)
gli.BufferData(gl_ARRAY_BUFFER, len(data)*4, unsafe.Pointer(&data[0]), gl_STREAM_DRAW) if inside {
var mask *image.Alpha
advance, mask, _, err = frc.glyph(idx, fixed.Point26_6{})
if err != nil {
prev = 0
hasPrev = false
continue
}
gli.VertexAttribPointer(vertex, 2, gl_FLOAT, false, 0, nil) for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ {
gli.VertexAttribPointer(alphaTexCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4)) off := y * mask.Stride
gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4) gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&mask.Pix[off]))
}
for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ { tw := float64(bounds.Dx()) / alphaTexSize
gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&zeroes[0])) th := float64(bounds.Dy()) / 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, nil)
gli.VertexAttribPointer(alphaTexCoord, 2, gl_FLOAT, false, 0, gli.PtrOffset(8*4))
gli.DrawArrays(gl_TRIANGLE_FAN, 0, 4)
for y, w, h := 0, bounds.Dx(), bounds.Dy(); y < h; y++ {
gli.TexSubImage2D(gl_TEXTURE_2D, 0, 0, int32(alphaTexSize-1-y), int32(w), 1, gl_ALPHA, gl_UNSIGNED_BYTE, gli.Ptr(&zeroes[0]))
}
} else {
advance, _ = frc.glyphAdvance(idx)
} }
x += float64(advance) / 64 x += float64(advance) / 64