freetype: text_size() so that users can retrieve the vertical size of a text too

pull/3497/head
Delyan Angelov 2020-01-18 21:08:11 +02:00 committed by Alexander Medvednikov
parent 09e390eac5
commit 8c1b03c731
3 changed files with 80 additions and 20 deletions

View File

@ -46,10 +46,16 @@ pub const (
) )
struct Character { struct Character {
code i64
texture_id u32 texture_id u32
size gg.Vec2 size gg.Vec2
bearing gg.Vec2
advance u32 horizontal_bearing_px gg.Vec2
horizontal_advance_px u32
vertical_bearing_px gg.Vec2
vertical_advance_px u32
} }
[typedef] [typedef]
@ -84,6 +90,19 @@ struct C.Bitmap {
struct C.Advance { struct C.Advance {
x int x int
y int
}
[typedef]
struct C.FT_Glyph_Metrics {
width int
height int
horiBearingX int
horiBearingY int
horiAdvance int
vertBearingX int
vertBearingY int
vertAdvance int
} }
struct C.Glyph { struct C.Glyph {
@ -91,11 +110,14 @@ struct C.Glyph {
bitmap_left int bitmap_left int
bitmap_top int bitmap_top int
advance Advance advance Advance
metrics FT_Glyph_Metrics
} }
[typedef] [typedef]
struct C.FT_Face { struct C.FT_Face {
glyph &Glyph glyph &Glyph
family_name charptr
style_name charptr
} }
fn C.FT_Load_Char(voidptr, i64, int) int fn C.FT_Load_Char(voidptr, i64, int) int
@ -104,12 +126,12 @@ fn ft_load_char(face C.FT_Face, code i64) Character {
//println('\nftload_char( code=$code)') //println('\nftload_char( code=$code)')
//C.printf('face=%p\n', face) //C.printf('face=%p\n', face)
//C.printf('cobj=%p\n', _face.cobj) //C.printf('cobj=%p\n', _face.cobj)
ret := C.FT_Load_Char(face, code, C.FT_LOAD_RENDER) ret := C.FT_Load_Char(face, code, C.FT_LOAD_RENDER|C.FT_LOAD_FORCE_AUTOHINT)
//println('ret=$ret') //println('ret=$ret')
if ret != 0 { if ret != 0 {
println('freetype: failed to load glyph (utf32 code=$code, ' + println('freetype: failed to load glyph (utf32 code=$code, ' +
'error code=$ret)') 'error code=$ret)')
return Character{} return Character{code: code}
} }
// Generate texture // Generate texture
mut texture := 0 mut texture := 0
@ -124,14 +146,19 @@ fn ft_load_char(face C.FT_Face, code i64) Character {
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_T, C.GL_CLAMP_TO_EDGE) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_WRAP_T, C.GL_CLAMP_TO_EDGE)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MIN_FILTER, C.GL_LINEAR)
C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR) C.glTexParameteri(C.GL_TEXTURE_2D, C.GL_TEXTURE_MAG_FILTER, C.GL_LINEAR)
fgleft := face.glyph.bitmap_left
fgtop := face.glyph.bitmap_top
// Create the character // Create the character
return Character { return Character {
code: code
texture_id: u32(texture) texture_id: u32(texture)
size: gg.vec2(int(u32(fgwidth)), int(u32(fgrows))) size: gg.vec2(fgwidth, fgrows)
bearing: gg.vec2(int(u32(fgleft)), int(u32(fgtop)))
advance: (u32(face.glyph.advance.x)) // Note: advance is number of 1/64 pixels
// Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
horizontal_bearing_px: gg.vec2(face.glyph.metrics.horiBearingX >> 6, face.glyph.metrics.horiBearingY >> 6)
vertical_bearing_px: gg.vec2(face.glyph.metrics.vertBearingX >> 6, face.glyph.metrics.vertBearingY >> 6) // not used for now
horizontal_advance_px: face.glyph.metrics.horiAdvance >> 6
vertical_advance_px: face.glyph.metrics.vertAdvance >> 6
} }
} }
@ -316,8 +343,8 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
//exit(1) //exit(1)
// continue // continue
} }
xpos := x + f32(ch.bearing.x) * 1 xpos := x + f32(ch.horizontal_bearing_px.x) * 1
ypos := y - f32(ch.size.y - ch.bearing.y) * 1 ypos := y - f32(ch.size.y - ch.horizontal_bearing_px.y) * 1
w := f32(ch.size.x) * 1 w := f32(ch.size.x) * 1
h := f32(ch.size.y) * 1 h := f32(ch.size.y) * 1
// Update VBO for each character // Update VBO for each character
@ -337,9 +364,7 @@ fn (ctx mut FreeType) private_draw_text(_x, _y int, utext ustring, cfg gx.TextCf
C.glBufferData(C.GL_ARRAY_BUFFER, 96, vertices.data, C.GL_DYNAMIC_DRAW) C.glBufferData(C.GL_ARRAY_BUFFER, 96, vertices.data, C.GL_DYNAMIC_DRAW)
// Render quad // Render quad
gl.draw_arrays(C.GL_TRIANGLES, 0, 6) gl.draw_arrays(C.GL_TRIANGLES, 0, 6)
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels) x += f32(ch.horizontal_advance_px)
// Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
x += ch.advance >> u32(6)
} }
gl.bind_vao(u32(0)) gl.bind_vao(u32(0))
C.glBindTexture(C.GL_TEXTURE_2D, 0) C.glBindTexture(C.GL_TEXTURE_2D, 0)
@ -355,12 +380,25 @@ pub fn (ctx mut FreeType) draw_text_def(x, y int, text string) {
} }
pub fn (ctx mut FreeType) text_width(s string) int { pub fn (ctx mut FreeType) text_width(s string) int {
x, _ := ctx.text_size(s)
return x
}
pub fn (ctx mut FreeType) text_height(s string) int {
_, y := ctx.text_size(s)
return y
}
pub fn (ctx mut FreeType) text_size(s string) (int, int) {
//t := time.ticks() //t := time.ticks()
utext := s.ustring() utext := s.ustring()
mut x := f64(0) mut x := u32(0)
mut maxy := u32(0)
mut _rune := ''
mut ch := Character{}
for i := 0; i < utext.len; i++ { for i := 0; i < utext.len; i++ {
_rune := utext.at(i) _rune = utext.at(i)
mut ch := Character{} ch = Character{}
mut found := false mut found := false
if _rune.len == 1 { if _rune.len == 1 {
idx := _rune[0] idx := _rune[0]
@ -387,10 +425,25 @@ pub fn (ctx mut FreeType) text_width(s string) int {
ctx.utf_runes << _rune ctx.utf_runes << _rune
ctx.utf_chars << ch ctx.utf_chars << ch
} }
x += ch.advance >> u32(6) x += ch.horizontal_advance_px
if maxy < ch.vertical_advance_px {
maxy = ch.vertical_advance_px
}
} }
//println('text width "$s" = ${time.ticks() - t} ms') //println('text width "$s" = ${time.ticks() - t} ms')
return int(x) / ctx.scale scaled_x := int(f64(x) / ctx.scale)
scaled_y := int(f64(maxy) / ctx.scale)
//println('text_size of "${s}" | x,y: $x,$maxy | scaled_x: ${scaled_x:3d} | scaled_y: ${scaled_y:3d} ')
return scaled_x, scaled_y
} }
pub fn (f FT_Face) str() string {
return 'FT_Face{ style_name: ${ptr_str(f.style_name)} family_name: ${ptr_str(f.family_name)} }'
}
pub fn (ac []Character) str() string {
mut res := []string
for c in ac {
res << ' Character{ code: $c.code , texture_id: $c.texture_id }'
}
return '[\n' + res.join(',\n') + ']'
}

View File

@ -17,6 +17,10 @@ pub:
y int y int
} }
pub fn (v Vec2) str() string {
return 'Vec2{ x: $v.x y: $v.y }'
}
pub fn vec2(x, y int) Vec2 { pub fn vec2(x, y int) Vec2 {
res := Vec2 { res := Vec2 {
x: x x: x

View File

@ -13,6 +13,9 @@ import glm
pub struct Shader { pub struct Shader {
program_id int program_id int
} }
pub fn (s Shader) str() string {
return 'Shader{ program_id: s.program_id }'
}
pub const ( pub const (
TEXT_VERT = '#version 330 core TEXT_VERT = '#version 330 core