diff options
Diffstat (limited to 'v_windows/v/vlib/x/ttf/README.md')
-rw-r--r-- | v_windows/v/vlib/x/ttf/README.md | 310 |
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() +} +``` |