diff --git a/glyphs/glyphs.go b/glyphs/glyphs.go index 6aa2939..4409a62 100755 --- a/glyphs/glyphs.go +++ b/glyphs/glyphs.go @@ -13,6 +13,9 @@ import ( "github.com/golang/freetype/truetype" ) +const floatsPerGlyph = 11 +const maxGlyphsPerBatch = 16384 + type GlyphRend struct { Atlas *FontAtlas AtlasTex *assets.Texture @@ -22,7 +25,13 @@ type GlyphRend struct { GlyphMat *materials.Material GlyphCount int32 - GlyphVBO []float32 + //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 + //allocated inside the function is fine (Go potentially can't detect what's happening properly). + // + //Luckily slices still work, so for now we will use our slice as an array (no appending) + GlyphVBO []float32 + // GlyphVBO [floatsPerGlyph * maxGlyphsPerBatch]float32 ScreenWidth int32 ScreenHeight int32 @@ -43,13 +52,11 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color //Prepass to pre-allocate the buffer rs := []rune(text) - const floatsPerGlyph = 18 // startPos := screenPos.Clone() pos := screenPos.Clone() advanceF32 := float32(gr.Atlas.Advance) lineHeightF32 := float32(gr.Atlas.LineHeight) - instancedData := make([]float32, 0, len(rs)*floatsPerGlyph) //This a larger approximation than needed because we don't count spaces etc for i := 0; i < len(rs); i++ { r := rs[i] @@ -62,7 +69,6 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color pos.SetX(pos.X() + advanceF32) continue } - gr.GlyphCount++ scale := gglm.NewVec2(advanceF32, lineHeightF32) @@ -73,17 +79,36 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color drawPos.SetX(drawPos.X()) drawPos.SetY(drawPos.Y() - g.Descent) - instancedData = append(instancedData, []float32{ - g.U, g.V, - color.R(), color.G(), color.B(), color.A(), //Color - roundF32(drawPos.X()), roundF32(drawPos.Y()), drawPos.Z(), //Model pos - scale.X(), scale.Y(), //Model scale - }...) + //Add the glyph information to the vbo + startIndex := gr.GlyphCount * floatsPerGlyph + //UV + gr.GlyphVBO[startIndex+0] = g.U + gr.GlyphVBO[startIndex+1] = g.V + + //Color + gr.GlyphVBO[startIndex+2] = color.R() + gr.GlyphVBO[startIndex+3] = color.G() + gr.GlyphVBO[startIndex+4] = color.B() + gr.GlyphVBO[startIndex+5] = color.A() + + //Model Pos + gr.GlyphVBO[startIndex+6] = roundF32(drawPos.X()) + gr.GlyphVBO[startIndex+7] = roundF32(drawPos.Y()) + gr.GlyphVBO[startIndex+8] = drawPos.Z() + + //Model Scale + gr.GlyphVBO[startIndex+9] = scale.X() + gr.GlyphVBO[startIndex+10] = scale.Y() + + gr.GlyphCount++ pos.SetX(pos.X() + advanceF32) - } - gr.GlyphVBO = append(gr.GlyphVBO, instancedData...) + //If we fill the buffer we issue a draw call + if gr.GlyphCount == maxGlyphsPerBatch { + gr.Draw() + } + } } func (gr *GlyphRend) Draw() { @@ -92,14 +117,12 @@ func (gr *GlyphRend) Draw() { return } - gr.InstancedBuf.SetData(gr.GlyphVBO) + gr.InstancedBuf.SetData(gr.GlyphVBO[:gr.GlyphCount*floatsPerGlyph]) gr.InstancedBuf.Bind() gr.GlyphMat.Bind() gl.DrawElementsInstanced(gl.TRIANGLES, gr.GlyphMesh.Buf.IndexBufCount, gl.UNSIGNED_INT, gl.PtrOffset(0), gr.GlyphCount) - gr.GlyphCount = 0 - gr.GlyphVBO = []float32{} } //SetFace updates the underlying font atlas used by the glyph renderer. @@ -178,7 +201,7 @@ func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, s gr := &GlyphRend{ GlyphCount: 0, - GlyphVBO: make([]float32, 0), + GlyphVBO: make([]float32, floatsPerGlyph*maxGlyphsPerBatch), } //Create glyph mesh diff --git a/go.mod b/go.mod index 33a3c77..a1ee36f 100755 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.18 require ( github.com/bloeys/gglm v0.41.10 - github.com/bloeys/nmage v0.12.12 + github.com/bloeys/nmage v0.12.13 github.com/go-gl/gl v0.0.0-20211025173605-bda47ffaa784 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/veandco/go-sdl2 v0.4.10 diff --git a/go.sum b/go.sum index cd9f657..2570ef8 100755 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/bloeys/gglm v0.41.10 h1:R9FMiI+VQVXAI+vDwCB7z9xqzy5VAR1657u8TQTDNKA= github.com/bloeys/gglm v0.41.10/go.mod h1:qwJQ0WzV191wAMwlGicbfbChbKoSedMk7gFFX6GnyOk= github.com/bloeys/nmage v0.12.12 h1:LeMR6NI+yMqxAZecdz7lOT1re4CWAVd1wDeJFK77+pI= github.com/bloeys/nmage v0.12.12/go.mod h1:chDDenktiDvAG4BoFYNq1n8nACpbQ6/RFuCgCGmDxh4= +github.com/bloeys/nmage v0.12.13 h1:xvoaMAdHNnVif7LCaQkYR7jewXDZa9B1iV7IdG39dgc= +github.com/bloeys/nmage v0.12.13/go.mod h1:chDDenktiDvAG4BoFYNq1n8nACpbQ6/RFuCgCGmDxh4= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-gl/gl v0.0.0-20211025173605-bda47ffaa784 h1:1Zi56D0LNfvkzM+BdoxKryvUEdyWO7LP8oRT+oSYJW0= diff --git a/main.go b/main.go index 58a56f3..e30d0f1 100755 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "math/rand" "github.com/bloeys/gglm/gglm" "github.com/bloeys/nmage/engine" @@ -9,6 +10,7 @@ import ( "github.com/bloeys/nmage/materials" "github.com/bloeys/nmage/meshes" "github.com/bloeys/nmage/renderer/rend3dgl" + "github.com/bloeys/nmage/timing" nmageimgui "github.com/bloeys/nmage/ui/imgui" "github.com/bloeys/nterm/glyphs" "github.com/go-gl/gl/v4.1-core/gl" @@ -154,20 +156,47 @@ func (p *program) Update() { if input.KeyClicked(sdl.K_SPACE) { p.shouldDrawGrid = !p.shouldDrawGrid } + + fmt.Println("FPS:", int(timing.GetAvgFPS()), "; Draws per frame:", charsPerFrame/16384) } +const charsPerFrame = 100_000 + var xOff float32 = 0 var yOff float32 = 0 +var r = rand.Float32() +var g = rand.Float32() +var b = rand.Float32() + func (p *program) Render() { + const colorSpd = 0.005 defer p.GlyphRend.Draw() - textColor := gglm.NewVec4(1, 1, 1, 1) - // p.GlyphRend.DrawTextOpenGL("y", gglm.NewVec3(0+xOff, 0+yOff, 0), textColor) - // p.GlyphRend.DrawTextOpenGL("A\np-+_; This is", gglm.NewVec3(0.3+xOff, 0.5+yOff, 0), textColor) - // p.GlyphRend.DrawTextOpenGLAbs("Hello there, friend.\nABCDEFGHIJKLMNOPQRSTUVWXYZ", gglm.NewVec3(0, 0, 0), textColor) - p.GlyphRend.DrawTextOpenGLAbs(" ijojo\n\n Hello there, friend|. pq?\n ABCDEFGHIJKLMNOPQRSTUVWXYZ", gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor) + r += colorSpd + if r > 1 { + r = 0 + } + + g += colorSpd + if g > 1 { + g = 0 + } + + b += colorSpd + if b > 1 { + b = 0 + } + + textColor := gglm.NewVec4(r, g, b, 1) + + str := " ijojo\n\n Hello there, friend|. pq?\n ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 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) + } if p.shouldDrawGrid { p.drawGrid()