Got zoom implemented on library's side. Still figuring out font size issue

This commit is contained in:
2025-01-10 20:16:51 -05:00
parent 3b59ac75bf
commit c995af36e7
3 changed files with 198 additions and 205 deletions

View File

@@ -150,66 +150,23 @@ get_font_vertical_metrics :: #force_inline proc ( font : Font_ID, font_size := F
} }
// Draw text using a string and normalized render coordinates // Draw text using a string and normalized render coordinates
draw_text_string_pos_norm :: proc( content : string, font : Font_ID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 ) draw_text :: proc( content : string, font : Font_ID, pos : Vec2, size : f32 = 0.0, color := COLOR_WHITE, scale : f32 = 1.0, zoom : f32 = 1.0 )
{ {
color_norm := normalize_rgba8(color) color_norm := normalize_rgba8(color)
def := demo_ctx.font_ids[ font.label ] def := demo_ctx.font_ids[ font.label ]
size := size > 2.0 ? size : f32(def.default_size) size := size >= 2.0 ? size : f32(def.default_size)
norm_pos, norm_scale := ve.get_normalized_position_scale( pos, scale, demo_ctx.screen_size ) ve.draw_text_view_space( & demo_ctx.ve_ctx,
ve.draw_text_normalized_space( & demo_ctx.ve_ctx,
def.ve_id, def.ve_id,
size, size,
color_norm, color_norm,
norm_pos, demo_ctx.screen_size,
norm_scale,
1.0,
content
)
// ve.draw_text_view_space( & demo_ctx.ve_ctx,
// def.ve_id,
// size,
// color_norm,
// demo_ctx.screen_size,
// pos,
// scale,
// 1.0,
// content
// )
return
}
// Adapt the draw_text_string_pos_extent_zoomed procedure
draw_text_zoomed_norm :: proc(content : string, font : Font_ID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE)
{
screen_size := demo_ctx.screen_size
screen_scale := 1 / screen_size
zoom_adjust_size := size * zoom
resolved_size := size
text_scale := screen_scale
{
diff_scalar := 1 + (zoom_adjust_size - resolved_size) / resolved_size
text_scale = diff_scalar * screen_scale
text_scale.x = clamp(text_scale.x, 0, 1)
text_scale.y = clamp(text_scale.y, 0, 1)
}
color_norm := normalize_rgba8(color)
def := demo_ctx.font_ids[ font.label ]
ve.draw_text_normalized_space(& demo_ctx.ve_ctx,
def.ve_id,
resolved_size,
color_norm,
pos, pos,
text_scale, scale,
1.0, zoom,
content content
) )
return
} }
sokol_app_alloc :: proc "c" ( size : uint, user_data : rawptr ) -> rawptr { sokol_app_alloc :: proc "c" ( size : uint, user_data : rawptr ) -> rawptr {
@@ -236,7 +193,6 @@ sokol_gfx_free :: proc "c" ( data : rawptr, user_data : rawptr ) {
free(data, allocator = context.allocator ) free(data, allocator = context.allocator )
} }
init :: proc "c" () init :: proc "c" ()
{ {
context = runtime.default_context() context = runtime.default_context()
@@ -268,18 +224,18 @@ init :: proc "c" ()
} }
glyph_draw_opts := ve.Init_Glyph_Draw_Params_Default glyph_draw_opts := ve.Init_Glyph_Draw_Params_Default
glyph_draw_opts.snap_glyph_height = false glyph_draw_opts.snap_glyph_height = true
shaper_opts := ve.Init_Shaper_Params_Default shaper_opts := ve.Init_Shaper_Params_Default
shaper_opts.snap_glyph_position = false shaper_opts.snap_glyph_position = true
ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator, ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator,
glyph_draw_params = glyph_draw_opts, glyph_draw_params = glyph_draw_opts,
shaper_params = shaper_opts, shaper_params = shaper_opts,
px_scalar = 1.5, px_scalar = 1,
alpha_sharpen = 0.1, alpha_sharpen = 0.1,
) )
ve_sokol.setup_gfx_objects( & demo_ctx.render_ctx, & demo_ctx.ve_ctx, vert_cap = 1024 * 1024, index_cap = 1024 * 1024 ) ve_sokol.setup_gfx_objects( & demo_ctx.render_ctx, & demo_ctx.ve_ctx, vert_cap = 256 * 1024, index_cap = 512 * 1024 )
error : mem.Allocator_Error error : mem.Allocator_Error
demo_ctx.font_ids, error = make( map[string]Font_Entry, 256 ) demo_ctx.font_ids, error = make( map[string]Font_Entry, 256 )
@@ -301,12 +257,12 @@ init :: proc "c" ()
path_noto_sans_jp_reg := strings.concatenate({ PATH_FONTS, "NotoSansJP-Regular.otf" }) path_noto_sans_jp_reg := strings.concatenate({ PATH_FONTS, "NotoSansJP-Regular.otf" })
path_firacode := strings.concatenate({ PATH_FONTS, "FiraCode-Regular.ttf" }) path_firacode := strings.concatenate({ PATH_FONTS, "FiraCode-Regular.ttf" })
demo_ctx.font_logo = font_load(path_sawarabi_mincho, 330.0, "SawarabiMincho", 6 ) demo_ctx.font_logo = font_load(path_sawarabi_mincho, 300.0, "SawarabiMincho", 12 )
demo_ctx.font_title = font_load(path_open_sans, 92.0, "OpenSans", 6 ) // demo_ctx.font_title = font_load(path_open_sans, 92.0, "OpenSans", 6 )
demo_ctx.font_print = font_load(path_noto_sans_jp, 19.0, "NotoSansJP") demo_ctx.font_print = font_load(path_noto_sans_jp, 19.0, "NotoSansJP")
demo_ctx.font_mono = font_load(path_ubuntu_mono, 21.0, "UbuntuMono") demo_ctx.font_mono = font_load(path_ubuntu_mono, 21.0, "UbuntuMono")
demo_ctx.font_small = font_load(path_roboto, 10.0, "Roboto") demo_ctx.font_small = font_load(path_roboto, 10.0, "Roboto")
demo_ctx.font_demo_sans = font_load(path_open_sans, 18.0, "OpenSans") demo_ctx.font_demo_sans = font_load(path_open_sans, 18.0, "OpenSans", 6)
demo_ctx.font_demo_serif = font_load(path_bitter, 18.0, "Bitter") demo_ctx.font_demo_serif = font_load(path_bitter, 18.0, "Bitter")
demo_ctx.font_demo_script = font_load(path_dancing_script, 22.0, "DancingScript") demo_ctx.font_demo_script = font_load(path_dancing_script, 22.0, "DancingScript")
demo_ctx.font_demo_mono = font_load(path_nova_mono, 18.0, "NovaMono") demo_ctx.font_demo_mono = font_load(path_nova_mono, 18.0, "NovaMono")
@@ -317,9 +273,10 @@ init :: proc "c" ()
demo_ctx.font_demo_arabic = font_load(path_tajawal, 24.0, "Tajawal") demo_ctx.font_demo_arabic = font_load(path_tajawal, 24.0, "Tajawal")
demo_ctx.font_demo_hebrew = font_load(path_david_libre, 22.0, "DavidLibre") demo_ctx.font_demo_hebrew = font_load(path_david_libre, 22.0, "DavidLibre")
demo_ctx.font_demo_raincode = font_load(path_noto_sans_jp_reg, 20.0, "NotoSansJPRegular") demo_ctx.font_demo_raincode = font_load(path_noto_sans_jp_reg, 20.0, "NotoSansJPRegular")
demo_ctx.font_demo_grid2 = font_load(path_noto_serif_sc, 54.0, "NotoSerifSC") demo_ctx.font_title = demo_ctx.font_demo_sans
demo_ctx.font_demo_grid3 = font_load(path_bitter, 44.0, "Bitter") demo_ctx.font_demo_grid2 = demo_ctx.font_demo_chinese
demo_ctx.font_firacode = font_load(path_firacode, 16.0, "FiraCode", 3 ) demo_ctx.font_demo_grid3 = demo_ctx.font_demo_serif
demo_ctx.font_firacode = font_load(path_firacode, 16.0, "FiraCode", 12 )
} }
event :: proc "c" (sokol_event : ^app.Event) event :: proc "c" (sokol_event : ^app.Event)
@@ -371,7 +328,7 @@ frame :: proc "c" ()
// Frametime display // Frametime display
frametime_text := fmt.tprintf("Frametime %v", frame_duration) frametime_text := fmt.tprintf("Frametime %v", frame_duration)
draw_text_string_pos_norm(frametime_text, demo_ctx.font_title, 0, {0.0, 0.0}, COLOR_WHITE) draw_text(frametime_text, demo_ctx.font_title, {0.0, 0.0}, size = 30)
if current_scroll < 1.5 { if current_scroll < 1.5 {
intro := `Ça va! Everything here is rendered using VE Font Cache, a single header-only library designed for game engines. intro := `Ça va! Everything here is rendered using VE Font Cache, a single header-only library designed for game engines.
@@ -386,9 +343,9 @@ It aims to:
• Support cached text shaping with HarfBuzz with simple Latin-style fallback. • Support cached text shaping with HarfBuzz with simple Latin-style fallback.
• Load and unload fonts at any time.` • Load and unload fonts at any time.`
draw_text_string_pos_norm("ゑ", demo_ctx.font_logo, 330, { 0.4, current_scroll }, COLOR_WHITE) draw_text("ゑ", demo_ctx.font_logo, { 0.4, current_scroll }, size = 200, scale = 2.0)
draw_text_string_pos_norm("VEFontCache Demo", demo_ctx.font_title, 92, { 0.2, current_scroll - 0.1 }, COLOR_WHITE) draw_text("VEFontCache Demo", demo_ctx.font_title, { 0.2, current_scroll - 0.1 }, size = 92)
draw_text_string_pos_norm(intro, demo_ctx.font_print, 19, { 0.2, current_scroll - 0.14 }, COLOR_WHITE) draw_text(intro, demo_ctx.font_print, { 0.2, current_scroll - 0.14 }, size = 19)
} }
section_start : f32 = 0.42 section_start : f32 = 0.42
@@ -431,10 +388,10 @@ Glyphs are first rendered to an intermediate 2k x 512px R8 texture. This allows
4 x 4 = 16x supersampling, and 8 Region C glyphs similarly. A simple 16-tap box downsample shader is then used to blit from this 4 x 4 = 16x supersampling, and 8 Region C glyphs similarly. A simple 16-tap box downsample shader is then used to blit from this
intermediate texture to the final atlas location.` intermediate texture to the final atlas location.`
draw_text_string_pos_norm("How it works", demo_ctx.font_title, 92, { 0.2, current_scroll - (section_start + 0.06) }, COLOR_WHITE) draw_text("How it works", demo_ctx.font_title, { 0.2, current_scroll - (section_start + 0.06) })
draw_text_string_pos_norm(how_it_works, demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.1) }, COLOR_WHITE) draw_text(how_it_works, demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.1) })
draw_text_string_pos_norm(caching_strategy, demo_ctx.font_mono, 21, { 0.28, current_scroll - (section_start + 0.32) }, COLOR_WHITE) draw_text(caching_strategy, demo_ctx.font_mono, { 0.28, current_scroll - (section_start + 0.32) })
draw_text_string_pos_norm(how_it_works2, demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.82) }, COLOR_WHITE) draw_text(how_it_works2, demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.82) })
} }
// Showcase section // Showcase section
@@ -445,49 +402,49 @@ intermediate texture to the final atlas location.`
incididunt ut labore et dolore magna aliqua. Est ullamcorper eget nulla facilisi incididunt ut labore et dolore magna aliqua. Est ullamcorper eget nulla facilisi
etiam dignissim diam quis enim. Convallis convallis tellus id interdum.` etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
draw_text_string_pos_norm("Showcase", demo_ctx.font_title, 92, { 0.2, current_scroll - (section_start + 0.2) }, COLOR_WHITE) draw_text("Showcase", demo_ctx.font_title, { 0.2, current_scroll - (section_start + 0.2) }, size = 92)
draw_text_string_pos_norm("This is a showcase demonstrating different hb_font categories and languages.", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.24) }, COLOR_WHITE) draw_text("This is a showcase demonstrating different hb_font categories and languages.", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.24) }, size = 19)
draw_text_string_pos_norm("Sans serif", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.28) }, COLOR_WHITE) draw_text("Sans serif", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.28) }, size = 19)
draw_text_string_pos_norm(font_family_test, demo_ctx.font_demo_sans, 18, { 0.3, current_scroll - (section_start + 0.28) }, COLOR_WHITE) draw_text(font_family_test, demo_ctx.font_demo_sans, { 0.3, current_scroll - (section_start + 0.28) }, size = 18)
draw_text_string_pos_norm("Serif", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.36) }, COLOR_WHITE) draw_text("Serif", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.36) })
draw_text_string_pos_norm(font_family_test, demo_ctx.font_demo_serif, 18, { 0.3, current_scroll - (section_start + 0.36) }, COLOR_WHITE) draw_text(font_family_test, demo_ctx.font_demo_serif, { 0.3, current_scroll - (section_start + 0.36) })
draw_text_string_pos_norm("Script", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.44) }, COLOR_WHITE) draw_text("Script", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.44) })
draw_text_string_pos_norm(font_family_test, demo_ctx.font_demo_script, 22, { 0.3, current_scroll - (section_start + 0.44) }, COLOR_WHITE) draw_text(font_family_test, demo_ctx.font_demo_script, { 0.3, current_scroll - (section_start + 0.44) })
draw_text_string_pos_norm("Monospace", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.52) }, COLOR_WHITE) draw_text("Monospace", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.52) })
draw_text_string_pos_norm(font_family_test, demo_ctx.font_demo_mono, 18, { 0.3, current_scroll - (section_start + 0.52) }, COLOR_WHITE) draw_text(font_family_test, demo_ctx.font_demo_mono, { 0.3, current_scroll - (section_start + 0.52) })
draw_text_string_pos_norm("Small", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.60) }, COLOR_WHITE) draw_text("Small", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.60) })
draw_text_string_pos_norm(font_family_test, demo_ctx.font_small, 10, { 0.3, current_scroll - (section_start + 0.60) }, COLOR_WHITE) draw_text(font_family_test, demo_ctx.font_small, { 0.3, current_scroll - (section_start + 0.60) })
draw_text_string_pos_norm("Greek", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.72) }, COLOR_WHITE) draw_text("Greek", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.72) })
draw_text_string_pos_norm("Ήταν απλώς θέμα χρόνου.", demo_ctx.font_demo_sans, 18, { 0.3, current_scroll - (section_start + 0.72) }, COLOR_WHITE) draw_text("Ήταν απλώς θέμα χρόνου.", demo_ctx.font_demo_sans, { 0.3, current_scroll - (section_start + 0.72) })
draw_text_string_pos_norm("Vietnamese", demo_ctx.font_print, 19, { 0.2, current_scroll - (section_start + 0.76) }, COLOR_WHITE) draw_text("Vietnamese", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.76) })
draw_text_string_pos_norm("Bầu trời trong xanh thăm thẳm, không một gợn mây.", demo_ctx.font_demo_sans, 18, { 0.3, current_scroll - (section_start + 0.76) }, COLOR_WHITE) draw_text("Bầu trời trong xanh thăm thẳm, không một gợn mây.", demo_ctx.font_demo_sans, { 0.3, current_scroll - (section_start + 0.76) })
draw_text_string_pos_norm("Thai", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 0.80)}, COLOR_WHITE) draw_text("Thai", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.80) })
draw_text_string_pos_norm("การเดินทางขากลับคงจะเหงา", demo_ctx.font_demo_thai, 24, {0.3, current_scroll - (section_start + 0.80)}, COLOR_WHITE) draw_text("การเดินทางขากลับคงจะเหงา", demo_ctx.font_demo_thai, { 0.3, current_scroll - (section_start + 0.80) })
draw_text_string_pos_norm("Chinese", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 0.84)}, COLOR_WHITE) draw_text("Chinese", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.84) })
draw_text_string_pos_norm("床前明月光 疑是地上霜 举头望明月 低头思故乡", demo_ctx.font_demo_chinese, 24, {0.3, current_scroll - (section_start + 0.84)}, COLOR_WHITE) draw_text("床前明月光 疑是地上霜 举头望明月 低头思故乡", demo_ctx.font_demo_chinese, {0.3, current_scroll - (section_start + 0.84) })
draw_text_string_pos_norm("Japanese", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 0.88)}, COLOR_WHITE) draw_text("Japanese", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.88) })
draw_text_string_pos_norm("ぎょしょうとナレズシの研究 モンスーン・アジアの食事文化", demo_ctx.font_demo_japanese, 24, {0.3, current_scroll - (section_start + 0.88)}, COLOR_WHITE) draw_text("ぎょしょうとナレズシの研究 モンスーン・アジアの食事文化", demo_ctx.font_demo_japanese, { 0.3, current_scroll - (section_start + 0.88) })
draw_text_string_pos_norm("Korean", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 0.92)}, COLOR_WHITE) draw_text("Korean", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.92) })
draw_text_string_pos_norm("그들의 장비와 기구는 모두 살아 있다.", demo_ctx.font_demo_korean, 36, {0.3, current_scroll - (section_start + 0.92)}, COLOR_WHITE) draw_text("그들의 장비와 기구는 모두 살아 있다.", demo_ctx.font_demo_korean, { 0.3, current_scroll - (section_start + 0.92) })
draw_text_string_pos_norm("Needs harfbuzz to work:", demo_ctx.font_print, 14, {0.2, current_scroll - (section_start + 0.96)}, COLOR_WHITE) draw_text("Needs harfbuzz to work:", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 0.96)})
draw_text_string_pos_norm("Arabic", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 1.00)}, COLOR_WHITE) draw_text("Arabic", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 1.00) })
draw_text_string_pos_norm("حب السماء لا تمطر غير الأحلام.", demo_ctx.font_demo_arabic, 24, {0.3, current_scroll - (section_start + 1.00)}, COLOR_WHITE) draw_text("حب السماء لا تمطر غير الأحلام.", demo_ctx.font_demo_arabic, { 0.3, current_scroll - (section_start + 1.00) })
draw_text_string_pos_norm("Hebrew", demo_ctx.font_print, 19, {0.2, current_scroll - (section_start + 1.04)}, COLOR_WHITE) draw_text("Hebrew", demo_ctx.font_print, { 0.2, current_scroll - (section_start + 1.04) })
draw_text_string_pos_norm("אז הגיע הלילה של כוכב השביט הראשון.", demo_ctx.font_demo_hebrew, 22, {0.3, current_scroll - (section_start + 1.04)}, COLOR_WHITE) draw_text("אז הגיע הלילה של כוכב השביט הראשון.", demo_ctx.font_demo_hebrew, { 0.3, current_scroll - (section_start + 1.04) })
} }
// Zoom Test // Zoom Test
@@ -525,21 +482,21 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
zoom_info_y := current_scroll - (section_start + 0.10) zoom_info_y := current_scroll - (section_start + 0.10)
zoomed_text_y := current_scroll - (section_start + 0.30) + math.sin(zoom_time) * 0.02 zoomed_text_y := current_scroll - (section_start + 0.30) + math.sin(zoom_time) * 0.02
draw_text_string_pos_norm("Zoom Test", demo_ctx.font_title, 92, {0.2, title_y}, COLOR_WHITE) draw_text("Zoom Test", demo_ctx.font_title, { 0.2, title_y }, size = 92)
zoomed_text_base_size : f32 = 12.0 zoomed_text_base_size : f32 = 12.0
zoom_adjust_size := zoomed_text_base_size * current_zoom zoom_adjust_size := zoomed_text_base_size * current_zoom
// ve_id, resolved_size := font_resolve_draw_id( font_firacode, zoom_adjust_size * OVER_SAMPLE_ZOOM ) // ve_id, resolved_size := font_resolve_draw_id( font_firacode, zoom_adjust_size * OVER_SAMPLE_ZOOM )
resolved_size := zoom_adjust_size resolved_size := zoom_adjust_size
current_zoom_text := fmt.tprintf("Current Zoom : %.2f x\nCurrent Resolved Size: %v px", current_zoom, resolved_size ) current_zoom_text := fmt.tprintf("Current Zoom : %.2f x\nCurrent Resolved Size: %v px", current_zoom, resolved_size )
draw_text_string_pos_norm(current_zoom_text, demo_ctx.font_firacode, 19, {0.2, zoom_info_y}, COLOR_WHITE) draw_text(current_zoom_text, demo_ctx.font_firacode, { 0.2, zoom_info_y })
// ve.configure_snap( & demo_ctx.ve_ctx, u32(0), u32(0) ) // ve.configure_snap( & demo_ctx.ve_ctx, u32(0), u32(0) )
size := measure_text_size( zoom_text, demo_ctx.font_firacode, zoomed_text_base_size, 0 ) * current_zoom size := measure_text_size( zoom_text, demo_ctx.font_firacode, zoomed_text_base_size, 0 ) * current_zoom
x_offset := (size.x / demo_ctx.screen_size.x) * 0.5 x_offset := (size.x / demo_ctx.screen_size.x) * 0.5
zoomed_text_pos := Vec2 { 0.5 - x_offset, zoomed_text_y } zoomed_text_pos := Vec2 { 0.5 - x_offset, zoomed_text_y }
draw_text_zoomed_norm(zoom_text, demo_ctx.font_firacode, zoomed_text_base_size, zoomed_text_pos, current_zoom, COLOR_WHITE) draw_text(zoom_text, demo_ctx.font_firacode, zoomed_text_pos, size = zoomed_text_base_size, zoom = current_zoom)
} }
// Raincode Demo // Raincode Demo
@@ -562,7 +519,7 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
" ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Z", "T", "H", "E", "", "¦", "日", " ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Z", "T", "H", "E", "", "¦", "日",
"ハ", "ミ", "ヒ", "ー", "ウ", "シ", "ナ", "モ", "ニ", "サ", "ワ", "ツ", "オ", "リ", "ア", "ホ", "テ", "マ", "ハ", "ミ", "ヒ", "ー", "ウ", "シ", "ナ", "モ", "ニ", "サ", "ワ", "ツ", "オ", "リ", "ア", "ホ", "テ", "マ",
"ケ", "メ", "エ", "カ", "キ", "ム", "ユ", "ラ", "セ", "ネ", "ス", "ツ", "タ", "ヌ", "ヘ", ":", "・", ".", "ケ", "メ", "エ", "カ", "キ", "ム", "ユ", "ラ", "セ", "ネ", "ス", "ツ", "タ", "ヌ", "ヘ", ":", "・", ".",
"\"", "=", "*", "+", "-", "<", ">", "ç", "リ", "ク", "コ", "チ", "ヤ", "ル", "ン", "C", "O", "D" "\"", "=", "*", "+", "-", "<", ">", "ç", "リ", "ク", "コ", "チ", "ヤ", "ル", "ン", "C", "O", "D",
} }
if !init_grid { if !init_grid {
@@ -571,7 +528,7 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
} }
@static fixed_timestep_passed : f32 = 0.0 @static fixed_timestep_passed : f32 = 0.0
fixed_timestep : f32 = (1.0 / 30.0) fixed_timestep : f32 = (1.0 / 20.0)
fixed_timestep_passed += frame_duration fixed_timestep_passed += frame_duration
for fixed_timestep_passed > fixed_timestep for fixed_timestep_passed > fixed_timestep
{ {
@@ -591,7 +548,7 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
} }
// Draw grid // Draw grid
draw_text_string_pos_norm("Raincode demo", demo_ctx.font_title, 92, { 0.2, current_scroll - (section_start + 0.2) }, COLOR_WHITE) draw_text("Raincode demo", demo_ctx.font_title, { 0.2, current_scroll - (section_start + 0.2) }, size = 92)
for y in 0 ..< GRID_H do for x in 0 ..< GRID_W for y in 0 ..< GRID_H do for x in 0 ..< GRID_W
{ {
pos_x := 0.2 + f32(x) * 0.007 pos_x := 0.2 + f32(x) * 0.007
@@ -608,7 +565,7 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
if code_colour.a == 0 do continue if code_colour.a == 0 do continue
} }
draw_text_string_pos_norm(codes[grid[y * GRID_W + x]], demo_ctx.font_demo_raincode, 20, {pos_x, pos_y}, code_colour) draw_text(codes[grid[y * GRID_W + x]], demo_ctx.font_demo_raincode, { pos_x, pos_y }, size = 20, color = code_colour)
} }
// ve.set_colour(&ve_ctx, {1.0, 1.0, 1.0, 1.0}) // ve.set_colour(&ve_ctx, {1.0, 1.0, 1.0, 1.0})
@@ -634,7 +591,7 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
@static fixed_timestep_passed : f32 = 0.0 @static fixed_timestep_passed : f32 = 0.0
fixed_timestep_passed += frame_duration fixed_timestep_passed += frame_duration
fixed_timestep := f32(1.0 / 30.0) fixed_timestep := f32(1.0 / 20.0)
for fixed_timestep_passed > fixed_timestep for fixed_timestep_passed > fixed_timestep
{ {
rotate_current = (rotate_current + 1) % 4 rotate_current = (rotate_current + 1) % 4
@@ -678,28 +635,28 @@ etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
} }
// Draw grid // Draw grid
draw_text_string_pos_norm("Cache pressure test", demo_ctx.font_title, 92, {0.2, current_scroll - (section_start + 0.2)}, COLOR_WHITE) draw_text("Cache pressure test (throttled to 120 hz)", demo_ctx.font_title, { 0.2, current_scroll - (section_start + 0.2) }, size = 92)
for y in 0..< GRID_H do for x in 0 ..< GRID_W for y in 0..< GRID_H do for x in 0 ..< GRID_W
{ {
posx := 0.2 + f32(x) * 0.02 posx := 0.2 + f32(x) * 0.02
posy := current_scroll - (section_start + 0.24 + f32(y) * 0.025) posy := current_scroll - (section_start + 0.24 + f32(y) * 0.025)
c := [5]u8{} c := [5]u8{}
codepoint_to_utf8(c[:], grid[ y * GRID_W + x ]) codepoint_to_utf8(c[:], grid[ y * GRID_W + x ])
draw_text_string_pos_norm(string( c[:] ), demo_ctx.font_demo_chinese, 24, {posx, posy}, COLOR_WHITE) draw_text(string( c[:] ), demo_ctx.font_demo_chinese, { posx, posy }, size = 24)
} }
for y in 0 ..< GRID2_H do for x in 0 ..< GRID2_W { for y in 0 ..< GRID2_H do for x in 0 ..< GRID2_W {
posx := 0.2 + f32(x) * 0.03 posx := 0.2 + f32(x) * 0.03
posy := current_scroll - (section_start + 0.66 + f32(y) * 0.052) posy := current_scroll - (section_start + 0.66 + f32(y) * 0.052)
c := [5]u8{} c := [5]u8{}
codepoint_to_utf8(c[:], grid2[ y * GRID2_W + x ]) codepoint_to_utf8(c[:], grid2[ y * GRID2_W + x ])
draw_text_string_pos_norm(string( c[:] ), demo_ctx.font_demo_grid2, 54, {posx, posy}, COLOR_WHITE) draw_text(string( c[:] ), demo_ctx.font_demo_chinese, { posx, posy }, size = 54)
} }
for y in 0 ..< GRID3_H do for x in 0 ..< GRID3_W { for y in 0 ..< GRID3_H do for x in 0 ..< GRID3_W {
posx := 0.45 + f32(x) * 0.02 posx := 0.45 + f32(x) * 0.02
posy := current_scroll - (section_start + 0.64 + f32(y) * 0.034) posy := current_scroll - (section_start + 0.64 + f32(y) * 0.034)
c := [5]u8{} c := [5]u8{}
codepoint_to_utf8( c[:], grid3[ y * GRID3_W + x ]) codepoint_to_utf8( c[:], grid3[ y * GRID3_W + x ])
draw_text_string_pos_norm(string( c[:] ), demo_ctx.font_demo_grid3, 44, {posx, posy}, COLOR_WHITE) draw_text(string( c[:] ), demo_ctx.font_demo_serif, { posx, posy }, size = 44)
} }
} }

