Handle tabs

This commit is contained in:
bloeys
2022-07-04 02:45:59 +04:00
parent c82fd6aac7
commit 0ff7f051f6
2 changed files with 43 additions and 33 deletions

View File

@ -14,7 +14,7 @@ import (
) )
const floatsPerGlyph = 11 const floatsPerGlyph = 11
const maxGlyphsPerBatch = 16384 const MaxGlyphsPerBatch = 16384
type GlyphRend struct { type GlyphRend struct {
Atlas *FontAtlas Atlas *FontAtlas
@ -24,7 +24,7 @@ type GlyphRend struct {
InstancedBuf buffers.Buffer InstancedBuf buffers.Buffer
GlyphMat *materials.Material GlyphMat *materials.Material
GlyphCount int32 GlyphCount uint32
//NOTE: Because of the sad realities (bugs?) of CGO, passing an array in a struct //NOTE: Because of the sad realities (bugs?) of CGO, passing an array in a struct
//to C explodes (Go pointer to Go pointer error) even though passing the same array //to C explodes (Go pointer to Go pointer error) even though passing the same array
//allocated inside the function is fine (Go potentially can't detect what's happening properly). //allocated inside the function is fine (Go potentially can't detect what's happening properly).
@ -35,6 +35,8 @@ type GlyphRend struct {
ScreenWidth int32 ScreenWidth int32
ScreenHeight int32 ScreenHeight int32
SpacesPerTab uint
} }
//DrawTextOpenGLAbs prepares text that will be drawn on the next GlyphRend.Draw call. //DrawTextOpenGLAbs prepares text that will be drawn on the next GlyphRend.Draw call.
@ -57,20 +59,25 @@ 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)
buffIndex := gr.GlyphCount * floatsPerGlyph
for i := 0; i < len(rs); i++ { for i := 0; i < len(rs); i++ {
r := rs[i] r := rs[i]
g := gr.Atlas.Glyphs[r]
if r == '\n' { if r == '\n' {
screenPos.SetY(screenPos.Y() - lineHeightF32) screenPos.SetY(screenPos.Y() - lineHeightF32)
pos = screenPos.Clone() pos = screenPos.Clone()
continue continue
} else if r == ' ' { } else if r == ' ' {
pos.SetX(pos.X() + advanceF32) pos.AddX(advanceF32)
continue
} else if r == '\t' {
pos.AddX(advanceF32 * float32(gr.SpacesPerTab))
continue continue
} }
scale := gglm.NewVec2(advanceF32, lineHeightF32) g := gr.Atlas.Glyphs[r]
//See: https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png //See: https://developer.apple.com/library/archive/documentation/TextFonts/Conceptual/CocoaTextArchitecture/Art/glyph_metrics_2x.png
//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.
@ -80,33 +87,34 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
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
startIndex := gr.GlyphCount * floatsPerGlyph
//UV //UV
gr.GlyphVBO[startIndex+0] = g.U gr.GlyphVBO[buffIndex+0] = g.U
gr.GlyphVBO[startIndex+1] = g.V gr.GlyphVBO[buffIndex+1] = g.V
//Color //Color
gr.GlyphVBO[startIndex+2] = color.R() gr.GlyphVBO[buffIndex+2] = color.R()
gr.GlyphVBO[startIndex+3] = color.G() gr.GlyphVBO[buffIndex+3] = color.G()
gr.GlyphVBO[startIndex+4] = color.B() gr.GlyphVBO[buffIndex+4] = color.B()
gr.GlyphVBO[startIndex+5] = color.A() gr.GlyphVBO[buffIndex+5] = color.A()
//Model Pos //Model Pos
gr.GlyphVBO[startIndex+6] = roundF32(drawPos.X()) gr.GlyphVBO[buffIndex+6] = roundF32(drawPos.X())
gr.GlyphVBO[startIndex+7] = roundF32(drawPos.Y()) gr.GlyphVBO[buffIndex+7] = roundF32(drawPos.Y())
gr.GlyphVBO[startIndex+8] = drawPos.Z() gr.GlyphVBO[buffIndex+8] = drawPos.Z()
//Model Scale //Model Scale
gr.GlyphVBO[startIndex+9] = scale.X() gr.GlyphVBO[buffIndex+9] = scale.X()
gr.GlyphVBO[startIndex+10] = scale.Y() gr.GlyphVBO[buffIndex+10] = scale.Y()
gr.GlyphCount++ gr.GlyphCount++
pos.SetX(pos.X() + advanceF32) pos.AddX(advanceF32)
//If we fill the buffer we issue a draw call //If we fill the buffer we issue a draw call
if gr.GlyphCount == maxGlyphsPerBatch { if gr.GlyphCount == MaxGlyphsPerBatch {
gr.Draw() gr.Draw()
buffIndex = 0
} else {
buffIndex += floatsPerGlyph
} }
} }
} }
@ -121,7 +129,7 @@ func (gr *GlyphRend) Draw() {
gr.InstancedBuf.Bind() gr.InstancedBuf.Bind()
gr.GlyphMat.Bind() gr.GlyphMat.Bind()
gl.DrawElementsInstanced(gl.TRIANGLES, gr.GlyphMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0), gr.GlyphCount) gl.DrawElementsInstanced(gl.TRIANGLES, gr.GlyphMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0), int32(gr.GlyphCount))
gr.GlyphCount = 0 gr.GlyphCount = 0
} }
@ -201,7 +209,8 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s
gr := &GlyphRend{ gr := &GlyphRend{
GlyphCount: 0, GlyphCount: 0,
GlyphVBO: make([]float32, floatsPerGlyph*maxGlyphsPerBatch), GlyphVBO: make([]float32, floatsPerGlyph*MaxGlyphsPerBatch),
SpacesPerTab: 4,
} }
//Create glyph mesh //Create glyph mesh

