Make TextRun struct to clean GetTextRuns

This commit is contained in:
bloeys
2022-07-08 08:09:12 +04:00
parent 9388bc0c92
commit d8289139d3
2 changed files with 47 additions and 39 deletions

View File

@ -71,44 +71,32 @@ func (gr *GlyphRend) DrawTextOpenGLAbs(text string, screenPos *gglm.Vec3, color
bufIndex := gr.GlyphCount * floatsPerGlyph bufIndex := gr.GlyphCount * floatsPerGlyph
for _, run := range runs { for runIndex := 0; runIndex < len(runs); runIndex++ {
rs := run run := &runs[runIndex]
prevRune := invalidRune prevRune := invalidRune
//TODO: Information on run (like bidi) should come from GetTextRuns. if run.IsLtr {
//Default is left in case we hav a run of neutrals
bidiCat := BidiCategory_L
for _, r := range rs {
if !unicode.Is(unicode.Common, r) {
bidiCat = RuneInfos[r].BidiCat
break
}
}
isLtr := !(bidiCat == BidiCategory_R || bidiCat == BidiCategory_AL || bidiCat == BidiCategory_RLE || bidiCat == BidiCategory_RLO || bidiCat == BidiCategory_RLI || bidiCat == BidiCategory_RLM)
if isLtr { for i := 0; i < len(run.Runes); i++ {
gr.drawRune(run, i, prevRune, screenPos, pos, color, advanceF32, lineHeightF32, &bufIndex)
for i := 0; i < len(rs); i++ { prevRune = run.Runes[i]
gr.drawRune(rs, i, prevRune, screenPos, pos, color, advanceF32, lineHeightF32, &bufIndex, isLtr)
prevRune = rs[i]
} }
} else { } else {
for i := len(rs) - 1; i >= 0; i-- { for i := len(run.Runes) - 1; i >= 0; i-- {
gr.drawRune(rs, i, prevRune, screenPos, pos, color, advanceF32, lineHeightF32, &bufIndex, isLtr) gr.drawRune(run, i, prevRune, screenPos, pos, color, advanceF32, lineHeightF32, &bufIndex)
prevRune = rs[i] prevRune = run.Runes[i]
} }
} }
} }
} }
func (gr *GlyphRend) drawRune(rs []rune, i int, prevRune rune, screenPos, pos *gglm.Vec3, color *gglm.Vec4, advanceF32, lineHeightF32 float32, bufIndex *uint32, isLtr bool) { func (gr *GlyphRend) drawRune(run *TextRun, i int, prevRune rune, screenPos, pos *gglm.Vec3, color *gglm.Vec4, advanceF32, lineHeightF32 float32, bufIndex *uint32) {
r := rs[i] r := run.Runes[i]
if r == '\n' { if r == '\n' {
screenPos.SetY(screenPos.Y() - lineHeightF32) screenPos.SetY(screenPos.Y() - lineHeightF32)
*pos = *screenPos.Clone() *pos = *screenPos.Clone()
@ -125,10 +113,10 @@ func (gr *GlyphRend) drawRune(rs []rune, i int, prevRune rune, screenPos, pos *g
} }
var g FontAtlasGlyph var g FontAtlasGlyph
if isLtr { if run.IsLtr {
if i < len(rs)-1 { if i < len(run.Runes)-1 {
//start or middle of sentence //start or middle of sentence
g = gr.glyphFromRunes(r, prevRune, rs[i+1]) g = gr.glyphFromRunes(r, prevRune, run.Runes[i+1])
} else { } else {
//Last character //Last character
g = gr.glyphFromRunes(r, prevRune, invalidRune) g = gr.glyphFromRunes(r, prevRune, invalidRune)
@ -136,7 +124,7 @@ func (gr *GlyphRend) drawRune(rs []rune, i int, prevRune rune, screenPos, pos *g
} else { } else {
if i > 0 { if i > 0 {
//start or middle of sentence //start or middle of sentence
g = gr.glyphFromRunes(r, rs[i-1], prevRune) g = gr.glyphFromRunes(r, run.Runes[i-1], prevRune)
} else { } else {
//Last character //Last character
g = gr.glyphFromRunes(r, invalidRune, prevRune) g = gr.glyphFromRunes(r, invalidRune, prevRune)
@ -187,16 +175,21 @@ func (gr *GlyphRend) drawRune(rs []rune, i int, prevRune rune, screenPos, pos *g
} }
} }
func (gr *GlyphRend) GetTextRuns(t string) [][]rune { type TextRun struct {
Runes []rune
IsLtr bool
}
//PERF: Might be better to pass a [][]rune buffer to avoid allocating on the heap func (gr *GlyphRend) GetTextRuns(t string) []TextRun {
//PERF: Might be better to pass a []TextRun buffer to avoid allocating on the heap
rs := []rune(t) rs := []rune(t)
if len(rs) == 0 { if len(rs) == 0 {
return nil return nil
} }
runs := make([][]rune, 0, 10) runs := make([]TextRun, 0, 10)
currRunScript := RuneInfos[rs[0]].ScriptTable currRunScript := RuneInfos[rs[0]].ScriptTable
//TODO: We need to detect neutral characters through BiDi category, not being in common //TODO: We need to detect neutral characters through BiDi category, not being in common
@ -211,10 +204,10 @@ func (gr *GlyphRend) GetTextRuns(t string) [][]rune {
} }
//We reached a new run so count trailing neutrals to be removed from this run //We reached a new run so count trailing neutrals to be removed from this run
newRun := rs[runStartIndex:i] newRunRunes := rs[runStartIndex:i]
trailingCommonsCount := 0 trailingCommonsCount := 0
for j := len(newRun) - 1; j >= 0; j-- { for j := len(newRunRunes) - 1; j >= 0; j-- {
if !unicode.Is(unicode.Common, newRun[j]) { if !unicode.Is(unicode.Common, newRunRunes[j]) {
break break
} }
trailingCommonsCount++ trailingCommonsCount++
@ -222,10 +215,11 @@ func (gr *GlyphRend) GetTextRuns(t string) [][]rune {
//If we have a run without trailing neutrals or had a run of just neutrals (e.g. starting sentence with spaces) //If we have a run without trailing neutrals or had a run of just neutrals (e.g. starting sentence with spaces)
//then the full run is added, otherwise we slice the run to put neturals in a separate run //then the full run is added, otherwise we slice the run to put neturals in a separate run
if trailingCommonsCount == 0 || len(newRun) == trailingCommonsCount { if trailingCommonsCount == 0 || len(newRunRunes) == trailingCommonsCount {
runs = append(runs, newRun) runs = append(runs, TextRun{Runes: newRunRunes})
} else { } else {
runs = append(runs, newRun[:len(newRun)-trailingCommonsCount], newRun[len(newRun)-trailingCommonsCount:]) runs = append(runs,
TextRun{Runes: newRunRunes[:len(newRunRunes)-trailingCommonsCount]}, TextRun{Runes: newRunRunes[len(newRunRunes)-trailingCommonsCount:]})
} }
//The removed neutrals are included as the start of the new run //The removed neutrals are included as the start of the new run
@ -233,7 +227,21 @@ func (gr *GlyphRend) GetTextRuns(t string) [][]rune {
currRunScript = ri.ScriptTable currRunScript = ri.ScriptTable
} }
runs = append(runs, rs[runStartIndex:]) runs = append(runs, TextRun{Runes: rs[runStartIndex:]})
//Detect directionality of each run
for i := 0; i < len(runs); i++ {
run := &runs[i]
bidiCat := BidiCategory_L
for _, r := range run.Runes {
if !unicode.Is(unicode.Common, r) {
bidiCat = RuneInfos[r].BidiCat
break
}
}
run.IsLtr = !(bidiCat == BidiCategory_R || bidiCat == BidiCategory_AL || bidiCat == BidiCategory_RLE || bidiCat == BidiCategory_RLO || bidiCat == BidiCategory_RLI || bidiCat == BidiCategory_RLM)
}
return runs return runs
} }

View File

@ -165,8 +165,8 @@ func (p *program) Update() {
if imgui.Button("Print Runs") { if imgui.Button("Print Runs") {
runs := p.GlyphRend.GetTextRuns(textToShow) runs := p.GlyphRend.GetTextRuns(textToShow)
for _, r := range runs { for _, run := range runs {
fmt.Printf("%s; runes: %#x\n\n", string(r), r) fmt.Printf("%s; runes: %#x\n\n", string(run.Runes), run.Runes)
} }
fmt.Printf("----------------\n") fmt.Printf("----------------\n")
} }