aboutsummaryrefslogtreecommitdiff
path: root/v_windows/v/vlib/x/ttf/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'v_windows/v/vlib/x/ttf/README.md')
-rw-r--r--v_windows/v/vlib/x/ttf/README.md310
1 files changed, 310 insertions, 0 deletions
diff --git a/v_windows/v/vlib/x/ttf/README.md b/v_windows/v/vlib/x/ttf/README.md
new file mode 100644
index 0000000..6394ac1
--- /dev/null
+++ b/v_windows/v/vlib/x/ttf/README.md
@@ -0,0 +1,310 @@
+# TTF font utility
+## introduction
+This module is designed to perform two main task
+- Load the font file
+- Render text using a TTF font
+
+The render system can be single or multiple, for example it is possible to have a bitmap
+render and a HW accelerated render.
+
+## TTF loader
+This part of the module do a simple task, load a TTF file and preprocess all the loaded data
+in order to simplify the rendering phase.
+
+Let's start with a simple snippet of code that load a font from the disk:
+```v ignore
+mut ttf_font := ttf.TTF_File{}
+ttf_font.buf = os.read_bytes("arial.ttf") or { panic(err) }
+ttf_font.init()
+```
+*Note: the font must be passed to the `TTF_file` as RAM buffer.*
+At this point the font "arial" is loaded and parsed and if it is a valid TTF font it is
+ready for the rendering.
+We can get some quick info on the font as string using the `get_info_string` function:
+
+```v oksyntax
+println(ttf_font.get_info_string())
+```
+produces an output like this:
+```
+----- Font Info -----
+font_family : Arial
+font_sub_family : Normal
+full_name : Arial
+postscript_name : ArialMT
+version : 1
+font_revision : 5.06
+magic_number : 5f0f3cf5
+flags : 81b
+created unixTS : 649950890
+modified unixTS : 1282151447
+units_per_em : 2048
+box : [x_min:-1361, y_min:-665, x_Max:4096, y_Max:2060]
+mac_style : 0
+-----------------------
+```
+
+Once loaded a font the `TTF_File` struct is filled with the font data and texts can be rendered.
+At high level no more action are required to use the loaded font.
+Multiple fonts can be loaded without problems at the same time.
+
+## TTF Bitmap render
+In this modue it is possible to have different renders running at the same time.
+At the present time all the rendering are made on the CPU, sokol is used only to draw the
+rendered text to the screen.
+Let's start with a simple snippet of code:
+```v oksyntax
+import os
+import x.ttf
+
+[console]
+fn main() {
+ mut ttf_font := ttf.TTF_File{}
+ ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
+ ttf_font.init()
+ // print font info
+ println(ttf_font.get_info_string())
+}
+```
+This simple code load a TTF font and display its basic informations.
+
+### draw_text
+The draw text function draw simple strings without indentation or other imagination tasks.
+At this point we can render a simple text:
+```v oksyntax
+import os
+import x.ttf
+
+[console]
+fn main() {
+ mut ttf_font := ttf.TTF_File{}
+ ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
+ ttf_font.init()
+ // print font info
+ println(ttf_font.get_info_string())
+
+ bmp_width := 200
+ bmp_heigth := 64
+ bmp_layers := 4 // number of planes for an RGBA buffer
+ // memory size of the buffer
+ bmp_size := bmp_width * bmp_heigth * bmp_layers
+
+ font_size := 32 // font size in points
+ device_dpi := 72 // default screen DPI
+ // Formula for scale calculation
+ // scaler := (font_size * device dpi) / (72dpi * em_unit)
+ scale := f32(font_size * device_dpi) / f32(72 * ttf_font.units_per_em)
+ // height of the font to use in the buffer to separate the lines
+ y_base := int((ttf_font.y_max - ttf_font.y_min) * scale)
+
+ // declare the bitmap struct
+ mut bmp := ttf.BitMap{
+ tf: &ttf_font
+ buf: malloc(bmp_size)
+ buf_size: bmp_size
+ width: bmp_width
+ height: bmp_heigth
+ bp: bmp_layers
+ color: 0x000000_FF // RGBA black
+ scale: scale
+ }
+ bmp.init_filler()
+ bmp.clear()
+ bmp.set_pos(10, y_base)
+ bmp.draw_text('Test Text!')
+ bmp.save_as_ppm('test.ppm')
+}
+```
+This is the low level render that draw ther text on a bitmap and save the bitmap on a disk as
+`.ppm` file.
+*Note: The render in this case is a raw rendering without any postfiltering or other processing.*
+
+Using the low level rendering you need to manage all the amenities like allocate and release
+memory and other tasks like calc the character dimensions.
+
+You can specify the style for the text rendering in the `BitMap` struct::
+```v
+enum Style {
+ outline
+ outline_aliased
+ filled // default syle
+ raw
+}
+```
+Use this level only if you want achieve particular result on text rendering.
+
+### draw_text_block
+Draw text block draw a justified and indented block of multiline text in the bitmap.
+```v oksyntax
+import os
+import x.ttf
+
+[console]
+fn main() {
+ mut ttf_font := ttf.TTF_File{}
+ ttf_font.buf = os.read_bytes('arial.ttf') or { panic(err) }
+ ttf_font.init()
+ // print font info
+ println(ttf_font.get_info_string())
+
+ bmp_width := 200
+ bmp_heigth := 200
+ bmp_layers := 4 // number of planes for an RGBA buffer
+ // memory size of the buffer
+ bmp_size := bmp_width * bmp_heigth * bmp_layers
+
+ font_size := 32 // font size in points
+ device_dpi := 72 // default screen DPI
+ // Formula for scale calculation
+ // scaler := (font_size * device dpi) / (72dpi * em_unit)
+ scale := f32(font_size * device_dpi) / f32(72 * ttf_font.units_per_em)
+ // height of the font to use in the buffer to separate the lines
+ y_base := int((ttf_font.y_max - ttf_font.y_min) * scale)
+
+ text := "Today it is a good day!
+Tomorrow I'm not so sure :(
+But Vwill prevail for sure, V is the way!!
+òàèì@ò!£$%&
+"
+ // declare the bitmap struct
+ mut bmp := ttf.BitMap{
+ tf: &ttf_font
+ buf: malloc(bmp_size)
+ buf_size: bmp_size
+ width: bmp_width
+ height: bmp_heigth
+ bp: bmp_layers
+ color: 0x000000_FF // RGBA black
+ scale: scale
+ }
+ bmp.init_filler()
+ bmp.clear()
+ bmp.justify = true
+ bmp.align = .left
+ bmp.draw_text_block(text, x: 0, y: 0, w: bmp_width - 20, h: bmp_heigth)
+ bmp.save_as_ppm('test.ppm')
+}
+```
+This is the low level render that draw text block on the bitmap.
+A text block is defined from a `Text_block` struct:
+```v
+struct Text_block {
+ x int // x postion of the left high corner
+ y int // y postion of the left high corner
+ w int // width of the text block
+ h int // heigth of the text block
+ cut_lines bool = true // force to cut the line if the length is over the text block width
+}
+```
+and use the following bitmap fields:
+```v ignore
+ style Style = .filled // default syle
+ align Text_align = .left // default text align
+ justify bool // justify text flag, default deactivated
+ justify_fill_ratio f32 = 0.5 // justify fill ratio, if the ratio of the filled
+ // row is >= of this then justify the text
+```
+
+It is possible to modify these parameters to obtain the desired effect on the text rendering.
+
+## TTF Sokol render
+The sokol render use the bitmap render to create the text and the `gg` functions to render
+the text to the screen.
+It is mor esimpel to use in a `gg app` that the raw bitmap render.
+Each single text rendered need its own reder to be declared, after you can modify it.
+Here a simple example of the usage:
+```v oksyntax
+import gg
+import gx
+import sokol.sapp
+import sokol.sgl
+import x.ttf
+import os
+
+const (
+ win_width = 600
+ win_height = 700
+ bg_color = gx.white
+ font_paths = [
+ 'arial.ttf',
+ ]
+)
+
+struct App_data {
+pub mut:
+ gg &gg.Context
+ sg_img C.sg_image
+ init_flag bool
+ frame_c int
+
+ tf []ttf.TTF_File
+ ttf_render []ttf.TTF_render_Sokol
+}
+
+fn my_init(mut app App_data) {
+ app.init_flag = true
+}
+
+fn draw_frame(mut app App_data) {
+ cframe_txt := 'Current Frame: $app.frame_c'
+
+ app.gg.begin()
+
+ sgl.defaults()
+ sgl.matrix_mode_projection()
+ sgl.ortho(0.0, f32(sapp.width()), f32(sapp.height()), 0.0, -1.0, 1.0)
+
+ // draw text only if the app is already initialized
+ if app.init_flag == true {
+ // update the text
+ mut txt1 := &app.ttf_render[0]
+ txt1.destroy_texture()
+ txt1.create_text(cframe_txt, 43)
+ txt1.create_texture()
+ txt1.draw_text_bmp(app.gg, 30, 60)
+ }
+ app.frame_c++
+ app.gg.end()
+}
+
+[console]
+fn main() {
+ mut app := &App_data{
+ gg: 0
+ }
+
+ app.gg = gg.new_context(
+ width: win_width
+ height: win_height
+ create_window: true
+ window_title: 'Test TTF module'
+ user_data: app
+ bg_color: bg_color
+ frame_fn: draw_frame
+ init_fn: my_init
+ )
+
+ // load TTF fonts
+ for font_path in font_paths {
+ mut tf := ttf.TTF_File{}
+ tf.buf = os.read_bytes(font_path) or { panic(err) }
+ println('TrueTypeFont file [$font_path] len: $tf.buf.len')
+ tf.init()
+ println(tf.get_info_string())
+ app.tf << tf
+ }
+
+ // TTF render 0 Frame counter
+ app.ttf_render << &ttf.TTF_render_Sokol{
+ bmp: &ttf.BitMap{
+ tf: &(app.tf[0])
+ buf: unsafe { malloc(32000000) }
+ buf_size: (32000000)
+ color: 0xFF0000FF
+ // style: .raw
+ }
+ }
+
+ app.gg.run()
+}
+```