Finished initial implementation of sokol demo

This commit is contained in:
2024-07-01 17:39:00 -04:00
parent b3f2add7d1
commit 6d4745700f
2 changed files with 489 additions and 45 deletions

View File

@@ -5,6 +5,7 @@ import "core:path/filepath"
file_name_from_path :: filepath.short_stem file_name_from_path :: filepath.short_stem
import "core:fmt" import "core:fmt"
import "core:math" import "core:math"
import "core:math/rand"
import "core:mem" import "core:mem"
import "core:os" import "core:os"
import "core:strings" import "core:strings"
@@ -33,22 +34,21 @@ normalize_rgba8 :: #force_inline proc( color : RGBA8 ) -> RGBAN {
return result return result
} }
Color_Blue :: RGBA8 { 90, 90, 230, 255 } COLOR_BLUE :: RGBA8 { 90, 90, 230, 255 }
Color_Red :: RGBA8 { 230, 90, 90, 255 } COLOR_RED :: RGBA8 { 230, 90, 90, 255 }
Color_White :: RGBA8 { 255, 255, 255, 255 } COLOR_WHITE :: RGBA8 { 255, 255, 255, 255 }
Font_Provider_Use_Freetype :: false FONT_LARGEST_PIXEL_SIZE :: 400
Font_Largest_Px_Size :: 154 FONT_SIZE_INTERVAL :: 2
Font_Size_Interval :: 2
Font_Default :: FontID { "" } FONT_DEFAULT :: FontID { "" }
Font_Default_Size :: 12.0 FONT_DEFAULT_SIZEZ :: 12.0
Font_Load_Use_Default_Size :: -1 FONT_LOAD_USE_DEFAULT_SIZE :: -1
Font_Load_Gen_ID :: "" FONT_LOAD_GEN_ID :: ""
// Working directory assumed to be the build folder // Working directory assumed to be the build folder
Path_Fonts :: "../fonts/" PATH_FONTS :: "../fonts/"
FontID :: struct { FontID :: struct {
label : string, label : string,
@@ -57,7 +57,7 @@ FontID :: struct {
FontDef :: struct { FontDef :: struct {
path_file : string, path_file : string,
default_size : i32, default_size : i32,
size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.FontID, size_table : [FONT_LARGEST_PIXEL_SIZE / FONT_SIZE_INTERVAL] ve.FontID,
} }
Demo_Context :: struct { Demo_Context :: struct {
@@ -65,16 +65,38 @@ Demo_Context :: struct {
render_ctx : ve_sokol.Context, render_ctx : ve_sokol.Context,
font_ids : map[string]FontDef, font_ids : map[string]FontDef,
font_firacode : FontID, // Values between 1, & -1 on Y axis
mouse_scroll : Vec2,
screen_size : [2]f32 font_firacode : FontID,
font_logo : FontID,
font_title : FontID,
font_print : FontID,
font_mono : FontID,
font_small : FontID,
font_demo_sans : FontID,
font_demo_serif : FontID,
font_demo_script : FontID,
font_demo_mono : FontID,
font_demo_chinese : FontID,
font_demo_japanese : FontID,
font_demo_korean : FontID,
font_demo_thai : FontID,
font_demo_arabic : FontID,
font_demo_hebrew : FontID,
font_demo_raincode : FontID,
font_demo_grid2 : FontID,
font_demo_grid3 : FontID,
screen_size : [2]f32,
} }
demo_ctx : Demo_Context demo_ctx : Demo_Context
font_load :: proc(path_file : string, font_load :: proc(path_file : string,
default_size : i32 = Font_Load_Use_Default_Size, default_size : i32 = FONT_LOAD_USE_DEFAULT_SIZE,
desired_id : string = Font_Load_Gen_ID desired_id : string = FONT_LOAD_GEN_ID,
curve_quality : u32 = 3,
) -> FontID ) -> FontID
{ {
msg := fmt.println("Loading font: %v", path_file) msg := fmt.println("Loading font: %v", path_file)
@@ -96,17 +118,17 @@ font_firacode : FontID
default_size := default_size default_size := default_size
if default_size < 0 { if default_size < 0 {
default_size = Font_Default_Size default_size = FONT_DEFAULT_SIZEZ
} }
def.path_file = path_file def.path_file = path_file
def.default_size = default_size def.default_size = default_size
for font_size : i32 = clamp( Font_Size_Interval, 2, Font_Size_Interval ); font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval for font_size : i32 = clamp( FONT_SIZE_INTERVAL, 2, FONT_SIZE_INTERVAL ); font_size <= FONT_LARGEST_PIXEL_SIZE; font_size += FONT_SIZE_INTERVAL
{ {
id := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval) id := (font_size / FONT_SIZE_INTERVAL) + (font_size % FONT_SIZE_INTERVAL)
ve_id := & def.size_table[id - 1] ve_id := & def.size_table[id - 1]
ve_ret_id := ve.load_font( & demo_ctx.ve_ctx, desired_id, font_data, f32(font_size) ) ve_ret_id := ve.load_font( & demo_ctx.ve_ctx, desired_id, font_data, f32(font_size), curve_quality )
(ve_id^) = ve_ret_id (ve_id^) = ve_ret_id
} }
@@ -120,10 +142,10 @@ font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Siz
{ {
def := demo_ctx.font_ids[ id.label ] def := demo_ctx.font_ids[ id.label ]
size := size == 0.0 ? f32(def.default_size) : size size := size == 0.0 ? f32(def.default_size) : size
even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval) even_size := math.round(size * (1.0 / f32(FONT_SIZE_INTERVAL))) * f32(FONT_SIZE_INTERVAL)
resolved_size = clamp( i32( even_size), 2, Font_Largest_Px_Size ) resolved_size = clamp( i32( even_size), 2, FONT_LARGEST_PIXEL_SIZE )
id := (resolved_size / Font_Size_Interval) + (resolved_size % Font_Size_Interval) id := (resolved_size / FONT_SIZE_INTERVAL) + (resolved_size % FONT_SIZE_INTERVAL)
ve_id = def.size_table[ id - 1 ] ve_id = def.size_table[ id - 1 ]
return return
} }
@@ -143,7 +165,7 @@ get_font_vertical_metrics :: #force_inline proc ( font : FontID, font_size := Fo
} }
// 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, id : FontID, size : f32, pos : Vec2, color := Color_White, scale : f32 = 1.0 ) draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE, scale : f32 = 1.0 )
{ {
width := demo_ctx.screen_size.x width := demo_ctx.screen_size.x
height := demo_ctx.screen_size.y height := demo_ctx.screen_size.y
@@ -157,12 +179,44 @@ draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, po
} }
// Draw text using a string and extent-based screen coordinates // Draw text using a string and extent-based screen coordinates
draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := Color_White ) { draw_text_string_pos_extent :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := COLOR_WHITE ) {
render_pos := pos + demo_ctx.screen_size * 0.5 render_pos := pos + demo_ctx.screen_size * 0.5
normalized_pos := render_pos * (1.0 / demo_ctx.screen_size) normalized_pos := render_pos * (1.0 / demo_ctx.screen_size)
draw_text_string_pos_norm( content, id, size, normalized_pos, color ) draw_text_string_pos_norm( content, id, size, normalized_pos, color )
} }
OVER_SAMPLE_ZOOM : f32 : 2.0 // Adjust this value as needed
// Adapt the draw_text_string_pos_extent_zoomed procedure
draw_text_zoomed_norm :: proc(content : string, id : FontID, size : f32, pos : Vec2, zoom : f32, color := COLOR_WHITE)
{
screen_size := demo_ctx.screen_size
screen_scale := Vec2{1.0 / screen_size.x, 1.0 / screen_size.y}
zoom_adjust_size := size * zoom
// Over-sample font-size
zoom_adjust_size *= OVER_SAMPLE_ZOOM
ve_id, resolved_size := font_provider_resolve_draw_id(id, zoom_adjust_size)
text_scale := screen_scale
{
f32_resolved_size := f32(resolved_size)
diff_scalar := 1 + (zoom_adjust_size - f32_resolved_size) / f32_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)
}
// Down-sample back
text_scale /= OVER_SAMPLE_ZOOM
color_norm := normalize_rgba8(color)
ve.set_colour(&demo_ctx.ve_ctx, color_norm)
ve.draw_text(&demo_ctx.ve_ctx, ve_id, content, pos, text_scale)
}
sokol_app_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr { sokol_app_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = runtime.default_context() context = runtime.default_context()
block, error := mem.alloc( int(size), allocator = context.allocator ) block, error := mem.alloc( int(size), allocator = context.allocator )
@@ -217,15 +271,57 @@ init :: proc "c" ()
case .DUMMY: fmt.println(">> using dummy backend") case .DUMMY: fmt.println(">> using dummy backend")
} }
ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator ) ve.startup( & demo_ctx.ve_ctx, .STB_TrueType, allocator = context.allocator, snap_shape_position = false )
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 = 1024 * 1024, index_cap = 1024 * 1024 )
error : mem.Allocator_Error error : mem.Allocator_Error
demo_ctx.font_ids, error = make( map[string]FontDef, 256 ) demo_ctx.font_ids, error = make( map[string]FontDef, 256 )
assert( error == .None, "Failed to allocate demo_ctx.font_ids" ) assert( error == .None, "Failed to allocate demo_ctx.font_ids" )
path_firacode := strings.concatenate( { Path_Fonts, "FiraCode-Regular.ttf" } ) path_sawarabi_mincho := strings.concatenate({ PATH_FONTS, "SawarabiMincho-Regular.ttf" })
demo_ctx.font_firacode = font_load( path_firacode, 16.0, "FiraCode" ) path_open_sans := strings.concatenate({ PATH_FONTS, "OpenSans-Regular.ttf" })
path_noto_sans_jp := strings.concatenate({ PATH_FONTS, "NotoSansJP-Light.otf" })
path_ubuntu_mono := strings.concatenate({ PATH_FONTS, "UbuntuMono-Regular.ttf" })
path_roboto := strings.concatenate({ PATH_FONTS, "Roboto-Regular.ttf" })
path_bitter := strings.concatenate({ PATH_FONTS, "Bitter-Regular.ttf" })
path_dancing_script := strings.concatenate({ PATH_FONTS, "DancingScript-Regular.ttf" })
path_nova_mono := strings.concatenate({ PATH_FONTS, "NovaMono-Regular.ttf" })
path_noto_serif_sc := strings.concatenate({ PATH_FONTS, "NotoSerifSC-Regular.otf" })
path_nanum_pen_script := strings.concatenate({ PATH_FONTS, "NanumPenScript-Regular.ttf" })
path_krub := strings.concatenate({ PATH_FONTS, "Krub-Regular.ttf" })
path_tajawal := strings.concatenate({ PATH_FONTS, "Tajawal-Regular.ttf" })
path_david_libre := strings.concatenate({ PATH_FONTS, "DavidLibre-Regular.ttf" })
path_noto_sans_jp_reg := strings.concatenate({ PATH_FONTS, "NotoSansJP-Regular.otf" })
path_firacode := strings.concatenate({ PATH_FONTS, "FiraCode-Regular.ttf" })
using demo_ctx
font_logo = font_load(path_sawarabi_mincho, 330.0, "SawarabiMincho", 6 )
font_title = font_load(path_open_sans, 92.0, "OpenSans", 12 )
font_print = font_load(path_noto_sans_jp, 19.0, "NotoSansJP")
font_mono = font_load(path_ubuntu_mono, 21.0, "UbuntuMono")
font_small = font_load(path_roboto, 10.0, "Roboto")
font_demo_sans = font_load(path_open_sans, 18.0, "OpenSans")
font_demo_serif = font_load(path_bitter, 18.0, "Bitter")
font_demo_script = font_load(path_dancing_script, 22.0, "DancingScript")
font_demo_mono = font_load(path_nova_mono, 18.0, "NovaMono")
font_demo_chinese = font_load(path_noto_serif_sc, 24.0, "NotoSerifSC")
font_demo_japanese = font_load(path_sawarabi_mincho, 24.0, "SawarabiMincho")
font_demo_korean = font_load(path_nanum_pen_script, 36.0, "NanumPenScript")
font_demo_thai = font_load(path_krub, 24.0, "Krub")
font_demo_arabic = font_load(path_tajawal, 24.0, "Tajawal")
font_demo_hebrew = font_load(path_david_libre, 22.0, "DavidLibre")
font_demo_raincode = font_load(path_noto_sans_jp_reg, 20.0, "NotoSansJPRegular")
font_demo_grid2 = font_load(path_noto_serif_sc, 54.0, "NotoSerifSC")
font_demo_grid3 = font_load(path_bitter, 44.0, "Bitter")
font_firacode = font_load(path_firacode, 16.0, "FiraCode", 12 )
}
event :: proc "c" (sokol_event : ^app.Event)
{
#partial switch sokol_event.type {
case .MOUSE_SCROLL:
demo_ctx.mouse_scroll = clamp(sokol_event.scroll_y, -1, 1) * -1
}
} }
frame :: proc "c" () frame :: proc "c" ()
@@ -235,43 +331,391 @@ frame :: proc "c" ()
demo_ctx.screen_size = { app.widthf(), app.heightf() } demo_ctx.screen_size = { app.widthf(), app.heightf() }
pass_action : gfx.Pass_Action; pass_action : gfx.Pass_Action;
pass_action.colors[0] = { load_action = .CLEAR, clear_value = { 0.18 * 0.18, 0.204 * 0.204, 0.251 * 0.251, 1.0 } } pass_action.colors[0] = { load_action = .CLEAR, clear_value = { 0.18, 0.204, 0.251, 1.0 } }
gfx.begin_pass({ action = pass_action, swapchain = glue.swapchain() }) gfx.begin_pass({ action = pass_action, swapchain = glue.swapchain() })
gfx.end_pass() gfx.end_pass()
{ {
ve.configure_snap( & demo_ctx.ve_ctx, u32(demo_ctx.screen_size.x), u32(demo_ctx.screen_size.y) ) ve.configure_snap( & demo_ctx.ve_ctx, u32(demo_ctx.screen_size.x), u32(demo_ctx.screen_size.y) )
ve.set_colour( & demo_ctx.ve_ctx, ve.Colour { 1.0, 1.0, 1.0, 1.0 }) ve.set_colour( & demo_ctx.ve_ctx, ve.Colour { 1.0, 1.0, 1.0, 1.0 })
ve_id, size := font_provider_resolve_draw_id( demo_ctx.font_firacode, 100 ) using demo_ctx
ve.draw_text(
& demo_ctx.ve_ctx,
ve_id,
"Hello VE FONT CACHE???",
Vec2{0.1, 0.1},
Vec2{1 / demo_ctx.screen_size.x, 1 / demo_ctx.screen_size.y }
)
draw_text_string_pos_extent( "Hello VEFontCache!", demo_ctx.font_firacode, 48, {0, 0}, Color_White ) // Smooth scrolling implementation
draw_text_string_pos_norm( "Hello VEFontCache!", demo_ctx.font_firacode, 24, {0, 0}, Color_White ) @static demo_autoscroll := true
@static current_scroll : f32 = 0.0
@static mouse_down_pos : f32 = -1.0
@static mouse_down_scroll : f32 = -1.0
@static mouse_prev_pos : f32 = 0.0
@static scroll_velocity : f32 = 0.0
frame_duration := cast(f32) app.frame_duration()
scroll_velocity += mouse_scroll.y * 0.05
mouse_down_pos = -1.0
substep_dt := frame_duration / 4.0
for _ in 0 ..< 4 {
scroll_velocity *= math.exp(-3.5 * substep_dt)
current_scroll += scroll_velocity * substep_dt * 18.0
}
if demo_autoscroll {
current_scroll += 0.05 * frame_duration
}
mouse_scroll = {} // Reset mouse scroll
// Clamp scroll value if needed
current_scroll = clamp(current_scroll, 0, 5.2) // Adjust max value as needed
// Frametime display
frametime_text := fmt.tprintf("Frametime %v", frame_duration)
draw_text_string_pos_norm(frametime_text, font_title, 0, {0.0, 0.0}, COLOR_WHITE)
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.
It aims to:
• Be fast and simple to integrate.
• Take advantage of modern GPU power.
• Be backend agnostic and easy to port to any API such as Vulkan, DirectX, OpenGL.
• Load TTF & OTF file formats directly.
• Use only runtime cache with no offline calculation.
• Render glyphs at reasonable quality at a wide range of hb_font sizes.
• Support a good amount of internationalisation. そうですね!
• Support cached text shaping with HarfBuzz with simple Latin-style fallback.
• Load and unload fonts at any time.`
draw_text_string_pos_norm("ゑ", font_logo, 330, {0.4, current_scroll}, COLOR_WHITE)
draw_text_string_pos_norm("VEFontCache Demo", font_title, 92, {0.2, current_scroll - 0.1}, COLOR_WHITE)
draw_text_string_pos_norm(intro, font_print, 19, {0.2, current_scroll - 0.14}, COLOR_WHITE)
}
section_start : f32 = 0.42
section_end : f32 = 2.32
if current_scroll > section_start && current_scroll < section_end {
how_it_works := `Glyphs are GPU rasterised with 16x supersampling. This method is a simplification of "Easy Scalable Text Rendering on the GPU",
by Evan Wallace, making use of XOR blending. Bézier curves are handled via brute force triangle tessellation; even 6 triangles per
curve only generates < 300 triangles, which is nothing for modern GPUs! This avoids complex frag shader for reasonable quality.
Texture atlas caching uses naïve grid placement; this wastes a lot of space but ensures interchangeable cache slots allowing for
LRU ( Least Recently Used ) caching scheme to be employed.
The hb_font atlas is a single 4k x 2k R8 texture divided into 4 regions:`
caching_strategy := ` 2k
--------------------
| | |
| A | |
| | | 2
|---------| C | k
| | |
1k | B | |
| | |
--------------------
| |
| |
| | 2
| D | k
| |
| |
| |
--------------------
Region A = 32x32 caches, 1024 glyphs
Region B = 32x64 caches, 512 glyphs
Region C = 64x64 caches, 512 glyphs
Region D = 128x128 caches, 256 glyphs`
how_it_works2 := `Region A is designed for small glyphs, Region B is for tall glyphs, Region C is for large glyphs, and Region D for huge glyphs.
Glyphs are first rendered to an intermediate 2k x 512px R8 texture. This allows for minimum 4 Region D glyphs supersampled at
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.`
draw_text_string_pos_norm("How it works", font_title, 92, {0.2, current_scroll - (section_start + 0.06)}, COLOR_WHITE)
draw_text_string_pos_norm(how_it_works, font_print, 19, {0.2, current_scroll - (section_start + 0.1)}, COLOR_WHITE)
draw_text_string_pos_norm(caching_strategy, demo_ctx.font_mono, 21, {0.28, current_scroll - (section_start + 0.32)}, COLOR_WHITE)
draw_text_string_pos_norm(how_it_works2, font_print, 19, {0.2, current_scroll - (section_start + 0.82)}, COLOR_WHITE)
}
// Showcase section
section_start, section_end = 1.2, 3.2
if current_scroll > section_start && current_scroll < section_end
{
font_family_test := `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Est ullamcorper eget nulla facilisi
etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
draw_text_string_pos_norm("Showcase", font_title, 92, {0.2, current_scroll - (section_start + 0.2)}, COLOR_WHITE)
draw_text_string_pos_norm("This is a showcase demonstrating different hb_font categories and languages.", font_print, 19, {0.2, current_scroll - (section_start + 0.24)}, COLOR_WHITE)
draw_text_string_pos_norm("Sans serif", font_print, 19, {0.2, current_scroll - (section_start + 0.28)}, COLOR_WHITE)
draw_text_string_pos_norm(font_family_test, font_demo_sans, 18, {0.3, current_scroll - (section_start + 0.28)}, COLOR_WHITE)
draw_text_string_pos_norm("Serif", font_print, 19, {0.2, current_scroll - (section_start + 0.36)}, COLOR_WHITE)
draw_text_string_pos_norm(font_family_test, font_demo_serif, 18, {0.3, current_scroll - (section_start + 0.36)}, COLOR_WHITE)
draw_text_string_pos_norm("Script", font_print, 19, {0.2, current_scroll - (section_start + 0.44)}, COLOR_WHITE)
draw_text_string_pos_norm(font_family_test, font_demo_script, 22, {0.3, current_scroll - (section_start + 0.44)}, COLOR_WHITE)
draw_text_string_pos_norm("Monospace", font_print, 19, {0.2, current_scroll - (section_start + 0.52)}, COLOR_WHITE)
draw_text_string_pos_norm(font_family_test, font_demo_mono, 18, {0.3, current_scroll - (section_start + 0.52)}, COLOR_WHITE)
draw_text_string_pos_norm("Small", font_print, 19, {0.2, current_scroll - (section_start + 0.60)}, COLOR_WHITE)
draw_text_string_pos_norm(font_family_test, font_small, 10, {0.3, current_scroll - (section_start + 0.60)}, COLOR_WHITE)
draw_text_string_pos_norm("Greek", font_print, 19, {0.2, current_scroll - (section_start + 0.72)}, COLOR_WHITE)
draw_text_string_pos_norm("Ήταν απλώς θέμα χρόνου.", font_demo_sans, 18, {0.3, current_scroll - (section_start + 0.72)}, COLOR_WHITE)
draw_text_string_pos_norm("Vietnamese", font_print, 19, {0.2, current_scroll - (section_start + 0.76)}, COLOR_WHITE)
draw_text_string_pos_norm("Bầu trời trong xanh thăm thẳm, không một gợn mây.", font_demo_sans, 18, {0.3, current_scroll - (section_start + 0.76)}, COLOR_WHITE)
draw_text_string_pos_norm("Thai", font_print, 19, {0.2, current_scroll - (section_start + 0.80)}, COLOR_WHITE)
draw_text_string_pos_norm("การเดินทางขากลับคงจะเหงา", font_demo_thai, 24, {0.3, current_scroll - (section_start + 0.80)}, COLOR_WHITE)
draw_text_string_pos_norm("Chinese", font_print, 19, {0.2, current_scroll - (section_start + 0.84)}, COLOR_WHITE)
draw_text_string_pos_norm("床前明月光 疑是地上霜 举头望明月 低头思故乡", font_demo_chinese, 24, {0.3, current_scroll - (section_start + 0.84)}, COLOR_WHITE)
draw_text_string_pos_norm("Japanese", font_print, 19, {0.2, current_scroll - (section_start + 0.88)}, COLOR_WHITE)
draw_text_string_pos_norm("ぎょしょうとナレズシの研究 モンスーン・アジアの食事文化", font_demo_japanese, 24, {0.3, current_scroll - (section_start + 0.88)}, COLOR_WHITE)
draw_text_string_pos_norm("Korean", font_print, 19, {0.2, current_scroll - (section_start + 0.92)}, COLOR_WHITE)
draw_text_string_pos_norm("그들의 장비와 기구는 모두 살아 있다.", font_demo_korean, 36, {0.3, current_scroll - (section_start + 0.92)}, COLOR_WHITE)
draw_text_string_pos_norm("Arabic", font_print, 19, {0.2, current_scroll - (section_start + 0.96)}, COLOR_WHITE)
draw_text_string_pos_norm("حب السماء لا تمطر غير الأحلام. This one needs HarfBuzz to work!", font_demo_arabic, 24, {0.3, current_scroll - (section_start + 0.96)}, COLOR_WHITE)
draw_text_string_pos_norm("Hebrew", font_print, 19, {0.2, current_scroll - (section_start + 1.0)}, COLOR_WHITE)
draw_text_string_pos_norm("אז הגיע הלילה של כוכב השביט הראשון. This one needs HarfBuzz to work!", font_demo_hebrew, 22, {0.3, current_scroll - (section_start + 1.0)}, COLOR_WHITE)
}
// Raincode Demo
section_start = 2.1
section_end = section_start + 2.23
if current_scroll > section_start && current_scroll < section_end
{
GRID_W :: 80
GRID_H :: 50
NUM_RAINDROPS :: GRID_W / 3
@static init_grid := false
@static grid : [ GRID_W * GRID_H ]int
@static grid_age : [ GRID_W * GRID_H ]f32
@static raindropsX : [ NUM_RAINDROPS ]int
@static raindropsY : [ NUM_RAINDROPS ]int
@static code_colour : RGBA8
@static codes := [?]string {
" ", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "Z", "T", "H", "E", "", "¦", "日",
"ハ", "ミ", "ヒ", "ー", "ウ", "シ", "ナ", "モ", "ニ", "サ", "ワ", "ツ", "オ", "リ", "ア", "ホ", "テ", "マ",
"ケ", "メ", "エ", "カ", "キ", "ム", "ユ", "ラ", "セ", "ネ", "ス", "ツ", "タ", "ヌ", "ヘ", ":", "・", ".",
"\"", "=", "*", "+", "-", "<", ">", "ç", "リ", "ク", "コ", "チ", "ヤ", "ル", "ン", "C", "O", "D"
}
if !init_grid {
for idx in 0..<NUM_RAINDROPS do raindropsY[idx] = GRID_H
init_grid = true
}
@static fixed_timestep_passed : f32 = 0.0
fixed_timestep : f32 = (1.0 / 60.0)
fixed_timestep_passed += frame_duration
for fixed_timestep_passed > fixed_timestep
{
for idx in 0 ..< (GRID_W * GRID_H) do grid_age[idx] += frame_duration
for idx in 0 ..< NUM_RAINDROPS {
raindropsY[idx] += 1
if raindropsY[idx] < 0 do continue
if raindropsY[idx] >= GRID_H {
raindropsY[idx] = -5 - rand.int_max(40)
raindropsX[idx] = rand.int_max(GRID_W)
continue
}
grid [ raindropsY[idx] * GRID_W + raindropsX[idx] ] = rand.int_max(len(codes))
grid_age[ raindropsY[idx] * GRID_W + raindropsX[idx] ] = 0.0
}
fixed_timestep_passed = 0
}
// Draw grid
draw_text_string_pos_norm("Raincode demo", font_title, 92, { 0.2, current_scroll - (section_start + 0.2) }, COLOR_WHITE)
for y in 0 ..< GRID_H do for x in 0 ..< GRID_W
{
pos_x := 0.2 + f32(x) * 0.007
pos_y := current_scroll - (section_start + 0.24 + f32(y) * 0.018)
age := grid_age[y * GRID_W + x]
code_colour = {255, 255, 255, 255}
if age > 0.0 {
code_colour = {
51 + 30,
77 + 30,
102 + 30,
u8(clamp((1.0 - age) * 255, 0, 255) ) }
if code_colour.a == 0 do continue
}
draw_text_string_pos_norm(codes[grid[y * GRID_W + x]], font_demo_raincode, 20, {pos_x, pos_y}, code_colour)
}
ve.set_colour(&ve_ctx, {1.0, 1.0, 1.0, 1.0})
}
// Zoom Test
section_start = 3.3
section_end = 4.8
if current_scroll > section_start && current_scroll < section_end
{
zoom_text := `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Est ullamcorper eget nulla facilisi
etiam dignissim diam quis enim. Convallis convallis tellus id interdum.`
@static zoom_time: f32 = 0
zoom_time += frame_duration
zoom_duration :: 10.0 // Time for one complete zoom cycle in seconds
modified_linear_zoom :: proc( delta : f32) -> f32
{
// Adjust these values to control the time spent at min/max zoom
min_threshold :: 0.05
max_threshold :: 0.95
if delta < min_threshold do return 0
else if delta > max_threshold do return 1
else do return (delta - min_threshold) / (max_threshold - min_threshold)
}
// Calculate the current zoom
delta := (math.sin(2 * math.PI * zoom_time / zoom_duration) + 1) / 2 // Normalize sine wave to 0-1
zoom_t := modified_linear_zoom(delta)
current_zoom := math.lerp(f32(1.0), f32(20.0), zoom_t) // Zoom range from 0.5x to 50x
// Calculate positions with reduced gaps
scroll_offset := current_scroll - section_start
title_y := current_scroll - (section_start + 0.05)
zoom_info_y := current_scroll - (section_start + 0.10)
zoomed_text_y := current_scroll - (section_start + 0.30) + math.sin(zoom_time) * 0.02
draw_text_string_pos_norm("Zoom Test", font_title, 92, {0.2, title_y}, COLOR_WHITE)
zoomed_text_base_size : f32 = 12.0
zoom_adjust_size := zoomed_text_base_size * current_zoom
ve_id, resolved_size := font_provider_resolve_draw_id( font_firacode, zoom_adjust_size * OVER_SAMPLE_ZOOM )
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, font_firacode, 19, {0.2, zoom_info_y}, COLOR_WHITE)
ve.configure_snap( & demo_ctx.ve_ctx, u32(0), u32(0) )
size := measure_text_size( zoom_text, font_firacode, zoomed_text_base_size, 0 ) * current_zoom
x_offset := (size.x / demo_ctx.screen_size.x) * 0.5
zoomed_text_pos := Vec2 { 0.5 - x_offset, zoomed_text_y }
draw_text_zoomed_norm(zoom_text, font_firacode, zoomed_text_base_size, zoomed_text_pos, current_zoom, COLOR_WHITE)
}
// Cache pressure test
section_start = 4.3
section_end = 5.3
if current_scroll > section_start && current_scroll < section_end && true
{
GRID_W :: 30
GRID_H :: 15
GRID2_W :: 8
GRID2_H :: 2
GRID3_W :: 16
GRID3_H :: 4
@static grid : [GRID_W * GRID_H ]int
@static grid2 : [GRID2_W * GRID2_H]int
@static grid3 : [GRID3_W * GRID3_H]int
@static rotate_current : int = 0
@static fixed_timestep_passed : f32 = 0.0
fixed_timestep_passed += frame_duration
fixed_timestep := f32(1.0 / 60.0)
for fixed_timestep_passed > fixed_timestep
{
rotate_current = (rotate_current + 1) % 4
rotate_idx := 0
for & g in grid
{
if (rotate_idx % 4) != rotate_current {
rotate_idx += 1
continue
}
g = 0x4E00 + rand.int_max(0x9FFF - 0x4E00)
rotate_idx += 1
}
for & g in grid2 do g = 0x4E00 + rand.int_max(0x9FFF - 0x4E00)
for & g in grid3 do g = rand.int_max(128)
fixed_timestep_passed -= fixed_timestep
}
codepoint_to_utf8 :: proc(c: []u8, chr: int) {
if chr == 0 {
return
}
else if (0xffffff80 & chr) == 0 {
c[0] = u8(chr)
}
else if (0xfffff800 & chr) == 0 {
c[0] = 0xc0 | u8(chr >> 6)
c[1] = 0x80 | u8(chr & 0x3f)
}
else if (0xffff0000 & chr) == 0 {
c[0] = 0xe0 | u8(chr >> 12)
c[1] = 0x80 | u8((chr >> 6) & 0x3f)
c[2] = 0x80 | u8(chr & 0x3f)
}
else {
c[0] = 0xf0 | u8(chr >> 18)
c[1] = 0x80 | u8((chr >> 12) & 0x3f)
c[2] = 0x80 | u8((chr >> 6) & 0x3f)
c[3] = 0x80 | u8(chr & 0x3f)
}
}
// Draw grid
draw_text_string_pos_norm("Cache pressure test", font_title, 92, {0.2, current_scroll - (section_start + 0.2)}, COLOR_WHITE)
for y in 0..< GRID_H do for x in 0 ..< GRID_W
{
posx := 0.2 + f32(x) * 0.02
posy := current_scroll - (section_start + 0.24 + f32(y) * 0.025)
c := [5]u8{}
codepoint_to_utf8(c[:], grid[ y * GRID_W + x ])
draw_text_string_pos_norm(string( c[:] ), font_demo_chinese, 24, {posx, posy}, COLOR_WHITE)
}
for y in 0 ..< GRID2_H do for x in 0 ..< GRID2_W {
posx := 0.2 + f32(x) * 0.03
posy := current_scroll - (section_start + 0.66 + f32(y) * 0.052)
c := [5]u8{}
codepoint_to_utf8(c[:], grid2[ y * GRID2_W + x ])
draw_text_string_pos_norm(string( c[:] ), font_demo_grid2, 54, {posx, posy}, COLOR_WHITE)
}
for y in 0 ..< GRID3_H do for x in 0 ..< GRID3_W {
posx := 0.45 + f32(x) * 0.02
posy := current_scroll - (section_start + 0.64 + f32(y) * 0.034)
c := [5]u8{}
codepoint_to_utf8( c[:], grid3[ y * GRID3_W + x ])
draw_text_string_pos_norm(string( c[:] ), font_demo_grid3, 44, {posx, posy}, COLOR_WHITE)
}
}
ve_sokol.render_text_layer(demo_ctx.screen_size * 0.5, & demo_ctx.ve_ctx, demo_ctx.render_ctx) ve_sokol.render_text_layer(demo_ctx.screen_size * 0.5, & demo_ctx.ve_ctx, demo_ctx.render_ctx)
} }
gfx.commit() gfx.commit()
ve.flush_draw_list( & demo_ctx.ve_ctx ) ve.flush_draw_list( & demo_ctx.ve_ctx )
} }
cleanup :: proc "c" () { cleanup :: proc "c" () {
context = runtime.default_context() context = runtime.default_context()
ve.shutdown( & demo_ctx.ve_ctx ) // ve.shutdown( & demo_ctx.ve_ctx )
gfx.shutdown() // gfx.shutdown()
} }
main :: proc() main :: proc()
{ {
demo_ctx.screen_size = Vec2 { 1600, 900 } demo_ctx.screen_size = Vec2 { 1920, 1080 }
app.run({ app.run({
init_cb = init, init_cb = init,
event_cb = event,
frame_cb = frame, frame_cb = frame,
cleanup_cb = cleanup, cleanup_cb = cleanup,
width = i32(demo_ctx.screen_size.x), width = i32(demo_ctx.screen_size.x),

View File

@@ -94,10 +94,10 @@ function build-SokolBackendDemo
# $build_args += $flag_micro_architecture_native # $build_args += $flag_micro_architecture_native
$build_args += $flag_use_separate_modules $build_args += $flag_use_separate_modules
$build_args += $flag_thread_count + $CoreCount_Physical $build_args += $flag_thread_count + $CoreCount_Physical
$build_args += $flag_optimize_none # $build_args += $flag_optimize_none
# $build_args += $flag_optimize_minimal # $build_args += $flag_optimize_minimal
# $build_args += $flag_optimize_speed # $build_args += $flag_optimize_speed
# $build_args += $falg_optimize_aggressive $build_args += $falg_optimize_aggressive
$build_args += $flag_debug $build_args += $flag_debug
$build_args += $flag_pdb_name + $pdb $build_args += $flag_pdb_name + $pdb
$build_args += $flag_subsystem + 'windows' $build_args += $flag_subsystem + 'windows'