mirror of
https://github.com/bloeys/nterm.git
synced 2025-12-29 06:28:20 +00:00
Handle tabs
This commit is contained in:
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,8 +208,9 @@ func (gr *GlyphRend) SetScreenSize(screenWidth, screenHeight int32) {
|
|||||||
func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, screenHeight int32) (*GlyphRend, error) {
|
func NewGlyphRend(fontFile string, fontOptions *truetype.Options, screenWidth, screenHeight int32) (*GlyphRend, error) {
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
21
main.go
21
main.go
@ -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)
|
// p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
|
||||||
|
|
||||||
// strLen := len(str)
|
strLen := len(str)
|
||||||
// for i := 0; i < charsPerFrame/strLen; i++ {
|
const charsPerFrame = 10_000
|
||||||
// p.GlyphRend.DrawTextOpenGLAbs(str, gglm.NewVec3(xOff, float32(p.GlyphRend.Atlas.LineHeight)*5+yOff, 0), textColor)
|
for i := 0; i < charsPerFrame/strLen; i++ {
|
||||||
// }
|
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)
|
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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user