fix hot-reload, starting to setup proper rendering again.
* Added hot_reload, measure_text_size to VEFontCache
This commit is contained in:
parent
4b8c4d0c2c
commit
59ed4d9dd6
@ -49,6 +49,17 @@ pool_list_init :: proc( pool : ^PoolList, capacity : u32 )
|
||||
back = -1
|
||||
}
|
||||
|
||||
pool_list_free :: proc( pool : ^PoolList )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
pool_list_reload :: proc( pool : ^PoolList, allocator : Allocator )
|
||||
{
|
||||
pool.items.backing = allocator
|
||||
pool.free_list.backing = allocator
|
||||
}
|
||||
|
||||
pool_list_push_front :: proc( pool : ^PoolList, value : PoolListValue )
|
||||
{
|
||||
using pool
|
||||
@ -134,6 +145,17 @@ LRU_init :: proc( cache : ^LRU_Cache, capacity : u32 ) {
|
||||
pool_list_init( & cache.key_queue, capacity )
|
||||
}
|
||||
|
||||
LRU_free :: proc( cache : ^LRU_Cache )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
LRU_reload :: proc( cache : ^LRU_Cache, allocator : Allocator )
|
||||
{
|
||||
hmap_zpl_reload( & cache.table, allocator )
|
||||
pool_list_reload( & cache.key_queue, allocator )
|
||||
}
|
||||
|
||||
LRU_hash_key :: #force_inline proc( key : u64 ) -> ( hash : u64 ) {
|
||||
bytes := transmute( [8]byte ) key
|
||||
hash = fnv64a( bytes[:] )
|
||||
@ -172,7 +194,8 @@ LRU_peek :: proc( cache : ^LRU_Cache, key : u64 ) -> i32 {
|
||||
return iter.value
|
||||
}
|
||||
|
||||
LRU_put :: proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64 {
|
||||
LRU_put :: proc( cache : ^LRU_Cache, key : u64, value : i32 ) -> u64
|
||||
{
|
||||
hash_key := LRU_hash_key( key )
|
||||
iter := get( & cache.table, hash_key )
|
||||
if iter != nil {
|
||||
|
@ -355,6 +355,43 @@ init :: proc( ctx : ^Context, parser_kind : ParserKind,
|
||||
shaper_init( & shaper_ctx )
|
||||
}
|
||||
|
||||
hot_reload :: proc( ctx : ^Context, allocator : Allocator )
|
||||
{
|
||||
ctx.backing = allocator
|
||||
context.allocator = ctx.backing
|
||||
|
||||
using ctx
|
||||
|
||||
entries.backing = allocator
|
||||
temp_path.backing = allocator
|
||||
hmap_zpl_reload( & temp_codepoint_seen, allocator )
|
||||
draw_list.vertices.backing = allocator
|
||||
draw_list.indices.backing = allocator
|
||||
draw_list.calls.backing = allocator
|
||||
|
||||
LRU_reload( & atlas.region_a.state, allocator)
|
||||
LRU_reload( & atlas.region_b.state, allocator)
|
||||
LRU_reload( & atlas.region_c.state, allocator)
|
||||
LRU_reload( & atlas.region_d.state, allocator)
|
||||
|
||||
LRU_reload( & shape_cache.state, allocator )
|
||||
for idx : u32 = 0; idx < u32(shape_cache.storage.capacity); idx += 1 {
|
||||
stroage_entry := & shape_cache.storage.data[idx]
|
||||
using stroage_entry
|
||||
|
||||
glyphs.backing = allocator
|
||||
positions.backing = allocator
|
||||
}
|
||||
|
||||
atlas.draw_list.calls.backing = allocator
|
||||
atlas.draw_list.indices.backing = allocator
|
||||
atlas.draw_list.vertices.backing = allocator
|
||||
|
||||
atlas.clear_draw_list.calls.backing = allocator
|
||||
atlas.clear_draw_list.indices.backing = allocator
|
||||
atlas.clear_draw_list.vertices.backing = allocator
|
||||
}
|
||||
|
||||
// ve_foncache_shutdown
|
||||
shutdown :: proc( ctx : ^Context )
|
||||
{
|
||||
@ -679,6 +716,37 @@ is_empty :: proc( ctx : ^Context, entry : ^Entry, glyph_index : Glyph ) -> b32
|
||||
return false
|
||||
}
|
||||
|
||||
measure_text_size :: proc( ctx : ^Context, font : FontID, text_utf8 : string ) -> (measured : Vec2)
|
||||
{
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && font < FontID(ctx.entries.num) )
|
||||
|
||||
atlas := ctx.atlas
|
||||
|
||||
shaped := shape_text_cached( ctx, font, text_utf8 )
|
||||
|
||||
entry := & ctx.entries.data[ font ]
|
||||
|
||||
batch_start_idx : i32 = 0
|
||||
for index : i32 = 0; index < i32(shaped.glyphs.num); index += 1
|
||||
{
|
||||
glyph_index := shaped.glyphs.data[ index ]
|
||||
if is_empty( ctx, entry, glyph_index ) do continue
|
||||
|
||||
bounds_0, bounds_1 := parser_get_glyph_box( & entry.parser_info, glyph_index )
|
||||
bounds_width := bounds_1.x - bounds_0.x
|
||||
bounds_height := bounds_1.y - bounds_0.y
|
||||
|
||||
bounds := Vec2 {
|
||||
cast(f32) cast(u32) (f32(bounds_width) * entry.size_scale - f32(atlas.glyph_padding)),
|
||||
cast(f32) cast(u32) (f32(bounds_height) * entry.size_scale - f32(atlas.glyph_padding)),
|
||||
}
|
||||
measured += bounds
|
||||
}
|
||||
|
||||
return measured
|
||||
}
|
||||
|
||||
reset_batch_codepoint_state :: proc( ctx : ^Context ) {
|
||||
clear( & ctx.temp_codepoint_seen )
|
||||
ctx.temp_codepoint_seen_num = 0
|
||||
|
@ -289,6 +289,8 @@ draw_text :: proc( ctx : ^Context, font : FontID, text_utf8 : string, position :
|
||||
assert( ctx != nil )
|
||||
assert( font >= 0 && font < FontID(ctx.entries.num) )
|
||||
|
||||
context.allocator = ctx.backing
|
||||
|
||||
shaped := shape_text_cached( ctx, font, text_utf8 )
|
||||
|
||||
snap_width := f32(ctx.snap_width)
|
||||
|
@ -108,6 +108,10 @@ make :: proc {
|
||||
hmap_zpl_init,
|
||||
}
|
||||
|
||||
// reload :: proc {
|
||||
|
||||
// }
|
||||
|
||||
remove_at :: proc {
|
||||
array_remove_at,
|
||||
}
|
||||
|
@ -2,17 +2,17 @@ package grime
|
||||
|
||||
import "base:runtime"
|
||||
|
||||
reload_array :: proc( self : [dynamic]$Type, allocator : Allocator ) {
|
||||
reload_array :: proc( self : ^[dynamic]$Type, allocator : Allocator ) {
|
||||
raw := transmute(runtime.Raw_Dynamic_Array) self
|
||||
raw.allocator = allocator
|
||||
}
|
||||
|
||||
reload_queue :: proc( self : Queue($Type), allocator : Allocator ) {
|
||||
reload_queue :: proc( self : ^Queue($Type), allocator : Allocator ) {
|
||||
raw_array := transmute(runtime.Raw_Dynamic_Array) self.data
|
||||
raw_array.allocator = allocator
|
||||
}
|
||||
|
||||
reload_map :: proc( self : map [$KeyType] $EntryType, allocator : Allocator ) {
|
||||
reload_map :: proc( self : ^map [$KeyType] $EntryType, allocator : Allocator ) {
|
||||
raw := transmute(runtime.Raw_Map) self
|
||||
raw.allocator = allocator
|
||||
}
|
||||
|
@ -1,6 +1,18 @@
|
||||
package sectr
|
||||
|
||||
RGBA8 :: struct { r, g, b, a : u8 }
|
||||
RGBA8 :: struct { r, g, b, a : u8 }
|
||||
RGBAN :: [4]f32
|
||||
|
||||
normalize_rgba8 :: #force_inline proc( color : RGBA8 ) -> RGBAN {
|
||||
result := RGBAN {
|
||||
1.0 / f32(color.r),
|
||||
1.0 / f32(color.g),
|
||||
1.0 / f32(color.b),
|
||||
1.0 / f32(color.a),
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Color_Blue :: RGBA8 { 90, 90, 230, 255 }
|
||||
Color_Red :: RGBA8 { 230, 90, 90, 255 }
|
||||
Color_White :: RGBA8 { 255, 255, 255, 255 }
|
||||
|
@ -43,8 +43,6 @@ render :: proc()
|
||||
do_nothing : bool
|
||||
do_nothing = false
|
||||
|
||||
time.sleep(10000)
|
||||
|
||||
// The below are most likely limited to a "depth layer" and so
|
||||
// different depth layers need different draw pass combos (of the 3 constructive passes)
|
||||
// Will need to profile how expensive it is for batching with the UI box rendering
|
@ -112,19 +112,19 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
using input_events
|
||||
|
||||
error : AllocatorError
|
||||
events, error = make( Queue(InputEvent), 4 * Kilo, persistent_allocator() )
|
||||
events, error = make( Queue(InputEvent), 4 * Kilo, persistent_slab_allocator() )
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.events array")
|
||||
|
||||
key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_allocator() )
|
||||
key_events, error = make( Queue(InputKeyEvent), Kilo, persistent_slab_allocator() )
|
||||
ensure(error == AllocatorError.None, "Failed to allocate key_events array")
|
||||
|
||||
mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_allocator() )
|
||||
mouse_events, error = make( Queue(InputMouseEvent), 2 * Kilo, persistent_slab_allocator() )
|
||||
ensure(error == AllocatorError.None, "Failed to allocate mouse_events array")
|
||||
|
||||
codes_pressed, error = make( Array(rune), Kilo, persistent_allocator() )
|
||||
codes_pressed, error = make( Array(rune), Kilo, persistent_slab_allocator() )
|
||||
ensure(error == AllocatorError.None, "Failed to allocate codes_pressed array")
|
||||
|
||||
staged_input_events, error = make( Array(InputEvent), 8 * Kilo, persistent_allocator() )
|
||||
staged_input_events, error = make( Array(InputEvent), 8 * Kilo, persistent_slab_allocator() )
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input_staged_events array")
|
||||
}
|
||||
|
||||
@ -416,9 +416,16 @@ hot_reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_
|
||||
slab_reload( persistent_slab, persistent_allocator() )
|
||||
|
||||
// input_reload()
|
||||
{
|
||||
using input_events
|
||||
reload( & events, persistent_slab_allocator())
|
||||
reload( & key_events, persistent_slab_allocator())
|
||||
reload( & mouse_events, persistent_slab_allocator())
|
||||
codes_pressed.backing = persistent_slab_allocator()
|
||||
staged_input_events.backing = persistent_slab_allocator()
|
||||
}
|
||||
|
||||
// font_provider_reload()
|
||||
hmap_chained_reload( font_provider_data.font_cache, persistent_allocator())
|
||||
font_provider_reload()
|
||||
|
||||
str_cache_reload( & string_cache, persistent_allocator(), persistent_allocator() )
|
||||
str_cache_set_module_ctx( & string_cache )
|
||||
@ -512,7 +519,7 @@ tick_work_frame :: #force_inline proc( host_delta_time_ms : f64 ) -> b32
|
||||
}
|
||||
|
||||
// Lifted out of tick so that sokol_app_frame_callback can do it as well.
|
||||
tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_ms : f64, host_delta_ns : Duration )
|
||||
tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_ms : f64, host_delta_ns : Duration, can_sleep := true )
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state
|
||||
@ -536,7 +543,7 @@ tick_frametime :: #force_inline proc( client_tick : ^time.Tick, host_delta_time_
|
||||
sleep_ms := frametime_target_ms - frametime_elapsed_ms
|
||||
pre_sleep_tick := time.tick_now()
|
||||
|
||||
if sleep_ms > 0 {
|
||||
if can_sleep && sleep_ms > 0 {
|
||||
thread_sleep( cast(Duration) sleep_ms * MS_To_NS )
|
||||
// thread__highres_wait( sleep_ms )
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ sokol_app_frame_callback :: proc "c" ()
|
||||
should_close |= tick_work_frame( sokol_delta_ms )
|
||||
profile_end()
|
||||
|
||||
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns )
|
||||
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns, can_sleep = false )
|
||||
window.resized = false
|
||||
}
|
||||
|
||||
|
336
code/sectr/engine/render.odin
Normal file
336
code/sectr/engine/render.odin
Normal file
@ -0,0 +1,336 @@
|
||||
package sectr
|
||||
|
||||
import "core:math"
|
||||
import "core:time"
|
||||
|
||||
import ve "codebase:font/VEFontCache"
|
||||
import sokol_app "thirdparty:sokol/app"
|
||||
import gfx "thirdparty:sokol/gfx"
|
||||
import sokol_glue "thirdparty:sokol/glue"
|
||||
import gp "thirdparty:sokol/gp"
|
||||
|
||||
PassActions :: struct {
|
||||
bg_clear_black : gfx.Pass_Action,
|
||||
|
||||
}
|
||||
|
||||
RenderState :: struct {
|
||||
pass_actions : PassActions,
|
||||
}
|
||||
|
||||
// Draw text using a string and normalized screen coordinates
|
||||
draw_text_string_pos_norm :: proc( content : string, id : FontID, size : f32, pos : Vec2, color := Color_White )
|
||||
{
|
||||
state := get_state(); using state
|
||||
width := app_window.extent.x * 2
|
||||
height := app_window.extent.y * 2
|
||||
|
||||
ve_id := font_provider_resolve_draw_id( id )
|
||||
color_norm := normalize_rgba8(color)
|
||||
|
||||
ve.set_colour( & font_provider_data.ve_font_cache, color_norm )
|
||||
ve.draw_text( & font_provider_data.ve_font_cache, ve_id, content, pos, Vec2{1 / width, 1 / height} )
|
||||
return
|
||||
}
|
||||
|
||||
// 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 )
|
||||
{
|
||||
state := get_state(); using state
|
||||
extent := app_window.extent
|
||||
|
||||
normalized_pos := pos / extent
|
||||
draw_text_string_pos_norm( content, id, size, normalized_pos, color )
|
||||
}
|
||||
|
||||
render :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack
|
||||
|
||||
|
||||
// TODO(Ed): Eventually we want to only update when state is dirty/user has done an action
|
||||
gfx.begin_pass(gfx.Pass { action = render_data.pass_actions.bg_clear_black, swapchain = sokol_glue.swapchain() })
|
||||
gfx.end_pass();
|
||||
|
||||
// render_mode_3d()
|
||||
|
||||
render_mode_2d_workspace()
|
||||
render_mode_screenspace()
|
||||
|
||||
gfx.commit()
|
||||
ve.flush_draw_list( & font_provider_data.ve_font_cache )
|
||||
}
|
||||
|
||||
// TODO(Ed): Eventually this needs to become a 'viewport within a UI'
|
||||
// This would allow the user to have more than one workspace open at the same time
|
||||
render_mode_2d_workspace :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack
|
||||
cam := & project.workspace.cam
|
||||
}
|
||||
|
||||
render_mode_screenspace :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack
|
||||
replay := & Memory_App.replay
|
||||
cam := & project.workspace.cam
|
||||
win_extent := state.app_window.extent
|
||||
|
||||
ve.configure_snap( & font_provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
|
||||
|
||||
render_screen_ui()
|
||||
|
||||
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color := Color_White, font : FontID = Font_Default )
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content ) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
font = default_font
|
||||
}
|
||||
// pos := screen_to_render_pos(pos)
|
||||
|
||||
draw_text_string_pos_extent( content, font, size, pos, color )
|
||||
}
|
||||
|
||||
debug_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@static draw_text_scratch : [Kilobyte * 8]u8
|
||||
|
||||
state := get_state(); using state
|
||||
if debug.draw_debug_text_y > 800 {
|
||||
debug.draw_debug_text_y = 0
|
||||
}
|
||||
|
||||
cam := & project.workspace.cam
|
||||
screen_corners := screen_get_corners()
|
||||
|
||||
position := screen_corners.top_right
|
||||
position.x -= app_window.extent.x
|
||||
position.y -= debug.draw_debug_text_y
|
||||
|
||||
content := str_fmt_buffer( draw_text_scratch[:], format, ..args )
|
||||
debug_draw_text( content, position, 12.0 )
|
||||
|
||||
debug.draw_debug_text_y += 14
|
||||
}
|
||||
|
||||
// "Draw text" using immediate mode api
|
||||
{
|
||||
font_provider := & state.font_provider_data
|
||||
using font_provider
|
||||
|
||||
@static index : i32
|
||||
text_test_str := str_fmt("frametime : %0.6f\nframetime(sokol): %0.2f\nframe id : %d\nsokol_frame: %d", frametime_delta_ms, sokol_app.frame_delta() * S_To_MS, frame, sokol_app.frame_count() )
|
||||
// log(text_test_str)
|
||||
// text_test_str := str_fmt("HELLO VE FONT CACHE!")
|
||||
// text_test_str := str_fmt("C")
|
||||
|
||||
// font_provider := & state.font_provider_data
|
||||
// fdef := hmap_chained_get( font_cache, default_font.key )
|
||||
|
||||
width := app_window.extent.x * 2
|
||||
height := app_window.extent.y * 2
|
||||
|
||||
ve.set_colour( & ve_font_cache, { 1.0, 1.0, 1.0, 1.0 } )
|
||||
ve.configure_snap( & ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
|
||||
|
||||
ve.draw_text( & ve_font_cache, font_provider_resolve_draw_id(default_font), text_test_str, {0.0, 0.975}, Vec2{1 / width, 1 / height} )
|
||||
}
|
||||
|
||||
debug.debug_text_vis = true
|
||||
if debug.debug_text_vis
|
||||
{
|
||||
fps_msg := str_fmt( "FPS: %f", fps_avg)
|
||||
fps_msg_width := cast(f32) u32(measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x) + 0.5
|
||||
fps_msg_pos := screen_get_corners().top_right - { fps_msg_width, 0 } - { 5, 5 }
|
||||
debug_draw_text( fps_msg, fps_msg_pos, 12.0, color = Color_White )
|
||||
// debug_draw_text( fps_msg, {}, 12.0, color = Color_White )
|
||||
|
||||
render_text_layer()
|
||||
}
|
||||
|
||||
debug.draw_debug_text_y = 14
|
||||
}
|
||||
|
||||
render_screen_ui :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state // TODO(Ed): Prefer passing static context to through the callstack
|
||||
|
||||
|
||||
}
|
||||
|
||||
render_text_layer :: proc()
|
||||
{
|
||||
profile("VEFontCache: render frame")
|
||||
|
||||
Bindings :: gfx.Bindings
|
||||
Range :: gfx.Range
|
||||
ShaderStage :: gfx.Shader_Stage
|
||||
|
||||
state := get_state(); using state
|
||||
font_provider := state.font_provider_data
|
||||
using font_provider
|
||||
|
||||
ve.optimize_draw_list( & ve_font_cache )
|
||||
draw_list := ve.get_draw_list( & ve_font_cache )
|
||||
|
||||
draw_list_vert_slice := array_to_slice(draw_list.vertices)
|
||||
draw_list_index_slice := array_to_slice(draw_list.indices)
|
||||
|
||||
gfx.update_buffer( draw_list_vbuf, Range{ draw_list.vertices.data, draw_list.vertices.num * size_of(ve.Vertex) })
|
||||
gfx.update_buffer( draw_list_ibuf, Range{ draw_list.indices.data, draw_list.indices.num * size_of(u32) })
|
||||
|
||||
draw_list_call_slice := array_to_slice(draw_list.calls)
|
||||
for & draw_call in array_to_slice(draw_list.calls)
|
||||
{
|
||||
watch := draw_call
|
||||
// profile("VEFontCache: draw call")
|
||||
|
||||
switch draw_call.pass
|
||||
{
|
||||
// 1. Do the glyph rendering pass
|
||||
// Glyphs are first rendered to an intermediate 2k x 512px R8 texture
|
||||
case .Glyph:
|
||||
// profile("VEFontCache: draw call: glyph")
|
||||
if (draw_call.end_index - draw_call.start_index) == 0 && ! draw_call.clear_before_draw {
|
||||
continue
|
||||
}
|
||||
|
||||
width := ve_font_cache.atlas.buffer_width
|
||||
height := ve_font_cache.atlas.buffer_height
|
||||
|
||||
pass := glyph_pass
|
||||
if draw_call.clear_before_draw {
|
||||
pass.action.colors[0].load_action = .CLEAR
|
||||
pass.action.colors[0].clear_value.a = 1.0
|
||||
}
|
||||
gfx.begin_pass( pass )
|
||||
|
||||
// sokol_gfx.apply_viewport( 0,0, width, height, origin_top_left = true )
|
||||
// sokol_gfx.apply_scissor_rect( 0,0, width, height, origin_top_left = true )
|
||||
|
||||
gfx.apply_pipeline( glyph_pipeline )
|
||||
|
||||
bindings := Bindings {
|
||||
vertex_buffers = {
|
||||
0 = draw_list_vbuf,
|
||||
},
|
||||
vertex_buffer_offsets = {
|
||||
0 = 0,
|
||||
},
|
||||
index_buffer = draw_list_ibuf,
|
||||
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
|
||||
fs = {},
|
||||
}
|
||||
gfx.apply_bindings( bindings )
|
||||
|
||||
// 2. Do the atlas rendering pass
|
||||
// A simple 16-tap box downsample shader is then used to blit from this intermediate texture to the final atlas location
|
||||
case .Atlas:
|
||||
// profile("VEFontCache: draw call: atlas")
|
||||
if (draw_call.end_index - draw_call.start_index) == 0 && ! draw_call.clear_before_draw {
|
||||
continue
|
||||
}
|
||||
|
||||
width := ve_font_cache.atlas.width
|
||||
height := ve_font_cache.atlas.height
|
||||
|
||||
pass := atlas_pass
|
||||
if draw_call.clear_before_draw {
|
||||
pass.action.colors[0].load_action = .CLEAR
|
||||
pass.action.colors[0].clear_value.a = 1.0
|
||||
}
|
||||
gfx.begin_pass( pass )
|
||||
|
||||
// sokol_gfx.apply_viewport( 0, 0, width, height, origin_top_left = true )
|
||||
// sokol_gfx.apply_scissor_rect( 0, 0, width, height, origin_top_left = true )
|
||||
|
||||
gfx.apply_pipeline( atlas_pipeline )
|
||||
|
||||
fs_uniform := Ve_Blit_Atlas_Fs_Params { region = cast(i32) draw_call.region }
|
||||
gfx.apply_uniforms( ShaderStage.FS, SLOT_ve_blit_atlas_fs_params, Range { & fs_uniform, size_of(Ve_Blit_Atlas_Fs_Params) })
|
||||
|
||||
gfx.apply_bindings(Bindings {
|
||||
vertex_buffers = {
|
||||
0 = draw_list_vbuf,
|
||||
},
|
||||
vertex_buffer_offsets = {
|
||||
0 = 0,
|
||||
},
|
||||
index_buffer = draw_list_ibuf,
|
||||
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
|
||||
fs = {
|
||||
images = { SLOT_ve_blit_atlas_src_texture = glyph_rt_color, },
|
||||
samplers = { SLOT_ve_blit_atlas_src_sampler = glyph_rt_sampler, },
|
||||
},
|
||||
})
|
||||
|
||||
// 3. Use the atlas to then render the text.
|
||||
case .None: fallthrough
|
||||
case .Target: fallthrough
|
||||
case .Target_Uncached:
|
||||
if (draw_call.end_index - draw_call.start_index) == 0 && ! draw_call.clear_before_draw {
|
||||
continue
|
||||
}
|
||||
|
||||
// profile("VEFontCache: draw call: target")
|
||||
width := u32(app_window.extent.x * 2)
|
||||
height := u32(app_window.extent.y * 2)
|
||||
|
||||
pass := screen_pass
|
||||
pass.swapchain = sokol_glue.swapchain()
|
||||
gfx.begin_pass( pass )
|
||||
|
||||
// sokol_gfx.apply_viewport( 0, 0, width, height, origin_top_left = true )
|
||||
// sokol_gfx.apply_scissor_rect( 0, 0, width, height, origin_top_left = true )
|
||||
|
||||
gfx.apply_pipeline( screen_pipeline )
|
||||
|
||||
src_rt := atlas_rt_color
|
||||
src_sampler := atlas_rt_sampler
|
||||
|
||||
fs_target_uniform := Ve_Draw_Text_Fs_Params {
|
||||
down_sample = 0,
|
||||
colour = {1.0, 1.0, 1.0, 1},
|
||||
}
|
||||
|
||||
if draw_call.pass == .Target_Uncached {
|
||||
fs_target_uniform.down_sample = 1
|
||||
src_rt = glyph_rt_color
|
||||
src_sampler = glyph_rt_sampler
|
||||
}
|
||||
gfx.apply_uniforms( ShaderStage.FS, SLOT_ve_draw_text_fs_params, Range { & fs_target_uniform, size_of(Ve_Draw_Text_Fs_Params) })
|
||||
|
||||
gfx.apply_bindings(Bindings {
|
||||
vertex_buffers = {
|
||||
0 = draw_list_vbuf,
|
||||
},
|
||||
vertex_buffer_offsets = {
|
||||
0 = 0,
|
||||
},
|
||||
index_buffer = draw_list_ibuf,
|
||||
index_buffer_offset = 0,//i32(draw_call.start_index) * size_of(u32),
|
||||
fs = {
|
||||
images = { SLOT_ve_draw_text_src_texture = src_rt, },
|
||||
samplers = { SLOT_ve_draw_text_src_sampler = src_sampler, },
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if (draw_call.end_index - draw_call.start_index) != 0 {
|
||||
num_indices := draw_call.end_index - draw_call.start_index
|
||||
gfx.draw( draw_call.start_index, num_indices, 1 )
|
||||
}
|
||||
|
||||
gfx.end_pass()
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package sectr
|
||||
|
||||
import "core:math"
|
||||
import "core:os"
|
||||
import ve "codebase:font/VEFontCache"
|
||||
import sokol_gfx "thirdparty:sokol/gfx"
|
||||
@ -22,8 +23,10 @@ FontID :: struct {
|
||||
}
|
||||
|
||||
FontDef :: struct {
|
||||
path_file : string,
|
||||
ve_id : ve.FontID,
|
||||
path_file : string,
|
||||
default_size : i32,
|
||||
size_table : [Font_Largest_Px_Size / Font_Size_Interval] ve.FontID,
|
||||
// ve_id : ve.FontID,
|
||||
}
|
||||
|
||||
FontProviderData :: struct
|
||||
@ -150,7 +153,7 @@ font_provider_startup :: proc()
|
||||
pixel_format = .R8,
|
||||
write_mask = .RGBA,
|
||||
blend = BlendState {
|
||||
enabled = true,
|
||||
enabled = true,
|
||||
src_factor_rgb = .ONE_MINUS_DST_COLOR,
|
||||
dst_factor_rgb = .ONE_MINUS_SRC_COLOR,
|
||||
op_rgb = BlendOp.ADD,
|
||||
@ -169,11 +172,11 @@ font_provider_startup :: proc()
|
||||
},
|
||||
color_count = 1,
|
||||
depth = {
|
||||
pixel_format = .DEPTH,
|
||||
compare = .ALWAYS,
|
||||
pixel_format = .DEPTH,
|
||||
compare = .ALWAYS,
|
||||
write_enabled = false,
|
||||
},
|
||||
cull_mode = .NONE,
|
||||
cull_mode = .NONE,
|
||||
sample_count = 1,
|
||||
// label =
|
||||
})
|
||||
@ -213,18 +216,17 @@ font_provider_startup :: proc()
|
||||
min_filter = Filter.NEAREST,
|
||||
mag_filter = Filter.NEAREST,
|
||||
mipmap_filter = Filter.NONE,
|
||||
wrap_u = .CLAMP_TO_EDGE,
|
||||
wrap_v = .CLAMP_TO_EDGE,
|
||||
min_lod = -1000.0,
|
||||
max_lod = 1000.0,
|
||||
wrap_u = .CLAMP_TO_EDGE,
|
||||
wrap_v = .CLAMP_TO_EDGE,
|
||||
min_lod = -1000.0,
|
||||
max_lod = 1000.0,
|
||||
border_color = BorderColor.OPAQUE_BLACK,
|
||||
compare = .NEVER
|
||||
compare = .NEVER
|
||||
})
|
||||
verify( sokol_gfx.query_sampler_state( glyph_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" )
|
||||
|
||||
color_attach := AttachmentDesc {
|
||||
image = glyph_rt_color,
|
||||
// mip_level = 1,
|
||||
image = glyph_rt_color,
|
||||
}
|
||||
|
||||
glyph_attachments := sokol_gfx.make_attachments({
|
||||
@ -242,19 +244,18 @@ font_provider_startup :: proc()
|
||||
0 = {
|
||||
load_action = .LOAD,
|
||||
store_action = .STORE,
|
||||
// clear_value = {0.01,0.01,0.01,1},
|
||||
clear_value = {0.00, 0.00, 0.00, 1.00},
|
||||
}
|
||||
},
|
||||
depth = {
|
||||
load_action = .DONTCARE,
|
||||
load_action = .DONTCARE,
|
||||
store_action = .DONTCARE,
|
||||
clear_value = 0.0,
|
||||
clear_value = 0.0,
|
||||
},
|
||||
stencil = {
|
||||
load_action = .DONTCARE,
|
||||
load_action = .DONTCARE,
|
||||
store_action = .DONTCARE,
|
||||
clear_value = 0,
|
||||
clear_value = 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -290,7 +291,7 @@ font_provider_startup :: proc()
|
||||
pixel_format = .R8,
|
||||
write_mask = .RGBA,
|
||||
blend = BlendState {
|
||||
enabled = true,
|
||||
enabled = true,
|
||||
src_factor_rgb = .SRC_ALPHA,
|
||||
dst_factor_rgb = .ONE_MINUS_SRC_ALPHA,
|
||||
op_rgb = BlendOp.ADD,
|
||||
@ -309,11 +310,11 @@ font_provider_startup :: proc()
|
||||
},
|
||||
color_count = 1,
|
||||
depth = {
|
||||
pixel_format = .DEPTH,
|
||||
compare = .ALWAYS,
|
||||
pixel_format = .DEPTH,
|
||||
compare = .ALWAYS,
|
||||
write_enabled = false,
|
||||
},
|
||||
cull_mode = .NONE,
|
||||
cull_mode = .NONE,
|
||||
sample_count = 1,
|
||||
})
|
||||
}
|
||||
@ -352,12 +353,12 @@ font_provider_startup :: proc()
|
||||
min_filter = Filter.NEAREST,
|
||||
mag_filter = Filter.NEAREST,
|
||||
mipmap_filter = Filter.NONE,
|
||||
wrap_u = .CLAMP_TO_EDGE,
|
||||
wrap_v = .CLAMP_TO_EDGE,
|
||||
min_lod = -1000.0,
|
||||
max_lod = 1000.0,
|
||||
wrap_u = .CLAMP_TO_EDGE,
|
||||
wrap_v = .CLAMP_TO_EDGE,
|
||||
min_lod = -1000.0,
|
||||
max_lod = 1000.0,
|
||||
border_color = BorderColor.OPAQUE_BLACK,
|
||||
compare = .NEVER
|
||||
compare = .NEVER
|
||||
})
|
||||
verify( sokol_gfx.query_sampler_state( atlas_rt_sampler) < ResourceState.FAILED, "Failed to make atlas_rt_sampler" )
|
||||
|
||||
@ -448,8 +449,8 @@ font_provider_startup :: proc()
|
||||
color_count = 1,
|
||||
sample_count = 1,
|
||||
depth = {
|
||||
pixel_format = app_env.defaults.depth_format,
|
||||
compare = .ALWAYS,
|
||||
pixel_format = app_env.defaults.depth_format,
|
||||
compare = .ALWAYS,
|
||||
write_enabled = false,
|
||||
},
|
||||
cull_mode = .NONE,
|
||||
@ -478,14 +479,14 @@ font_provider_startup :: proc()
|
||||
}
|
||||
},
|
||||
depth = {
|
||||
load_action = .DONTCARE,
|
||||
load_action = .DONTCARE,
|
||||
store_action = .DONTCARE,
|
||||
clear_value = 0.0,
|
||||
clear_value = 0.0,
|
||||
},
|
||||
stencil = {
|
||||
load_action = .DONTCARE,
|
||||
load_action = .DONTCARE,
|
||||
store_action = .DONTCARE,
|
||||
clear_value = 0,
|
||||
clear_value = 0,
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,7 +503,10 @@ font_provider_reload :: proc()
|
||||
state := get_state()
|
||||
provider_data := & state.font_provider_data
|
||||
|
||||
ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
|
||||
hmap_chained_reload( provider_data.font_cache, persistent_allocator())
|
||||
|
||||
// ve.configure_snap( & provider_data.ve_font_cache, u32(state.app_window.extent.x * 2.0), u32(state.app_window.extent.y * 2.0) )
|
||||
ve.hot_reload( & provider_data.ve_font_cache, persistent_slab_allocator() )
|
||||
}
|
||||
|
||||
font_provider_shutdown :: proc()
|
||||
@ -514,13 +518,14 @@ font_provider_shutdown :: proc()
|
||||
}
|
||||
|
||||
font_load :: proc(path_file : string,
|
||||
default_size : f32 = Font_Load_Use_Default_Size,
|
||||
default_size : i32 = Font_Load_Use_Default_Size,
|
||||
desired_id : string = Font_Load_Gen_ID
|
||||
) -> FontID
|
||||
{
|
||||
profile(#procedure)
|
||||
msg := str_fmt_tmp("Loading font: %v", path_file)
|
||||
profile(msg)
|
||||
log(msg)
|
||||
|
||||
logf("Loading font: %v", path_file)
|
||||
provider_data := & get_state().font_provider_data; using provider_data
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_file, persistent_allocator() )
|
||||
@ -542,11 +547,47 @@ font_load :: proc(path_file : string,
|
||||
def, set_error := hmap_chained_set(font_cache, key, FontDef{})
|
||||
verify( set_error == AllocatorError.None, "Failed to add new font entry to cache" )
|
||||
|
||||
def.path_file = path_file
|
||||
def.path_file = path_file
|
||||
def.default_size = default_size
|
||||
|
||||
// TODO(Ed): Load even sizes from 8px to upper bound.
|
||||
def.ve_id = ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, 18.0 )
|
||||
for font_size : i32 = Font_Size_Interval; font_size <= Font_Largest_Px_Size; 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^ = ve.load_font( & provider_data.ve_font_cache, desired_id, font_data, 14.0 )
|
||||
}
|
||||
|
||||
fid := FontID { key, desired_id }
|
||||
return fid
|
||||
}
|
||||
|
||||
Font_Use_Default_Size :: f32(0.0)
|
||||
|
||||
font_provider_resolve_draw_id :: proc( id : FontID, size := Font_Use_Default_Size ) -> ve.FontID
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
even_size := math.round(size * (1.0 / f32(Font_Size_Interval))) * f32(Font_Size_Interval)
|
||||
size := clamp( i32( even_size), 4, Font_Largest_Px_Size )
|
||||
def := hmap_chained_get( font_provider_data.font_cache, id.key )
|
||||
size = size if size != i32(Font_Use_Default_Size) else def.default_size
|
||||
|
||||
id := (size / Font_Size_Interval) + (size % Font_Size_Interval)
|
||||
ve_id := def.size_table[ id - 1 ]
|
||||
|
||||
width := app_window.extent.x * 2
|
||||
height := app_window.extent.y * 2
|
||||
return ve_id
|
||||
}
|
||||
|
||||
measure_text_size :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
||||
{
|
||||
state := get_state(); using state
|
||||
|
||||
// profile(#procedure)
|
||||
px_size := math.round( font_size )
|
||||
ve_id := font_provider_resolve_draw_id( font, font_size )
|
||||
|
||||
measured := ve.measure_text_size( & font_provider_data.ve_font_cache, ve_id, text )
|
||||
return measured
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ push-location $path_root
|
||||
# $build_args += $flag_optimize_minimal
|
||||
# $build_args += $flag_optimize_speed
|
||||
# $build_args += $falg_optimize_aggressive
|
||||
# $build_args += $flag_debug
|
||||
$build_args += $flag_debug
|
||||
$build_args += $flag_pdb_name + $pdb
|
||||
$build_args += $flag_subsystem + 'windows'
|
||||
# $build_args += $flag_show_system_calls
|
||||
|
Loading…
Reference in New Issue
Block a user