fix hot-reload, starting to setup proper rendering again.
* Added hot_reload, measure_text_size to VEFontCache
This commit is contained in:
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user