View File

@@ -16,10 +16,10 @@ Shape_Key :: u32
its position should be used for rendering. its position should be used for rendering.
For this library's case it also resolves any content that does not have to be done For this library's case it also resolves any content that does not have to be done
on a per-frame basis for draw list generation. on a per-frame basis for draw list generation:
* Resolve atlas lru codes * atlas lru codes
* Resolve glyph bounds and scale * glyph bounds and scale
* Resolve atlas region the glyph is associated with. * atlas region the glyph is associated with.
Ideally the user should resolve this shape once and cache/store it on their side. Ideally the user should resolve this shape once and cache/store it on their side.
They have the best ability to avoid costly lookups. They have the best ability to avoid costly lookups.
@@ -82,7 +82,7 @@ shaper_init :: proc( ctx : ^Shaper_Context )
assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer") assert( ctx.hb_buffer != nil, "VEFontCache.shaper_init: Failed to create harfbuzz buffer")
} }
shaper_shutdown :: proc( ctx : ^Shaper_Context ) shaper_shutdown :: proc( ctx : ^Shaper_Context )
{ {
if ctx.hb_buffer != nil { if ctx.hb_buffer != nil {
harfbuzz.buffer_destroy( ctx.hb_buffer ) harfbuzz.buffer_destroy( ctx.hb_buffer )
@@ -144,9 +144,9 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
profile(#procedure) profile(#procedure)
// Set script and direction. We use the system's default langauge. // Set script and direction. We use the system's default langauge.
// script = HB_SCRIPT_LATIN // script = HB_SCRIPT_LATIN
harfbuzz.buffer_set_script( buffer, script ) harfbuzz.buffer_set_script ( buffer, script )
harfbuzz.buffer_set_direction( buffer, harfbuzz.script_get_horizontal_direction( script )) harfbuzz.buffer_set_direction( buffer, harfbuzz.script_get_horizontal_direction( script ))
harfbuzz.buffer_set_language( buffer, harfbuzz.language_get_default() ) harfbuzz.buffer_set_language ( buffer, harfbuzz.language_get_default() )
// Perform the actual shaping of this run using HarfBuzz. // Perform the actual shaping of this run using HarfBuzz.
harfbuzz.buffer_set_content_type( buffer, harfbuzz.Buffer_Content_Type.UNICODE ) harfbuzz.buffer_set_content_type( buffer, harfbuzz.Buffer_Content_Type.UNICODE )
@@ -171,12 +171,11 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
position.x = 0.0 position.x = 0.0
position.y -= line_height position.y -= line_height
position.y = floor(position.y) position.y = floor(position.y)
(line_count^) += 1 (line_count^) += 1
continue continue
} }
if abs( font_px_size ) <= adv_snap_small_font_threshold if abs( font_px_size ) <= adv_snap_small_font_threshold {
{ (position^) = ceil( position^ )
(position^) = ceil( position^ )
} }
glyph_pos := position^ glyph_pos := position^
@@ -219,7 +218,10 @@ shaper_shape_harfbuzz :: proc( ctx : ^Shaper_Context, text_utf8 : string, entry
ScriptKind :: harfbuzz.Script ScriptKind :: harfbuzz.Script
special_script : b32 = script == ScriptKind.UNKNOWN || script == ScriptKind.INHERITED || script == ScriptKind.COMMON special_script : b32 = script == ScriptKind.UNKNOWN || script == ScriptKind.INHERITED || script == ScriptKind.COMMON
if special_script || script == current_script || byte_offset == 0 { if special_script \
|| script == current_script \
|| byte_offset == 0
{
harfbuzz.buffer_add( ctx.hb_buffer, hb_codepoint, codepoint == '\n' ? 1 : 0 ) harfbuzz.buffer_add( ctx.hb_buffer, hb_codepoint, codepoint == '\n' ? 1 : 0 )
current_script = special_script ? current_script : script current_script = special_script ? current_script : script
continue continue
@@ -287,15 +289,13 @@ shaper_shape_text_uncached_advanced :: #force_inline proc( ctx : ^Shaper_Context
resize( & output.bounds, len(output.glyph) ) resize( & output.bounds, len(output.glyph) )
profile_begin("atlas_lru_code") profile_begin("atlas_lru_code")
for id, index in output.glyph for id, index in output.glyph {
{
output.atlas_lru_code[index] = atlas_glyph_lru_code(entry.id, font_px_size, id) output.atlas_lru_code[index] = atlas_glyph_lru_code(entry.id, font_px_size, id)
} }
profile_end() profile_end()
profile_begin("bounds & region") profile_begin("bounds & region")
for id, index in output.glyph for id, index in output.glyph {
{
bounds := & output.bounds[index] bounds := & output.bounds[index]
(bounds ^) = parser_get_bounds( entry.parser_info, id ) (bounds ^) = parser_get_bounds( entry.parser_info, id )
bounds_size_scaled := (bounds.p1 - bounds.p0) * font_scale bounds_size_scaled := (bounds.p1 - bounds.p0) * font_scale
@@ -377,15 +377,13 @@ shaper_shape_text_latin :: proc( ctx : ^Shaper_Context,
resize( & output.bounds, len(output.glyph) ) resize( & output.bounds, len(output.glyph) )
profile_begin("atlas_lru_code") profile_begin("atlas_lru_code")
for id, index in output.glyph for id, index in output.glyph {
{
output.atlas_lru_code[index] = atlas_glyph_lru_code(entry.id, font_px_size, id) output.atlas_lru_code[index] = atlas_glyph_lru_code(entry.id, font_px_size, id)
} }
profile_end() profile_end()
profile_begin("bounds & region") profile_begin("bounds & region")
for id, index in output.glyph for id, index in output.glyph {
{
bounds := & output.bounds[index] bounds := & output.bounds[index]
(bounds ^) = parser_get_bounds( entry.parser_info, id ) (bounds ^) = parser_get_bounds( entry.parser_info, id )
bounds_size_scaled := (bounds.p1 - bounds.p0) * font_scale bounds_size_scaled := (bounds.p1 - bounds.p0) * font_scale
@@ -429,12 +427,12 @@ shaper_shape_text_cached :: proc( text_utf8 : string,
shape_cache_idx := lru_get( state, lru_code ) shape_cache_idx := lru_get( state, lru_code )
if shape_cache_idx == -1 if shape_cache_idx == -1
{ {
if shape_cache.next_cache_id < i32(state.capacity) { if shape_cache.next_cache_id < i32(state.capacity){
shape_cache_idx = shape_cache.next_cache_id shape_cache_idx = shape_cache.next_cache_id
shape_cache.next_cache_id += 1 shape_cache.next_cache_id += 1
evicted := lru_put( state, lru_code, shape_cache_idx ) evicted := lru_put( state, lru_code, shape_cache_idx )
} }
else else
{ {
next_evict_idx := lru_get_next_evicted( state ^ ) next_evict_idx := lru_get_next_evicted( state ^ )
assert( next_evict_idx != LRU_Fail_Mask_32 ) assert( next_evict_idx != LRU_Fail_Mask_32 )

View File

@@ -101,7 +101,8 @@ Context :: struct {
// Used by draw interface to super-scale the text by // Used by draw interface to super-scale the text by
// upscaling px_size with px_scalar and then down-scaling // upscaling px_size with px_scalar and then down-scaling
// the draw_list result by the same amount. // the draw_list result by the same amount.
px_scalar : f32, // Improves hinting, positioning, etc. Can make zoomed out text too jagged. px_scalar : f32, // Improves hinting, positioning, etc. Can make zoomed out text too jagged.
zoom_px_interval : f32, // When using zoom, the size can be locked to to this interval (fixes text width jitter)
default_curve_quality : i32, default_curve_quality : i32,
} }
@@ -177,6 +178,7 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
shaper_params := Init_Shaper_Params_Default, shaper_params := Init_Shaper_Params_Default,
alpha_sharpen : f32 = 0.0, alpha_sharpen : f32 = 0.0,
px_scalar : f32 = 1, px_scalar : f32 = 1,
zoom_px_interval : i32 = 2,
// Curve quality to use for a font when unspecified, // Curve quality to use for a font when unspecified,
// Affects step size for bezier curve passes in generate_glyph_pass_draw_list // Affects step size for bezier curve passes in generate_glyph_pass_draw_list
@@ -190,8 +192,9 @@ startup :: proc( ctx : ^Context, parser_kind : Parser_Kind = .STB_TrueType, // N
ctx.backing = allocator ctx.backing = allocator
context.allocator = ctx.backing context.allocator = ctx.backing
ctx.alpha_sharpen = alpha_sharpen ctx.alpha_sharpen = alpha_sharpen
ctx.px_scalar = px_scalar ctx.px_scalar = px_scalar
ctx.zoom_px_interval = f32(zoom_px_interval)
shaper_ctx := & ctx.shaper_ctx shaper_ctx := & ctx.shaper_ctx
shaper_ctx.adv_snap_small_font_threshold = f32(shaper_params.adv_snap_small_font_threshold) shaper_ctx.adv_snap_small_font_threshold = f32(shaper_params.adv_snap_small_font_threshold)
@@ -664,16 +667,15 @@ get_normalized_position_scale :: #force_inline proc "contextless" ( position, sc
} }
// Used to constrain the px_size used in draw calls. // Used to constrain the px_size used in draw calls.
resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, default_size, interval, min, max : f32 ) -> (resolved_size : f32) { resolve_draw_px_size :: #force_inline proc "contextless" ( px_size, interval, min, max : f32 ) -> (resolved_size : f32) {
interval_quotient := 1.0 / f32(interval) interval_quotient := 1.0 / f32(interval)
size := px_size == 0.0 ? default_size : px_size interval_size := round(px_size * interval_quotient) * interval
even_size := round(size * interval_quotient) * interval resolved_size = clamp( interval_size, min, max )
resolved_size = clamp( even_size, min, max )
return return
} }
set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar } set_alpha_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.alpha_sharpen = scalar }
set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar } set_px_scalar :: #force_inline proc( ctx : ^Context, scalar : f32 ) { assert(ctx != nil); ctx.px_scalar = scalar }
// During a shaping pass on text, will snap each glyph's position via ceil. // During a shaping pass on text, will snap each glyph's position via ceil.
set_snap_glyph_shape_position :: #force_inline proc( ctx : ^Context, should_snap : b32 ) { set_snap_glyph_shape_position :: #force_inline proc( ctx : ^Context, should_snap : b32 ) {
@@ -695,7 +697,7 @@ set_snap_glyph_render_height :: #force_inline proc( ctx : ^Context, should_snap
| | | | | |
| | | | | |
| | Glyph Quad | | | Glyph Quad |
| | +---------+ < scale.y | | | +--------+ < scale.y |
| | | ** | * | | | | | ** | * | |
| | | * * | **** | | | | | * * | **** | |
| | | **** | * * | | | | | **** | * * | |
@@ -717,12 +719,12 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
colour : RGBAN, colour : RGBAN,
position : Vec2, position : Vec2,
scale : Vec2, scale : Vec2,
zoom : f32, // TODO(Ed): Implement zoom support
shape : Shaped_Text shape : Shaped_Text
) )
{ {
profile(#procedure) profile(#procedure)
assert( ctx != nil ) assert( ctx != nil )
// TODO(Ed): This should be taken from the shape instead (you cannot use a different font with a shape)
assert( font >= 0 && int(font) < len(ctx.entries) ) assert( font >= 0 && int(font) < len(ctx.entries) )
entry := ctx.entries[ font ] entry := ctx.entries[ font ]
@@ -730,9 +732,9 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
adjusted_colour := colour adjusted_colour := colour
adjusted_colour.a += ctx.alpha_sharpen adjusted_colour.a += ctx.alpha_sharpen
target_px_size := px_size * ctx.px_scalar target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar) target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
@@ -771,13 +773,13 @@ draw_text_shape_normalized_space :: #force_inline proc( ctx : ^Context,
*/ */
@(optimization_mode = "favor_size") @(optimization_mode = "favor_size")
draw_text_normalized_space :: proc( ctx : ^Context, draw_text_normalized_space :: proc( ctx : ^Context,
font : Font_ID, font : Font_ID,
px_size : f32, px_size : f32,
colour : RGBAN, colour : RGBAN,
position : Vec2, position : Vec2,
scale : Vec2, scale : Vec2,
zoom : f32, // TODO(Ed): Implement Zoom support text_utf8 : string,
text_utf8 : string shaper_proc : $Shaper_Shape_Text_Uncached_Proc = shaper_shape_text_uncached_advanced
) )
{ {
profile(#procedure) profile(#procedure)
@@ -792,16 +794,16 @@ draw_text_normalized_space :: proc( ctx : ^Context,
adjusted_colour.a += ctx.alpha_sharpen adjusted_colour.a += ctx.alpha_sharpen
// Does nothing when px_scalar is 1.0 // Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar target_px_size := px_size * ctx.px_scalar
target_scale := scale * (1 / ctx.px_scalar) target_scale := scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font, font,
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
shaper_shape_text_uncached_advanced shaper_proc
) )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
@@ -833,8 +835,10 @@ draw_text_normalized_space :: proc( ctx : ^Context,
| | | | | |
| (0.0, 0.0) +----------------------------------+ | (0.0, 0.0) +----------------------------------+
view : The coordinate space is scaled to the view. Positions will be snapped to it.
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned) position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size. <-> scale : Scale the glyph beyond its default scaling from its px_size.
zoom : Will affect the scale similar to how the zoom on a canvas would behave.
*/ */
// @(optimization_mode="favor_size") // @(optimization_mode="favor_size")
draw_text_shape_view_space :: #force_inline proc( ctx : ^Context, draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
@@ -844,12 +848,13 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
view : Vec2, view : Vec2,
position : Vec2, position : Vec2,
scale : Vec2, scale : Vec2,
zoom : f32, // TODO(Ed): Implement zoom support zoom : f32,
shape : Shaped_Text shape : Shaped_Text
) )
{ {
profile(#procedure) profile(#procedure)
assert( ctx != nil ) assert( ctx != nil )
// TODO(Ed): This should be taken from the shape instead (you cannot use a different font with a shape)
assert( font >= 0 && int(font) < len(ctx.entries) ) assert( font >= 0 && int(font) < len(ctx.entries) )
assert( ctx.px_scalar > 0.0 ) assert( ctx.px_scalar > 0.0 )
@@ -858,12 +863,20 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
adjusted_colour := colour adjusted_colour := colour
adjusted_colour.a = 1.0 + ctx.alpha_sharpen adjusted_colour.a = 1.0 + ctx.alpha_sharpen
norm_position, norm_scale := get_normalized_position_scale( position, scale, view ) // Does nothing when zoom is 1.0
zoom_px_size := px_size * zoom
resolved_size := resolve_draw_px_size( zoom_px_size, ctx.zoom_px_interval, 2, 999.0 )
zoom_diff_scalar := 1 + (zoom_px_size - resolved_size) * (1 / resolved_size)
zoom_scale := zoom_diff_scalar * scale
zoom_scale.x = clamp(zoom_scale.x, 0, view.x)
zoom_scale.y = clamp(zoom_scale.y, 0, view.y)
norm_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view )
// Does nothing if px_scalar is 1.0 // Does nothing if px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar) target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
@@ -895,19 +908,22 @@ draw_text_shape_view_space :: #force_inline proc( ctx : ^Context,
| | | | | |
| (0.0, 0.0) +----------------------------------+ | (0.0, 0.0) +----------------------------------+
view : The coordinate space is scaled to the view. Positions will be snapped to it.
position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned) position: Anchor point in normalized space (where the bottom-right vertex of the first glyph quad will be positioned)
<-> scale : Scale the glyph beyond its default scaling from its px_size. <-> scale : Scale the glyph beyond its default scaling from its px_size.
zoom : Will affect the scale similar to how the zoom on a canvas would behave.
*/ */
// @(optimization_mode = "favor_size") // @(optimization_mode = "favor_size")
draw_text_view_space :: proc(ctx : ^Context, draw_text_view_space :: proc(ctx : ^Context,
font : Font_ID, font : Font_ID,
px_size : f32, px_size : f32,
colour : RGBAN, colour : RGBAN,
view : Vec2, view : Vec2,
position : Vec2, position : Vec2,
scale : Vec2, scale : Vec2,
zoom : f32, // TODO(Ed): Implement Zoom support zoom : f32,
text_utf8 : string text_utf8 : string,
shaper_proc : $Shaper_Shape_Text_Uncached_Proc = shaper_shape_text_uncached_advanced
) )
{ {
profile(#procedure) profile(#procedure)
@@ -922,19 +938,27 @@ draw_text_view_space :: proc(ctx : ^Context,
adjusted_colour := colour adjusted_colour := colour
adjusted_colour.a += ctx.alpha_sharpen adjusted_colour.a += ctx.alpha_sharpen
norm_position, norm_scale := get_normalized_position_scale( position, scale, view ) // Does nothing when zoom is 1.0
zoom_px_size := px_size * zoom
resolved_size := resolve_draw_px_size( zoom_px_size, ctx.zoom_px_interval, 2, 999.0 )
zoom_diff_scalar := 1 + (zoom_px_size - resolved_size) * (1 / resolved_size)
zoom_scale := zoom_diff_scalar * scale
zoom_scale.x = clamp(zoom_scale.x, 0, view.x)
zoom_scale.y = clamp(zoom_scale.y, 0, view.y)
target_position, norm_scale := get_normalized_position_scale( position, zoom_scale, view )
// Does nothing if px_scalar is 1.0 // Does nothing if px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar target_px_size := resolved_size * ctx.px_scalar
target_scale := norm_scale * (1 / ctx.px_scalar) target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font, font,
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
shaper_shape_text_uncached_advanced shaper_proc
) )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
@@ -942,7 +966,7 @@ draw_text_view_space :: proc(ctx : ^Context,
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
norm_position, target_position,
target_scale, target_scale,
) )
} }
@@ -962,8 +986,8 @@ absolute_scale := peek(stack.scale ) * scale
| | | **** | * * | | | | | **** | * * | |
| | | * * | **** | | | | | * * | **** | |
| | +---------+--------+.... | | | +---------+--------+.... |
| | absolute ^ ^ absolute | | | absolute ^ ^ absolute |
| | position scale.x | | | position scale.x |
| | | | | |
| | | | | |
| | | | | |
@@ -997,28 +1021,34 @@ draw_shape :: proc( ctx : ^Context, position, scale : Vec2, shape : Shaped_Text
adjusted_colour := peek(stack.colour) adjusted_colour := peek(stack.colour)
adjusted_colour.a += ctx.alpha_sharpen adjusted_colour.a += ctx.alpha_sharpen
// TODO(Ed): Implement zoom for draw_text
zoom := peek(stack.zoom)
absolute_position := peek(stack.position) + position
absolute_scale := peek(stack.scale) * scale
adjusted_position := get_snapped_position( absolute_position, view )
px_size := peek(stack.font_size) px_size := peek(stack.font_size)
// Does nothing when zoom is 1.0
zoom := peek(stack.zoom)
zoom_px_size := zoom * px_size
resolved_size := resolve_draw_px_size( zoom_px_size, ctx.zoom_px_interval, 2, 999.0 )
zoom_diff_scalar := 1 + (zoom_px_size - resolved_size) * (1 / resolved_size)
zoom_scale := zoom_diff_scalar * scale
zoom_scale.x = clamp(zoom_scale.x, 0, view.x)
zoom_scale.y = clamp(zoom_scale.y, 0, view.y)
absolute_position := peek(stack.position) + position
absolute_scale := peek(stack.scale) * zoom_scale
target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view )
// Does nothing when px_scalar is 1.0 // Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar target_px_size := resolved_size * ctx.px_scalar
target_scale := absolute_scale * (1 / ctx.px_scalar) target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
adjusted_colour, adjusted_colour,
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
adjusted_position, target_position,
target_scale, target_scale,
) )
} }
@@ -1038,15 +1068,17 @@ absolute_scale := peek(stack.scale ) * scale
| | | **** | * * | | | | | **** | * * | |
| | | * * | **** | | | | | * * | **** | |
| | +---------+--------+.... | | | +---------+--------+.... |
| | absolute ^ ^ absolute | | | absolute ^ ^ absolute |
| | position scale.x | | | position scale.x |
| | | | | |
| | | | | |
| | | | | |
| (0.0, 0.0) +-----------------------------------+ | (0.0, 0.0) +-----------------------------------+
*/ */
// @(optimization_mode = "favor_size") // @(optimization_mode = "favor_size")
draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string ) draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string,
shaper_proc : $Shaper_Shape_Text_Uncached_Proc = shaper_shape_text_uncached_advanced
)
{ {
profile(#procedure) profile(#procedure)
assert( ctx != nil ) assert( ctx != nil )
@@ -1073,27 +1105,33 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
adjusted_colour := peek(stack.colour) adjusted_colour := peek(stack.colour)
adjusted_colour.a += ctx.alpha_sharpen adjusted_colour.a += ctx.alpha_sharpen
// TODO(Ed): Implement zoom for draw_text px_size := peek(stack.font_size)
zoom := peek(stack.zoom)
// Does nothing when zoom is 1.0
zoom := peek(stack.zoom)
zoom_px_size := zoom * px_size
resolved_size := resolve_draw_px_size( zoom_px_size, ctx.zoom_px_interval , 2, 999.0 )
zoom_diff_scalar := 1 + (zoom_px_size - resolved_size) * (1 / resolved_size)
zoom_scale := zoom_diff_scalar * scale
zoom_scale.x = clamp(zoom_scale.x, 0, view.x)
zoom_scale.y = clamp(zoom_scale.y, 0, view.y)
absolute_position := peek(stack.position) + position absolute_position := peek(stack.position) + position
absolute_scale := peek(stack.scale) * scale absolute_scale := peek(stack.scale) * scale
adjusted_position := get_snapped_position( absolute_position, view ) target_position, norm_scale := get_normalized_position_scale( absolute_position, absolute_scale, view )
px_size := peek(stack.font_size)
// Does nothing when px_scalar is 1.0 // Does nothing when px_scalar is 1.0
target_px_size := px_size * ctx.px_scalar target_px_size := resolved_size * ctx.px_scalar
target_scale := absolute_scale * (1 / ctx.px_scalar) target_scale := norm_scale * (1 / ctx.px_scalar)
target_font_scale := parser_scale( entry.parser_info, target_px_size ) target_font_scale := parser_scale( entry.parser_info, target_px_size )
shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size), shape := shaper_shape_text_cached( text_utf8, & ctx.shaper_ctx, & ctx.shape_cache, ctx.atlas, vec2(ctx.glyph_buffer.size),
font, font,
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
shaper_shape_text_uncached_advanced shaper_proc
) )
ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer, ctx.cursor_pos = generate_shape_draw_list( & ctx.draw_list, shape, & ctx.atlas, & ctx.glyph_buffer,
ctx.px_scalar, ctx.px_scalar,
@@ -1101,7 +1139,7 @@ draw_text :: proc( ctx : ^Context, position, scale : Vec2, text_utf8 : string )
entry, entry,
target_px_size, target_px_size,
target_font_scale, target_font_scale,
adjusted_position, target_position,
target_scale, target_scale,
) )
} }