19
main.go
View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
"math"
"math/rand" "math/rand"
"github.com/bloeys/gglm/gglm" "github.com/bloeys/gglm/gglm"
@ -10,6 +11,7 @@ import (
"github.com/bloeys/nmage/materials" "github.com/bloeys/nmage/materials"
"github.com/bloeys/nmage/meshes" "github.com/bloeys/nmage/meshes"
"github.com/bloeys/nmage/renderer/rend3dgl" "github.com/bloeys/nmage/renderer/rend3dgl"
"github.com/bloeys/nmage/timing"
nmageimgui "github.com/bloeys/nmage/ui/imgui" nmageimgui "github.com/bloeys/nmage/ui/imgui"
"github.com/bloeys/nterm/glyphs" "github.com/bloeys/nterm/glyphs"
"github.com/golang/freetype/truetype" "github.com/golang/freetype/truetype"
@ -164,14 +166,13 @@ var b = rand.Float32()
func (p *program) Render() { func (p *program) Render() {
const colorSpd = 0.005
// const charsPerFrame = 100_000
defer p.GlyphRend.Draw() defer p.GlyphRend.Draw()
if p.shouldDrawGrid { if p.shouldDrawGrid {
p.drawGrid() p.drawGrid()
} }
const colorSpd = 0.005
r += colorSpd r += colorSpd
if r > 1 { if r > 1 {
r = 0 r = 0
@ -188,16 +189,16 @@ func (p *program) Render() {
} }
textColor := gglm.NewVec4(r, g, b, 1) textColor := gglm.NewVec4(r, g, b, 1)
str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFGHIJKLMNOPQRSTUVWXYZ" str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFG\tHIJKLMNOPQRSTUVWXYZ"
p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
// strLen := len(str)
// for i := 0; i < charsPerFrame/strLen; i++ {
// p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor) // p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
// }
// fmt.Println("FPS:", int(timing.GetAvgFPS()), "; Draws per frame:", charsPerFrame/16384) strLen := len(str)
const charsPerFrame = 10_000
for i := 0; i < charsPerFrame/strLen; i++ {
p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
}
p.win.SDLWin.SetTitle(fmt.Sprint("FPS:", int(timing.GetAvgFPS()), "; Draws per frame:", math.Ceil(charsPerFrame/glyphs.MaxGlyphsPerBatch)))
} }
func (p *program) drawGrid() { func (p *program) drawGrid() {