mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 06:28:20 +00:00
Don't allocate when drawing by reusing glyp rend buffer
This commit is contained in:
@ -13,6 +13,9 @@ import (
|
|||||||
"github.com/golang/freetype/truetype"
|
"github.com/golang/freetype/truetype"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const floatsPerGlyph = 11
|
||||||
|
const maxGlyphsPerBatch = 16384
|
||||||
|
|
||||||
type GlyphRend struct {
|
type GlyphRend struct {
|
||||||
Atlas *FontAtlas
|
Atlas *FontAtlas
|
||||||
AtlasTex *assets.Texture
|
AtlasTex *assets.Texture
|
||||||
@ -22,7 +25,13 @@ type GlyphRend struct {
|
|||||||
GlyphMat *materials.Material
|
GlyphMat *materials.Material
|
||||||
|
|
||||||
GlyphCount int32
|
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
|
ScreenWidth int32
|
||||||
ScreenHeight int32
|
ScreenHeight int32
|
||||||
@ -43,13 +52,11 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
|
|
||||||
//Prepass to pre-allocate the buffer
|
//Prepass to pre-allocate the buffer
|
||||||
rs := []rune(text)
|
rs := []rune(text)
|
||||||
const floatsPerGlyph = 18
|
|
||||||
|
|
||||||
// startPos := screenPos.Clone()
|
// startPos := screenPos.Clone()
|
||||||
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)
|
||||||
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++ {
|
for i := 0; i < len(rs); i++ {
|
||||||
|
|
||||||
r := rs[i]
|
r := rs[i]
|
||||||
@ -62,7 +69,6 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
pos.SetX(pos.X() + advanceF32)
|
pos.SetX(pos.X() + advanceF32)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
gr.GlyphCount++
|
|
||||||
|
|
||||||
scale := gglm.NewVec2(advanceF32, lineHeightF32)
|
scale := gglm.NewVec2(advanceF32, lineHeightF32)
|
||||||
|
|
||||||
@ -73,17 +79,36 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
|
|||||||
drawPos.SetX(drawPos.X())
|
drawPos.SetX(drawPos.X())
|
||||||
drawPos.SetY(drawPos.Y() - g.Descent)
|
drawPos.SetY(drawPos.Y() - g.Descent)
|
||||||
|
|
||||||
instancedData = append(instancedData, []float32{
|
//Add the glyph information to the vbo
|
||||||
g.U, g.V,
|
startIndex := gr.GlyphCount * floatsPerGlyph
|
||||||
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
|
|
||||||
}...)
|
|
||||||
|
|
||||||
|
//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)
|
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() {
|
func (gr *GlyphRend) Draw() {
|
||||||
@ -92,14 +117,12 @@ func (gr *GlyphRend) Draw() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
gr.InstancedBuf.SetData(gr.GlyphVBO)
|
gr.InstancedBuf.SetData(gr.GlyphVBO[:gr.GlyphCount*floatsPerGlyph])
|
||||||
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), gr.GlyphCount)
|
||||||
|
|
||||||
gr.GlyphCount = 0
|
gr.GlyphCount = 0
|
||||||
gr.GlyphVBO = []float32{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//SetFace updates the underlying font atlas used by the glyph renderer.
|
//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{
|
gr := &GlyphRend{
|
||||||
GlyphCount: 0,
|
GlyphCount: 0,
|
||||||
GlyphVBO: make([]float32, 0),
|
GlyphVBO: make([]float32, floatsPerGlyph*maxGlyphsPerBatch),
|
||||||
}
|
}
|
||||||
|
|
||||||
//Create glyph mesh
|
//Create glyph mesh
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -4,7 +4,7 @@ go 1.18
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bloeys/gglm v0.41.10
|
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/go-gl/gl v0.0.0-20211025173605-bda47ffaa784
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
|
||||||
github.com/veandco/go-sdl2 v0.4.10
|
github.com/veandco/go-sdl2 v0.4.10
|
||||||
|
|||||||
2
go.sum
2
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/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 h1:LeMR6NI+yMqxAZecdz7lOT1re4CWAVd1wDeJFK77+pI=
|
||||||
github.com/bloeys/nmage v0.12.12/go.mod h1:chDDenktiDvAG4BoFYNq1n8nACpbQ6/RFuCgCGmDxh4=
|
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 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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=
|
github.com/go-gl/gl v0.0.0-20211025173605-bda47ffaa784 h1:1Zi56D0LNfvkzM+BdoxKryvUEdyWO7LP8oRT+oSYJW0=
|
||||||
|
|||||||
39
main.go
39
main.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"github.com/bloeys/gglm/gglm"
|
"github.com/bloeys/gglm/gglm"
|
||||||
"github.com/bloeys/nmage/engine"
|
"github.com/bloeys/nmage/engine"
|
||||||
@ -9,6 +10,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/go-gl/gl/v4.1-core/gl"
|
"github.com/go-gl/gl/v4.1-core/gl"
|
||||||
@ -154,20 +156,47 @@ func (p *program) Update() {
|
|||||||
if input.KeyClicked(sdl.K_SPACE) {
|
if input.KeyClicked(sdl.K_SPACE) {
|
||||||
p.shouldDrawGrid = !p.shouldDrawGrid
|
p.shouldDrawGrid = !p.shouldDrawGrid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println("FPS:", int(timing.GetAvgFPS()), "; Draws per frame:", charsPerFrame/16384)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const charsPerFrame = 100_000
|
||||||
|
|
||||||
var xOff float32 = 0
|
var xOff float32 = 0
|
||||||
var yOff float32 = 0
|
var yOff float32 = 0
|
||||||
|
|
||||||
|
var r = rand.Float32()
|
||||||
|
var g = rand.Float32()
|
||||||
|
var b = rand.Float32()
|
||||||
|
|
||||||
func (p *program) Render() {
|
func (p *program) Render() {
|
||||||
|
|
||||||
|
const colorSpd = 0.005
|
||||||
defer p.GlyphRend.Draw()
|
defer p.GlyphRend.Draw()
|
||||||
|
|
||||||
textColor := gglm.NewVec4(1, 1, 1, 1)
|
r += colorSpd
|
||||||
// p.GlyphRend.DrawTextOpenGL("y", gglm.NewVec3(0+xOff, 0+yOff, 0), textColor)
|
if r > 1 {
|
||||||
// p.GlyphRend.DrawTextOpenGL("A\np-+_; This is", gglm.NewVec3(0.3+xOff, 0.5+yOff, 0), textColor)
|
r = 0
|
||||||
// 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)
|
|
||||||
|
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 {
|
if p.shouldDrawGrid {
|
||||||
p.drawGrid()
|
p.drawGrid()
|
||||||
|
|||||||
Reference in New Issue
Block a user