mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 14:38:19 +00:00
Use per-char width instead of fixed advance in font atlas
This gives us more (much?) efficient packing of letters and we load exact size of the letters. It looks visually a lot better too! This wasn't good with normal smapling, but using texelFetch its great.
This commit is contained in:
@ -2,6 +2,7 @@ package glyphs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
@ -10,7 +11,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/bloeys/gglm/gglm"
|
|
||||||
"github.com/bloeys/nterm/assert"
|
"github.com/bloeys/nterm/assert"
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
@ -25,12 +25,13 @@ type FontAtlas struct {
|
|||||||
//Advance is global to the atlas because we only support monospaced fonts
|
//Advance is global to the atlas because we only support monospaced fonts
|
||||||
Advance int
|
Advance int
|
||||||
LineHeight int
|
LineHeight int
|
||||||
SizeUV gglm.Vec2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FontAtlasGlyph struct {
|
type FontAtlasGlyph struct {
|
||||||
U float32
|
U float32
|
||||||
V float32
|
V float32
|
||||||
|
SizeU float32
|
||||||
|
SizeV float32
|
||||||
|
|
||||||
Ascent float32
|
Ascent float32
|
||||||
Descent float32
|
Descent float32
|
||||||
@ -73,8 +74,8 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*Fo
|
|||||||
assert.T(len(glyphs) > 0, "no glyphs")
|
assert.T(len(glyphs) > 0, "no glyphs")
|
||||||
|
|
||||||
//Find advance and line height
|
//Find advance and line height
|
||||||
const charPaddingX = 2
|
const charPaddingX = 4
|
||||||
const charPaddingY = 2
|
const charPaddingY = 4
|
||||||
charAdvFixed, _ := face.GlyphAdvance('L')
|
charAdvFixed, _ := face.GlyphAdvance('L')
|
||||||
charAdv := charAdvFixed.Ceil() + charPaddingX
|
charAdv := charAdvFixed.Ceil() + charPaddingX
|
||||||
|
|
||||||
@ -120,7 +121,7 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*Fo
|
|||||||
|
|
||||||
//Create atlas
|
//Create atlas
|
||||||
// atlasSizeXF32 := float32(atlasSizeX)
|
// atlasSizeXF32 := float32(atlasSizeX)
|
||||||
atlasSizeYF32 := float32(atlasSizeY)
|
// atlasSizeYF32 := float32(atlasSizeY)
|
||||||
atlas := &FontAtlas{
|
atlas := &FontAtlas{
|
||||||
Font: f,
|
Font: f,
|
||||||
Img: image.NewRGBA(image.Rect(0, 0, atlasSizeX, atlasSizeY)),
|
Img: image.NewRGBA(image.Rect(0, 0, atlasSizeX, atlasSizeY)),
|
||||||
@ -128,7 +129,6 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*Fo
|
|||||||
|
|
||||||
Advance: charAdv - charPaddingX,
|
Advance: charAdv - charPaddingX,
|
||||||
LineHeight: lineHeight,
|
LineHeight: lineHeight,
|
||||||
SizeUV: *gglm.NewVec2(float32(charAdv-charPaddingX), float32(lineHeight)),
|
|
||||||
// SizeUV: *gglm.NewVec2(float32(charAdv-charPaddingX)/atlasSizeXF32, float32(lineHeight)/atlasSizeYF32),
|
// SizeUV: *gglm.NewVec2(float32(charAdv-charPaddingX)/atlasSizeXF32, float32(lineHeight)/atlasSizeYF32),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,70 +146,58 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*Fo
|
|||||||
|
|
||||||
charsOnLine := 0
|
charsOnLine := 0
|
||||||
drawer.Dot = fixed.P(atlas.Advance+charPaddingX, lineHeight)
|
drawer.Dot = fixed.P(atlas.Advance+charPaddingX, lineHeight)
|
||||||
|
const drawBoundingBoxes = false
|
||||||
|
|
||||||
drawHorizontalLines := true
|
for currGlyphCount, g := range glyphs {
|
||||||
drawVerticalLines := true
|
|
||||||
for _, g := range glyphs {
|
|
||||||
|
|
||||||
gBounds, _, _ := face.GlyphBounds(g)
|
gBounds, _, _ := face.GlyphBounds(g)
|
||||||
ascent := absFixedI26_6(gBounds.Min.Y)
|
bearingX := gBounds.Min.X
|
||||||
descent := absFixedI26_6(gBounds.Max.Y)
|
ascentAbsFixed := absFixedI26_6(gBounds.Min.Y)
|
||||||
bearingX := absFixedI26_6(gBounds.Min.X)
|
descentAbsFixed := absFixedI26_6(gBounds.Max.Y)
|
||||||
|
gWidth := gBounds.Min.X + gBounds.Max.X
|
||||||
|
|
||||||
|
gTopLeft := image.Point{
|
||||||
|
X: (drawer.Dot.X + bearingX).Floor(),
|
||||||
|
Y: (drawer.Dot.Y - ascentAbsFixed).Floor(),
|
||||||
|
}
|
||||||
|
|
||||||
|
gBotRight := image.Point{
|
||||||
|
X: (drawer.Dot.X + gWidth).Ceil(),
|
||||||
|
Y: (drawer.Dot.Y + descentAbsFixed).Ceil(),
|
||||||
|
}
|
||||||
|
|
||||||
atlas.Glyphs[g] = FontAtlasGlyph{
|
atlas.Glyphs[g] = FontAtlasGlyph{
|
||||||
U: float32((drawer.Dot.X).Floor()),
|
U: float32(gTopLeft.X) - 1,
|
||||||
V: (atlasSizeYF32 - float32((drawer.Dot.Y).Ceil())),
|
V: float32(atlasSizeY - gBotRight.Y),
|
||||||
// U: float32((drawer.Dot.X).Floor()) / atlasSizeXF32,
|
SizeU: float32(gBotRight.X - gTopLeft.X),
|
||||||
// V: (atlasSizeYF32 - float32((drawer.Dot.Y).Ceil())) / atlasSizeYF32,
|
SizeV: float32(gBotRight.Y - gTopLeft.Y),
|
||||||
|
|
||||||
Ascent: float32(ascent.Ceil()),
|
Ascent: float32(ascentAbsFixed.Ceil()),
|
||||||
Descent: float32(descent.Ceil()),
|
Descent: float32(descentAbsFixed.Ceil()),
|
||||||
BearingX: float32(bearingX.Ceil()),
|
BearingX: float32(bearingX.Ceil()),
|
||||||
}
|
}
|
||||||
|
|
||||||
//Get glyph to draw but undo any applied descent so that the glyph is drawn sitting on the line exactly.
|
imgRect, mask, maskp, gAdvance, _ := face.Glyph(drawer.Dot, g)
|
||||||
//Bearing will be applied correctly but descent will be the responsibility of the positioning code
|
if gAdvance == 0 {
|
||||||
imgRect, mask, maskp, _, _ := face.Glyph(drawer.Dot, g)
|
fmt.Printf("Got advance of %s for char with code 0x%04x\n", gAdvance.String(), g)
|
||||||
if imgRect.Max.Y > drawer.Dot.Y.Ceil() {
|
continue
|
||||||
diff := imgRect.Max.Y - drawer.Dot.Y.Ceil()
|
|
||||||
imgRect.Min.Y -= diff
|
|
||||||
imgRect.Max.Y -= diff
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if drawVerticalLines {
|
if drawBoundingBoxes {
|
||||||
rectCopy := imgRect
|
|
||||||
rectCopy.Min.Y = 0
|
rect := image.Rectangle{
|
||||||
rectCopy.Max.Y = drawer.Dst.Bounds().Max.Y
|
Min: gTopLeft,
|
||||||
rectCopy.Max.X = rectCopy.Min.X + 1
|
Max: gBotRight,
|
||||||
oldPos := drawer.Dot
|
}
|
||||||
drawer.Dot.Y = 0
|
drawRectOutline(atlas.Img, rect, color.NRGBA{B: 255, A: 128})
|
||||||
// fmt.Printf("Drawing with maskP %s\n", maskp.String())
|
|
||||||
draw.Draw(drawer.Dst, rectCopy, image.NewUniform(color.NRGBA{G: 255, A: 255}), image.Point{}, draw.Over)
|
|
||||||
drawer.Dot = oldPos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw glyph and advance dot
|
//Draw glyph and advance dot
|
||||||
draw.DrawMask(drawer.Dst, imgRect, drawer.Src, image.Point{}, mask, maskp, draw.Over)
|
draw.DrawMask(drawer.Dst, imgRect, drawer.Src, image.Point{}, mask, maskp, draw.Over)
|
||||||
drawer.Dot.X += fixed.I(atlas.Advance) + charPaddingXFixed
|
drawer.Dot.X += gWidth + charPaddingXFixed
|
||||||
|
|
||||||
charsOnLine++
|
charsOnLine++
|
||||||
if charsOnLine == charsPerLine {
|
if charsOnLine == charsPerLine || currGlyphCount == len(glyphs)-1 {
|
||||||
|
|
||||||
if drawHorizontalLines {
|
|
||||||
rectCopy := imgRect
|
|
||||||
rectCopy.Min.X = 0
|
|
||||||
rectCopy.Max.X = drawer.Dst.Bounds().Max.X
|
|
||||||
|
|
||||||
// rectCopy.Min.Y += (lineHeightFixed + charPaddingYFixed).Floor() * 1
|
|
||||||
rectCopy.Max.Y = rectCopy.Min.Y + 1
|
|
||||||
|
|
||||||
oldPos := drawer.Dot
|
|
||||||
drawer.Dot.X = 0
|
|
||||||
draw.Draw(drawer.Dst, rectCopy, image.NewUniform(color.NRGBA{G: 255, A: 255}), image.Point{}, draw.Over)
|
|
||||||
drawer.Dot = oldPos
|
|
||||||
|
|
||||||
drawVerticalLines = false
|
|
||||||
}
|
|
||||||
|
|
||||||
charsOnLine = 0
|
charsOnLine = 0
|
||||||
drawer.Dot.X = fixed.I(atlas.Advance) + charPaddingXFixed
|
drawer.Dot.X = fixed.I(atlas.Advance) + charPaddingXFixed
|
||||||
@ -220,6 +208,82 @@ func NewFontAtlasFromFont(f *truetype.Font, face font.Face, pointSize uint) (*Fo
|
|||||||
return atlas, nil
|
return atlas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func drawRectOutline(img *image.RGBA, rect image.Rectangle, color color.NRGBA) {
|
||||||
|
|
||||||
|
rowPixCount := img.Stride / 4
|
||||||
|
|
||||||
|
topLeft := img.PixOffset(rect.Min.X, rect.Min.Y)
|
||||||
|
botRight := img.PixOffset(rect.Max.X, rect.Max.Y)
|
||||||
|
|
||||||
|
for i := topLeft; i <= botRight; i += 4 {
|
||||||
|
|
||||||
|
pixel := i / 4
|
||||||
|
y := pixel / rowPixCount
|
||||||
|
x := pixel - y*rowPixCount
|
||||||
|
|
||||||
|
if x >= rect.Min.X && x <= rect.Max.X && y >= rect.Min.Y && y <= rect.Max.Y {
|
||||||
|
if x == rect.Min.X || x == rect.Max.X || y == rect.Min.Y || y == rect.Max.Y {
|
||||||
|
img.Pix[i+3] = color.A
|
||||||
|
img.Pix[i+2] = color.B
|
||||||
|
img.Pix[i+1] = color.G
|
||||||
|
img.Pix[i+0] = color.R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DrawRect(img *image.RGBA, rect image.Rectangle, color color.NRGBA) {
|
||||||
|
|
||||||
|
rowPixCount := img.Stride / 4
|
||||||
|
|
||||||
|
topLeft := img.PixOffset(rect.Min.X, rect.Min.Y)
|
||||||
|
botRight := img.PixOffset(rect.Max.X, rect.Max.Y)
|
||||||
|
|
||||||
|
//Draw top line
|
||||||
|
for i := topLeft; i <= botRight; i += 4 {
|
||||||
|
|
||||||
|
pixel := i / 4
|
||||||
|
y := pixel / rowPixCount
|
||||||
|
x := pixel - y*rowPixCount
|
||||||
|
|
||||||
|
if x >= rect.Min.X && x <= rect.Max.X && y >= rect.Min.Y && y <= rect.Max.Y {
|
||||||
|
img.Pix[i+3] = color.A
|
||||||
|
img.Pix[i+2] = color.B
|
||||||
|
img.Pix[i+1] = color.G
|
||||||
|
img.Pix[i+0] = color.R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DrawVerticalLine(img *image.RGBA, posX int, color color.NRGBA) {
|
||||||
|
|
||||||
|
rowLength := img.Stride
|
||||||
|
start := img.PixOffset(posX, 0)
|
||||||
|
|
||||||
|
for i := start; i < len(img.Pix); i += rowLength {
|
||||||
|
|
||||||
|
img.Pix[i+3] = color.A
|
||||||
|
img.Pix[i+2] = color.B
|
||||||
|
img.Pix[i+1] = color.G
|
||||||
|
img.Pix[i+0] = color.R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DrawHorizontalLine(img *image.RGBA, posY int, color color.NRGBA) {
|
||||||
|
|
||||||
|
rowLength := img.Stride
|
||||||
|
start := img.PixOffset(0, posY)
|
||||||
|
|
||||||
|
//Horizontal line
|
||||||
|
for i := start; i < start+rowLength; i += 4 {
|
||||||
|
|
||||||
|
img.Pix[i+3] = color.A
|
||||||
|
img.Pix[i+2] = color.B
|
||||||
|
img.Pix[i+1] = color.G
|
||||||
|
img.Pix[i+0] = color.R
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func SaveImgToPNG(img image.Image, file string) error {
|
func SaveImgToPNG(img image.Image, file string) error {
|
||||||
|
|
||||||
outFile, err := os.Create(file)
|
outFile, err := os.Create(file)
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package glyphs
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"math"
|
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/bloeys/gglm/gglm"
|
"github.com/bloeys/gglm/gglm"
|
||||||
@ -17,7 +16,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
MaxGlyphsPerBatch = 16384
|
MaxGlyphsPerBatch = 16384
|
||||||
|
|
||||||
floatsPerGlyph = 11
|
floatsPerGlyph = 13
|
||||||
invalidRune = unicode.ReplacementChar
|
invalidRune = unicode.ReplacementChar
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -69,7 +68,7 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
pos := screenPos.Clone()
|
pos := screenPos.Clone()
|
||||||
advanceF32 := float32(gr.Atlas.Advance)
|
advanceF32 := float32(gr.Atlas.Advance)
|
||||||
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
lineHeightF32 := float32(gr.Atlas.LineHeight)
|
||||||
scale := gglm.NewVec2(advanceF32, lineHeightF32)
|
// scale := gglm.NewVec2(advanceF32, lineHeightF32)
|
||||||
|
|
||||||
buffIndex := gr.GlyphCount * floatsPerGlyph
|
buffIndex := gr.GlyphCount * floatsPerGlyph
|
||||||
|
|
||||||
@ -122,28 +121,37 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
//The uvs coming in make it so that glyphs are sitting on top of the baseline (no descent) and with horizontal bearing applied.
|
//The uvs coming in make it so that glyphs are sitting on top of the baseline (no descent) and with horizontal bearing applied.
|
||||||
//So to position correctly we move them down by the descent amount.
|
//So to position correctly we move them down by the descent amount.
|
||||||
drawPos := *pos
|
drawPos := *pos
|
||||||
drawPos.SetX(drawPos.X())
|
drawPos.SetX(drawPos.X() + g.BearingX)
|
||||||
drawPos.SetY(drawPos.Y() - g.Descent)
|
drawPos.SetY(drawPos.Y() - g.Descent)
|
||||||
|
|
||||||
//Add the glyph information to the vbo
|
//Add the glyph information to the vbo
|
||||||
//UV
|
//UV
|
||||||
gr.GlyphVBO[buffIndex+0] = g.U
|
gr.GlyphVBO[buffIndex+0] = g.U
|
||||||
gr.GlyphVBO[buffIndex+1] = g.V
|
gr.GlyphVBO[buffIndex+1] = g.V
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
|
//UVSize
|
||||||
|
gr.GlyphVBO[buffIndex+0] = g.SizeU
|
||||||
|
gr.GlyphVBO[buffIndex+1] = g.SizeV
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
//Color
|
//Color
|
||||||
gr.GlyphVBO[buffIndex+2] = color.R()
|
gr.GlyphVBO[buffIndex+0] = color.R()
|
||||||
gr.GlyphVBO[buffIndex+3] = color.G()
|
gr.GlyphVBO[buffIndex+1] = color.G()
|
||||||
gr.GlyphVBO[buffIndex+4] = color.B()
|
gr.GlyphVBO[buffIndex+2] = color.B()
|
||||||
gr.GlyphVBO[buffIndex+5] = color.A()
|
gr.GlyphVBO[buffIndex+3] = color.A()
|
||||||
|
buffIndex += 4
|
||||||
|
|
||||||
//Model Pos
|
//Model Pos
|
||||||
gr.GlyphVBO[buffIndex+6] = drawPos.X()
|
gr.GlyphVBO[buffIndex+0] = drawPos.X()
|
||||||
gr.GlyphVBO[buffIndex+7] = drawPos.Y()
|
gr.GlyphVBO[buffIndex+1] = drawPos.Y()
|
||||||
gr.GlyphVBO[buffIndex+8] = drawPos.Z()
|
gr.GlyphVBO[buffIndex+2] = drawPos.Z()
|
||||||
|
buffIndex += 3
|
||||||
|
|
||||||
//Model Scale
|
//Model Scale
|
||||||
gr.GlyphVBO[buffIndex+9] = scale.X()
|
gr.GlyphVBO[buffIndex+0] = g.SizeU
|
||||||
gr.GlyphVBO[buffIndex+10] = scale.Y()
|
gr.GlyphVBO[buffIndex+1] = g.SizeV
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
gr.GlyphCount++
|
gr.GlyphCount++
|
||||||
pos.AddX(advanceF32)
|
pos.AddX(advanceF32)
|
||||||
@ -152,8 +160,6 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
if gr.GlyphCount == MaxGlyphsPerBatch {
|
if gr.GlyphCount == MaxGlyphsPerBatch {
|
||||||
gr.Draw()
|
gr.Draw()
|
||||||
buffIndex = 0
|
buffIndex = 0
|
||||||
} else {
|
|
||||||
buffIndex += floatsPerGlyph
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevRune = r
|
prevRune = r
|
||||||
@ -192,28 +198,37 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
//The uvs coming in make it so that glyphs are sitting on top of the baseline (no descent) and with horizontal bearing applied.
|
//The uvs coming in make it so that glyphs are sitting on top of the baseline (no descent) and with horizontal bearing applied.
|
||||||
//So to position correctly we move them down by the descent amount.
|
//So to position correctly we move them down by the descent amount.
|
||||||
drawPos := *pos
|
drawPos := *pos
|
||||||
drawPos.SetX(drawPos.X())
|
drawPos.SetX(drawPos.X() + g.BearingX)
|
||||||
drawPos.SetY(drawPos.Y() - g.Descent)
|
drawPos.SetY(drawPos.Y() - g.Descent)
|
||||||
|
|
||||||
//Add the glyph information to the vbo
|
//Add the glyph information to the vbo
|
||||||
//UV
|
//UV
|
||||||
gr.GlyphVBO[buffIndex+0] = g.U
|
gr.GlyphVBO[buffIndex+0] = g.U
|
||||||
gr.GlyphVBO[buffIndex+1] = g.V
|
gr.GlyphVBO[buffIndex+1] = g.V
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
|
//UVSize
|
||||||
|
gr.GlyphVBO[buffIndex+0] = g.SizeU
|
||||||
|
gr.GlyphVBO[buffIndex+1] = g.SizeV
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
//Color
|
//Color
|
||||||
gr.GlyphVBO[buffIndex+2] = color.R()
|
gr.GlyphVBO[buffIndex+0] = color.R()
|
||||||
gr.GlyphVBO[buffIndex+3] = color.G()
|
gr.GlyphVBO[buffIndex+1] = color.G()
|
||||||
gr.GlyphVBO[buffIndex+4] = color.B()
|
gr.GlyphVBO[buffIndex+2] = color.B()
|
||||||
gr.GlyphVBO[buffIndex+5] = color.A()
|
gr.GlyphVBO[buffIndex+3] = color.A()
|
||||||
|
buffIndex += 4
|
||||||
|
|
||||||
//Model Pos
|
//Model Pos
|
||||||
gr.GlyphVBO[buffIndex+6] = roundF32(drawPos.X())
|
gr.GlyphVBO[buffIndex+0] = drawPos.X()
|
||||||
gr.GlyphVBO[buffIndex+7] = roundF32(drawPos.Y())
|
gr.GlyphVBO[buffIndex+1] = drawPos.Y()
|
||||||
gr.GlyphVBO[buffIndex+8] = drawPos.Z()
|
gr.GlyphVBO[buffIndex+2] = drawPos.Z()
|
||||||
|
buffIndex += 3
|
||||||
|
|
||||||
//Model Scale
|
//Model Scale
|
||||||
gr.GlyphVBO[buffIndex+9] = scale.X()
|
gr.GlyphVBO[buffIndex+0] = g.SizeU
|
||||||
gr.GlyphVBO[buffIndex+10] = scale.Y()
|
gr.GlyphVBO[buffIndex+1] = g.SizeV
|
||||||
|
buffIndex += 2
|
||||||
|
|
||||||
gr.GlyphCount++
|
gr.GlyphCount++
|
||||||
pos.AddX(advanceF32)
|
pos.AddX(advanceF32)
|
||||||
@ -222,8 +237,6 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
if gr.GlyphCount == MaxGlyphsPerBatch {
|
if gr.GlyphCount == MaxGlyphsPerBatch {
|
||||||
gr.Draw()
|
gr.Draw()
|
||||||
buffIndex = 0
|
buffIndex = 0
|
||||||
} else {
|
|
||||||
buffIndex += floatsPerGlyph
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevRune = r
|
prevRune = r
|
||||||
@ -450,7 +463,7 @@ func (gr *GlyphRend) updateFontAtlasTexture() error {
|
|||||||
|
|
||||||
//Update material
|
//Update material
|
||||||
gr.GlyphMat.DiffuseTex = gr.AtlasTex.TexID
|
gr.GlyphMat.DiffuseTex = gr.AtlasTex.TexID
|
||||||
gr.GlyphMat.SetUnifVec2("sizeUV", &gr.Atlas.SizeUV)
|
// gr.GlyphMat.SetUnifVec2("sizeUV", &gr.Atlas.SizeUV)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -527,6 +540,7 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s
|
|||||||
|
|
||||||
gr.InstancedBuf.SetLayout(
|
gr.InstancedBuf.SetLayout(
|
||||||
buffers.Element{ElementType: buffers.DataTypeVec2}, //UV0
|
buffers.Element{ElementType: buffers.DataTypeVec2}, //UV0
|
||||||
|
buffers.Element{ElementType: buffers.DataTypeVec2}, //UVSize
|
||||||
buffers.Element{ElementType: buffers.DataTypeVec4}, //Color
|
buffers.Element{ElementType: buffers.DataTypeVec4}, //Color
|
||||||
buffers.Element{ElementType: buffers.DataTypeVec3}, //ModelPos
|
buffers.Element{ElementType: buffers.DataTypeVec3}, //ModelPos
|
||||||
buffers.Element{ElementType: buffers.DataTypeVec2}, //ModelScale
|
buffers.Element{ElementType: buffers.DataTypeVec2}, //ModelScale
|
||||||
@ -542,21 +556,26 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s
|
|||||||
gl.VertexAttribPointer(1, uvEle.ElementType.CompCount(), uvEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(uvEle.Offset))
|
gl.VertexAttribPointer(1, uvEle.ElementType.CompCount(), uvEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(uvEle.Offset))
|
||||||
gl.VertexAttribDivisor(1, 1)
|
gl.VertexAttribDivisor(1, 1)
|
||||||
|
|
||||||
colorEle := layout[1]
|
uvSize := layout[1]
|
||||||
gl.EnableVertexAttribArray(2)
|
gl.EnableVertexAttribArray(2)
|
||||||
gl.VertexAttribPointer(2, colorEle.ElementType.CompCount(), colorEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(colorEle.Offset))
|
gl.VertexAttribPointer(2, uvSize.ElementType.CompCount(), uvSize.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(uvSize.Offset))
|
||||||
gl.VertexAttribDivisor(2, 1)
|
gl.VertexAttribDivisor(2, 1)
|
||||||
|
|
||||||
posEle := layout[2]
|
colorEle := layout[2]
|
||||||
gl.EnableVertexAttribArray(3)
|
gl.EnableVertexAttribArray(3)
|
||||||
gl.VertexAttribPointer(3, posEle.ElementType.CompCount(), posEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(posEle.Offset))
|
gl.VertexAttribPointer(3, colorEle.ElementType.CompCount(), colorEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(colorEle.Offset))
|
||||||
gl.VertexAttribDivisor(3, 1)
|
gl.VertexAttribDivisor(3, 1)
|
||||||
|
|
||||||
scaleEle := layout[3]
|
posEle := layout[3]
|
||||||
gl.EnableVertexAttribArray(4)
|
gl.EnableVertexAttribArray(4)
|
||||||
gl.VertexAttribPointer(4, scaleEle.ElementType.CompCount(), scaleEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(scaleEle.Offset))
|
gl.VertexAttribPointer(4, posEle.ElementType.CompCount(), posEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(posEle.Offset))
|
||||||
gl.VertexAttribDivisor(4, 1)
|
gl.VertexAttribDivisor(4, 1)
|
||||||
|
|
||||||
|
scaleEle := layout[4]
|
||||||
|
gl.EnableVertexAttribArray(5)
|
||||||
|
gl.VertexAttribPointer(5, scaleEle.ElementType.CompCount(), scaleEle.ElementType.GLType(), false, gr.InstancedBuf.Stride, gl.PtrOffset(scaleEle.Offset))
|
||||||
|
gl.VertexAttribDivisor(5, 1)
|
||||||
|
|
||||||
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
|
||||||
gr.InstancedBuf.UnBind()
|
gr.InstancedBuf.UnBind()
|
||||||
|
|
||||||
@ -572,7 +591,3 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s
|
|||||||
|
|
||||||
return gr, nil
|
return gr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func roundF32(x float32) float32 {
|
|
||||||
return float32(math.Round(float64(x)))
|
|
||||||
}
|
|
||||||
|
|||||||
5
imgui.ini
Executable file
5
imgui.ini
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
[Window][Debug##Default]
|
||||||
|
Pos=814,53
|
||||||
|
Size=405,63
|
||||||
|
Collapsed=0
|
||||||
|
|
||||||
14
main.go
14
main.go
@ -11,8 +11,10 @@ import (
|
|||||||
"github.com/bloeys/nmage/meshes"
|
"github.com/bloeys/nmage/meshes"
|
||||||
"github.com/bloeys/nmage/renderer/rend3dgl"
|
"github.com/bloeys/nmage/renderer/rend3dgl"
|
||||||
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
nmageimgui "github.com/bloeys/nmage/ui/imgui"
|
||||||
|
"github.com/bloeys/nterm/assert"
|
||||||
"github.com/bloeys/nterm/glyphs"
|
"github.com/bloeys/nterm/glyphs"
|
||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
|
"github.com/inkyblackness/imgui-go/v4"
|
||||||
"github.com/veandco/go-sdl2/sdl"
|
"github.com/veandco/go-sdl2/sdl"
|
||||||
"golang.org/x/image/font"
|
"golang.org/x/image/font"
|
||||||
)
|
)
|
||||||
@ -107,6 +109,7 @@ func (p *program) Init() {
|
|||||||
p.handleWindowResize()
|
p.handleWindowResize()
|
||||||
|
|
||||||
// runs := p.GlyphRend.GetTextRuns("hello there يا friend. أسمي عمر wow")
|
// runs := p.GlyphRend.GetTextRuns("hello there يا friend. أسمي عمر wow")
|
||||||
|
// runs := p.GlyphRend.GetTextRuns("hello there my friend!")
|
||||||
// fmt.Printf("%+v\n", runs)
|
// fmt.Printf("%+v\n", runs)
|
||||||
// for _, r := range runs {
|
// for _, r := range runs {
|
||||||
// fmt.Printf("%s;\n", string(r))
|
// fmt.Printf("%s;\n", string(r))
|
||||||
@ -164,7 +167,14 @@ func (p *program) Update() {
|
|||||||
if input.KeyClicked(sdl.K_SPACE) {
|
if input.KeyClicked(sdl.K_SPACE) {
|
||||||
p.shouldDrawGrid = !p.shouldDrawGrid
|
p.shouldDrawGrid = !p.shouldDrawGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imgui.InputText("", &textToShow)
|
||||||
|
if len(textToShow) > 0 {
|
||||||
|
assert.T(len(textToShow) == len(p.GlyphRend.GetTextRuns(textToShow)[0]), "??")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var textToShow = "Hello there my friend"
|
||||||
|
|
||||||
var xOff float32 = 0
|
var xOff float32 = 0
|
||||||
var yOff float32 = 0
|
var yOff float32 = 0
|
||||||
@ -198,8 +208,10 @@ func (p *program) Render() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
textColor := gglm.NewVec4(r, g, b, 1)
|
textColor := gglm.NewVec4(r, g, b, 1)
|
||||||
|
str := textToShow
|
||||||
// str := "مرحبا بك my friend"
|
// str := "مرحبا بك my friend"
|
||||||
str := " hello there يا friend. سمي عمر wow"
|
// str := "my, friend"
|
||||||
|
// str := " hello there يا friend. سمي عمر wow"
|
||||||
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ\nمرحبا بك"
|
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ\nمرحبا بك"
|
||||||
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ"
|
// str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
|||||||
@ -6,9 +6,10 @@ layout(location=0) in vec3 aVertPos;
|
|||||||
|
|
||||||
//Instanced
|
//Instanced
|
||||||
layout(location=1) in vec2 aUV0;
|
layout(location=1) in vec2 aUV0;
|
||||||
layout(location=2) in vec4 aVertColor;
|
layout(location=2) in vec2 aUVSize;
|
||||||
layout(location=3) in vec3 aModelPos;
|
layout(location=3) in vec4 aVertColor;
|
||||||
layout(location=4) in vec2 aModelScale;
|
layout(location=4) in vec3 aModelPos;
|
||||||
|
layout(location=5) in vec2 aModelScale;
|
||||||
|
|
||||||
out vec2 v2fUV0;
|
out vec2 v2fUV0;
|
||||||
out vec4 v2fColor;
|
out vec4 v2fColor;
|
||||||
@ -16,7 +17,6 @@ out vec3 v2fFragPos;
|
|||||||
|
|
||||||
uniform mat4 projViewMat;
|
uniform mat4 projViewMat;
|
||||||
uniform vec2 modelSize;
|
uniform vec2 modelSize;
|
||||||
uniform vec2 sizeUV;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
@ -27,7 +27,7 @@ void main()
|
|||||||
aModelPos.x, aModelPos.y, aModelPos.z, 1.0
|
aModelPos.x, aModelPos.y, aModelPos.z, 1.0
|
||||||
);
|
);
|
||||||
|
|
||||||
v2fUV0 = aUV0 + aVertPos.xy * sizeUV;
|
v2fUV0 = aUV0 + aVertPos.xy * aUVSize;
|
||||||
v2fColor = aVertColor;
|
v2fColor = aVertColor;
|
||||||
|
|
||||||
gl_Position = projViewMat * modelMat * vec4(aVertPos, 1.0);
|
gl_Position = projViewMat * modelMat * vec4(aVertPos, 1.0);
|
||||||
|
|||||||
Reference in New Issue
Block a user