Gut raylib usage from the codebase.
Going to either fully commit to sokol or if it fails, rolling the platform layer myself.
This commit is contained in:
parent
13c3032dba
commit
797ab227e9
@ -3,11 +3,10 @@ package sectr
|
||||
// Scratch space
|
||||
|
||||
import sokol_gfx "thirdparty:sokol/gfx"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
DebugData :: struct {
|
||||
square_size : i32,
|
||||
square_pos : rl.Vector2,
|
||||
square_pos : Vec2,
|
||||
|
||||
debug_text_vis : b32,
|
||||
draw_debug_text_y : f32,
|
||||
@ -35,10 +34,6 @@ DebugData :: struct {
|
||||
lorem_content : []byte,
|
||||
lorem_parse : PWS_ParseResult,
|
||||
|
||||
// Test 3d Viewport
|
||||
cam_vp : rl.Camera3D,
|
||||
viewport_rt : rl.RenderTexture,
|
||||
|
||||
gfx_clear_demo_pass_action : sokol_gfx.Pass_Action,
|
||||
gfx_tri_demo_state : struct {
|
||||
pipeline : sokol_gfx.Pipeline,
|
||||
|
@ -6,8 +6,6 @@ import "core:mem"
|
||||
import "core:mem/virtual"
|
||||
import "core:os"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Str_App_State := "App State"
|
||||
|
||||
#region("Memory")
|
||||
@ -167,6 +165,7 @@ AppWindow :: struct {
|
||||
extent : Extents2, // Window half-size
|
||||
dpi_scale : f32, // Dots per inch scale (provided by raylib via glfw)
|
||||
ppcm : f32, // Dots per centimetre
|
||||
resized : b32, // Extent changed this frame
|
||||
}
|
||||
|
||||
FontData :: struct {
|
||||
@ -241,9 +240,14 @@ State :: struct {
|
||||
font_rec_mono_semicasual_reg : FontID,
|
||||
default_font : FontID,
|
||||
|
||||
|
||||
// Context tracking
|
||||
// These are used as implicit contextual states when doing immediate mode interfaces
|
||||
// or for event callbacks that need their context assigned
|
||||
|
||||
// There are two potential UI contextes for this prototype so far,
|
||||
// the screen-space UI and the current workspace UI.
|
||||
// This is used so that the ui api doesn't need to have the user pass the context every single time.
|
||||
// This is used so that the ui api doesn't need to have the user pass the context through every proc.
|
||||
ui_context : ^UI_State,
|
||||
ui_floating_context : ^UI_FloatingManager,
|
||||
|
||||
|
@ -116,12 +116,12 @@ theme_table_row :: proc( is_even : bool ) -> UI_Theme
|
||||
if ! loaded
|
||||
{
|
||||
app_color := app_color_theme()
|
||||
table_bg : Color
|
||||
table_bg : RGBA8
|
||||
if is_even {
|
||||
table_bg = app_color.table_even_bg_color
|
||||
table_bg = app_color.table_even_bg
|
||||
}
|
||||
else {
|
||||
table_bg = app_color.table_odd_bg_color
|
||||
table_bg = app_color.table_odd_bg
|
||||
}
|
||||
layout := UI_Layout {
|
||||
flags = {},
|
||||
|
@ -1,32 +1,29 @@
|
||||
package sectr
|
||||
|
||||
import rl "vendor:raylib"
|
||||
RGBA8 :: struct { r, g, b, a : u8 }
|
||||
Color_Blue :: RGBA8 { 90, 90, 230, 255 }
|
||||
Color_Red :: RGBA8 { 230, 90, 90, 255 }
|
||||
Color_White :: RGBA8 { 255, 255, 255, 255 }
|
||||
|
||||
Color :: rl.Color
|
||||
Color_Blue :: rl.BLUE
|
||||
// Color_Green :: rl.GREEN
|
||||
Color_Red :: rl.RED
|
||||
Color_White :: rl.WHITE
|
||||
Color_Transparent :: RGBA8 { 0, 0, 0, 0 }
|
||||
Color_BG :: RGBA8 { 55, 55, 60, 255 }
|
||||
Color_BG_TextBox :: RGBA8 { 32, 32, 32, 180 }
|
||||
Color_BG_Panel :: RGBA8 { 32, 32, 32, 255 }
|
||||
Color_BG_Panel_Translucent :: RGBA8 { 32, 32, 32, 220 }
|
||||
Color_BG_TextBox_Green :: RGBA8 { 102, 102, 110, 255 }
|
||||
Color_Frame_Disabled :: RGBA8 { 22, 22, 22, 120 }
|
||||
Color_Frame_Hover :: RGBA8 { 122, 122, 125, 200 }
|
||||
Color_Frame_Select :: RGBA8 { 188, 188, 188, 220 }
|
||||
Color_GreyRed :: RGBA8 { 220, 100, 100, 50 }
|
||||
Color_White_A125 :: RGBA8 { 255, 255, 255, 165 }
|
||||
Color_Black :: RGBA8 { 0, 0, 0, 255 }
|
||||
Color_Green :: RGBA8 { 0, 180, 0, 255 }
|
||||
Color_ResizeHandle :: RGBA8 { 80, 80, 90, 180 }
|
||||
|
||||
Color_Transparent :: Color { 0, 0, 0, 0 }
|
||||
Color_BG :: Color { 55, 55, 60, 255 }
|
||||
Color_BG_TextBox :: Color { 32, 32, 32, 180 }
|
||||
Color_BG_Panel :: Color { 32, 32, 32, 255 }
|
||||
Color_BG_Panel_Translucent :: Color { 32, 32, 32, 220 }
|
||||
Color_BG_TextBox_Green :: Color { 102, 102, 110, 255 }
|
||||
Color_Frame_Disabled :: Color { 22, 22, 22, 120 }
|
||||
Color_Frame_Hover :: Color { 122, 122, 125, 200 }
|
||||
Color_Frame_Select :: Color { 188, 188, 188, 220 }
|
||||
Color_GreyRed :: Color { 220, 100, 100, 50 }
|
||||
Color_White_A125 :: Color { 255, 255, 255, 165 }
|
||||
Color_Black :: Color { 0, 0, 0, 255 }
|
||||
Color_Green :: Color { 0, 180, 0, 255 }
|
||||
Color_ResizeHandle :: Color { 80, 80, 90, 180 }
|
||||
RGBA8_3D_BG :: RGBA8 { 188, 182 , 170, 255 }
|
||||
|
||||
Color_3D_BG :: Color { 188, 182 , 170, 255 }
|
||||
|
||||
Color_Debug_UI_Padding_Bounds :: Color { 40, 195, 170, 160 }
|
||||
Color_Debug_UI_Content_Bounds :: Color { 170, 120, 240, 160 }
|
||||
RGBA8_Debug_UI_Padding_Bounds :: RGBA8 { 40, 195, 170, 160 }
|
||||
RGBA8_Debug_UI_Content_Bounds :: RGBA8 { 170, 120, 240, 160 }
|
||||
|
||||
// TODO(Ed): The entire rendering pass should be post-processed by a tone curve configurable for the user
|
||||
// This is how you properly support any tonality of light or dark themes and not have it be base don the monitors raw output.
|
||||
@ -51,8 +48,8 @@ AppColorTheme :: struct {
|
||||
resize_hndl_hot,
|
||||
resize_hndl_active,
|
||||
|
||||
table_even_bg_color,
|
||||
table_odd_bg_color,
|
||||
table_even_bg,
|
||||
table_odd_bg,
|
||||
|
||||
text_default,
|
||||
text_hot,
|
||||
@ -66,116 +63,116 @@ AppColorTheme :: struct {
|
||||
|
||||
window_panel_bg,
|
||||
window_panel_border \
|
||||
: Color
|
||||
: RGBA8
|
||||
}
|
||||
|
||||
App_Thm_Dark :: AppColorTheme {
|
||||
light_limit = Color {185, 185, 185, 255},
|
||||
dark_limit = Color { 6, 6, 6, 255},
|
||||
light_limit = RGBA8 {185, 185, 185, 255},
|
||||
dark_limit = RGBA8 { 6, 6, 6, 255},
|
||||
|
||||
bg = Color {16, 16, 16, 255},
|
||||
bg = RGBA8 {16, 16, 16, 255},
|
||||
|
||||
border_default = Color { 54, 54, 54, 255},
|
||||
border_default = RGBA8 { 54, 54, 54, 255},
|
||||
|
||||
btn_bg_default = Color { 32, 32, 32, 255},
|
||||
btn_bg_hot = Color { 80, 80, 100, 255},
|
||||
btn_bg_active = Color { 100, 130, 180, 255},
|
||||
btn_bg_default = RGBA8 { 32, 32, 32, 255},
|
||||
btn_bg_hot = RGBA8 { 80, 80, 100, 255},
|
||||
btn_bg_active = RGBA8 { 100, 130, 180, 255},
|
||||
|
||||
input_box_bg = Color { 20, 20, 20, 255},
|
||||
input_box_bg_hot = Color { 25, 25, 25, 255},
|
||||
input_box_bg_active = Color { 15, 15, 15, 255},
|
||||
input_box_bg = RGBA8 { 20, 20, 20, 255},
|
||||
input_box_bg_hot = RGBA8 { 25, 25, 25, 255},
|
||||
input_box_bg_active = RGBA8 { 15, 15, 15, 255},
|
||||
|
||||
resize_hndl_default = Color_Transparent,
|
||||
resize_hndl_hot = Color { 72, 72, 72, 90},
|
||||
resize_hndl_active = Color { 88, 88, 88, 90},
|
||||
resize_hndl_hot = RGBA8 { 72, 72, 72, 90},
|
||||
resize_hndl_active = RGBA8 { 88, 88, 88, 90},
|
||||
|
||||
table_even_bg_color = Color { 35, 35, 35, 255},
|
||||
table_odd_bg_color = Color { 30, 30, 30, 255},
|
||||
table_even_bg = RGBA8 { 35, 35, 35, 255},
|
||||
table_odd_bg = RGBA8 { 30, 30, 30, 255},
|
||||
|
||||
text_default = Color {140, 137, 135, 255},
|
||||
text_hot = Color {210, 210, 210, 255},
|
||||
text_active = Color {255, 255, 255, 255},
|
||||
text_default = RGBA8 {140, 137, 135, 255},
|
||||
text_hot = RGBA8 {210, 210, 210, 255},
|
||||
text_active = RGBA8 {255, 255, 255, 255},
|
||||
|
||||
translucent_panel = Color { 30, 30, 30, 50},
|
||||
translucent_panel = RGBA8 { 30, 30, 30, 50},
|
||||
|
||||
window_bar_border = Color{74, 74, 74, 255},
|
||||
window_bar_bg = Color{32, 32, 32, 255},
|
||||
window_btn_close_bg_hot = Color{65, 45, 45, 255},
|
||||
window_bar_border = RGBA8{74, 74, 74, 255},
|
||||
window_bar_bg = RGBA8{32, 32, 32, 255},
|
||||
window_btn_close_bg_hot = RGBA8{65, 45, 45, 255},
|
||||
|
||||
window_panel_bg = Color{ 20, 20, 20, 50},
|
||||
window_panel_border = Color{ 84, 84, 84, 255},
|
||||
window_panel_bg = RGBA8{ 20, 20, 20, 50},
|
||||
window_panel_border = RGBA8{ 84, 84, 84, 255},
|
||||
}
|
||||
|
||||
App_Thm_Dusk :: AppColorTheme {
|
||||
light_limit = Color {125, 125, 125, 255},
|
||||
dark_limit = Color { 10, 10, 10, 255},
|
||||
light_limit = RGBA8 {125, 125, 125, 255},
|
||||
dark_limit = RGBA8 { 10, 10, 10, 255},
|
||||
|
||||
bg = Color {33, 33, 33, 255},
|
||||
bg = RGBA8 {33, 33, 33, 255},
|
||||
|
||||
border_default = Color { 64, 64, 64, 255},
|
||||
border_default = RGBA8 { 64, 64, 64, 255},
|
||||
|
||||
btn_bg_default = Color { 40, 40, 40, 255},
|
||||
btn_bg_hot = Color { 60, 60, 70, 255},
|
||||
btn_bg_active = Color { 90, 100, 130, 255},
|
||||
btn_bg_default = RGBA8 { 40, 40, 40, 255},
|
||||
btn_bg_hot = RGBA8 { 60, 60, 70, 255},
|
||||
btn_bg_active = RGBA8 { 90, 100, 130, 255},
|
||||
|
||||
input_box_bg = Color { 20, 20, 20, 255},
|
||||
input_box_bg_hot = Color { 25, 25, 25, 255},
|
||||
input_box_bg_active = Color { 15, 15, 15, 255},
|
||||
input_box_bg = RGBA8 { 20, 20, 20, 255},
|
||||
input_box_bg_hot = RGBA8 { 25, 25, 25, 255},
|
||||
input_box_bg_active = RGBA8 { 15, 15, 15, 255},
|
||||
|
||||
resize_hndl_default = Color_Transparent,
|
||||
resize_hndl_hot = Color { 72, 72, 72, 90},
|
||||
resize_hndl_active = Color { 88, 88, 88, 90},
|
||||
resize_hndl_hot = RGBA8 { 72, 72, 72, 90},
|
||||
resize_hndl_active = RGBA8 { 88, 88, 88, 90},
|
||||
|
||||
table_even_bg_color = Color { 35, 35, 35, 255},
|
||||
table_odd_bg_color = Color { 30, 30, 30, 255},
|
||||
table_even_bg = RGBA8 { 35, 35, 35, 255},
|
||||
table_odd_bg = RGBA8 { 30, 30, 30, 255},
|
||||
|
||||
text_default = Color {120, 117, 115, 255},
|
||||
text_hot = Color {180, 180, 180, 255},
|
||||
text_active = Color {240, 240, 240, 255},
|
||||
text_default = RGBA8 {120, 117, 115, 255},
|
||||
text_hot = RGBA8 {180, 180, 180, 255},
|
||||
text_active = RGBA8 {240, 240, 240, 255},
|
||||
|
||||
translucent_panel = Color { 10, 10, 10, 50},
|
||||
translucent_panel = RGBA8 { 10, 10, 10, 50},
|
||||
|
||||
window_bar_border = Color { 64, 64, 64, 255}, // border_default
|
||||
window_bar_bg = Color{35, 35, 35, 255},
|
||||
window_btn_close_bg_hot = Color{45, 35, 35, 255},
|
||||
window_bar_border = RGBA8 { 64, 64, 64, 255}, // border_default
|
||||
window_bar_bg = RGBA8{35, 35, 35, 255},
|
||||
window_btn_close_bg_hot = RGBA8{45, 35, 35, 255},
|
||||
|
||||
window_panel_bg = Color { 10, 10, 10, 50}, // translucent_panel
|
||||
window_panel_border = Color{24, 24, 24, 255},
|
||||
window_panel_bg = RGBA8 { 10, 10, 10, 50}, // translucent_panel
|
||||
window_panel_border = RGBA8{24, 24, 24, 255},
|
||||
}
|
||||
|
||||
App_Thm_Light :: AppColorTheme {
|
||||
light_limit = Color {195, 195, 195, 255},
|
||||
dark_limit = Color { 60, 60, 60, 255},
|
||||
light_limit = RGBA8 {195, 195, 195, 255},
|
||||
dark_limit = RGBA8 { 60, 60, 60, 255},
|
||||
|
||||
bg = Color {135, 135, 135, 255},
|
||||
bg = RGBA8 {135, 135, 135, 255},
|
||||
|
||||
border_default = Color { 174, 174, 174, 255},
|
||||
border_default = RGBA8 { 174, 174, 174, 255},
|
||||
|
||||
btn_bg_default = Color { 160, 160, 160, 255},
|
||||
btn_bg_hot = Color { 145, 145, 155, 255},
|
||||
btn_bg_active = Color { 124, 124, 136, 255},
|
||||
btn_bg_default = RGBA8 { 160, 160, 160, 255},
|
||||
btn_bg_hot = RGBA8 { 145, 145, 155, 255},
|
||||
btn_bg_active = RGBA8 { 124, 124, 136, 255},
|
||||
|
||||
input_box_bg = Color {115, 115, 115, 255},
|
||||
input_box_bg_hot = Color {125, 125, 125, 255},
|
||||
input_box_bg_active = Color {105, 105, 105, 255},
|
||||
input_box_bg = RGBA8 {115, 115, 115, 255},
|
||||
input_box_bg_hot = RGBA8 {125, 125, 125, 255},
|
||||
input_box_bg_active = RGBA8 {105, 105, 105, 255},
|
||||
|
||||
resize_hndl_default = Color_Transparent,
|
||||
resize_hndl_hot = Color { 95, 95, 95, 90},
|
||||
resize_hndl_active = Color { 80, 80, 80, 90},
|
||||
resize_hndl_hot = RGBA8 { 95, 95, 95, 90},
|
||||
resize_hndl_active = RGBA8 { 80, 80, 80, 90},
|
||||
|
||||
table_even_bg_color = Color {150, 150, 150, 255},
|
||||
table_odd_bg_color = Color {160, 160, 160, 255},
|
||||
table_even_bg = RGBA8 {150, 150, 150, 255},
|
||||
table_odd_bg = RGBA8 {160, 160, 160, 255},
|
||||
|
||||
text_default = Color { 55, 55, 55, 255},
|
||||
text_hot = Color { 85, 85, 85, 255},
|
||||
text_active = Color { 45, 45, 49, 255},
|
||||
text_default = RGBA8 { 55, 55, 55, 255},
|
||||
text_hot = RGBA8 { 85, 85, 85, 255},
|
||||
text_active = RGBA8 { 45, 45, 49, 255},
|
||||
|
||||
translucent_panel = Color { 110, 110, 110, 50},
|
||||
translucent_panel = RGBA8 { 110, 110, 110, 50},
|
||||
|
||||
window_bar_border = Color{ 174, 174, 174, 255}, // border_default
|
||||
window_bar_bg = Color{ 155, 155, 155, 255},
|
||||
window_btn_close_bg_hot = Color{ 145, 135, 135, 255},
|
||||
window_bar_border = RGBA8{ 174, 174, 174, 255}, // border_default
|
||||
window_bar_bg = RGBA8{ 155, 155, 155, 255},
|
||||
window_btn_close_bg_hot = RGBA8{ 145, 135, 135, 255},
|
||||
|
||||
window_panel_bg = Color {135, 135, 135, 50}, // translucent_panel
|
||||
window_panel_border = Color{184, 184, 184, 255},
|
||||
window_panel_bg = RGBA8 {135, 135, 135, 50}, // translucent_panel
|
||||
window_panel_border = RGBA8{184, 184, 184, 255},
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ import sokol_app "thirdparty:sokol/app"
|
||||
import sokol_gfx "thirdparty:sokol/gfx"
|
||||
import sokol_app_gfx_glue "thirdparty:sokol/glue"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Path_Assets :: "../assets/"
|
||||
Path_Shaders :: "../shaders/"
|
||||
Path_Input_Replay :: "scratch.sectr_replay"
|
||||
@ -104,15 +102,17 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
}
|
||||
|
||||
// Setup input frame poll references
|
||||
input = & input_data[1]
|
||||
input_prev = & input_data[0]
|
||||
for & input in input_data {
|
||||
using input
|
||||
error : AllocatorError
|
||||
keyboard_events.keys_pressed, error = array_init_reserve(KeyCode, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.keys_pressed array")
|
||||
keyboard_events.chars_pressed, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.chars_pressed array")
|
||||
{
|
||||
input = & input_data[1]
|
||||
input_prev = & input_data[0]
|
||||
for & input in input_data {
|
||||
using input
|
||||
error : AllocatorError
|
||||
keyboard_events.keys_pressed, error = array_init_reserve(KeyCode, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.keys_pressed array")
|
||||
keyboard_events.chars_pressed, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.chars_pressed array")
|
||||
}
|
||||
}
|
||||
|
||||
// Configuration Load
|
||||
@ -305,9 +305,9 @@ startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem
|
||||
{
|
||||
using project.workspace
|
||||
cam = {
|
||||
target = { 0, 0 },
|
||||
offset = transmute(Vec2) app_window.extent,
|
||||
rotation = 0,
|
||||
position = { 0, 0 },
|
||||
view = transmute(Vec2) app_window.extent,
|
||||
// rotation = 0,
|
||||
zoom = 1.0,
|
||||
}
|
||||
// cam = {
|
@ -1,424 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import "base:runtime"
|
||||
import c "core:c/libc"
|
||||
import "core:dynlib"
|
||||
import "core:mem"
|
||||
import "core:mem/virtual"
|
||||
import "core:os"
|
||||
import "core:slice"
|
||||
import "core:strings"
|
||||
import "core:time"
|
||||
import "core:prof/spall"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
when false {
|
||||
Path_Assets :: "../assets/"
|
||||
Path_Shaders :: "../shaders/"
|
||||
Path_Input_Replay :: "scratch.sectr_replay"
|
||||
|
||||
Persistent_Slab_DBG_Name := "Peristent Slab"
|
||||
Frame_Slab_DBG_Name := "Frame Slab"
|
||||
Transient_Slab_DBG_Name := "Transient Slab"
|
||||
|
||||
ModuleAPI :: struct {
|
||||
lib : dynlib.Library,
|
||||
write_time : FileTime,
|
||||
lib_version : i32,
|
||||
|
||||
startup : type_of( startup ),
|
||||
shutdown : type_of( sectr_shutdown ),
|
||||
reload : type_of( reload ),
|
||||
tick : type_of( tick ),
|
||||
clean_frame : type_of( clean_frame ),
|
||||
}
|
||||
|
||||
@export
|
||||
startup :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^Logger )
|
||||
{
|
||||
spall.SCOPED_EVENT( & prof.ctx, & prof.buffer, #procedure )
|
||||
Memory_App.profiler = prof
|
||||
|
||||
startup_tick := time.tick_now()
|
||||
|
||||
logger_init( & Memory_App.logger, "Sectr", host_logger.file_path, host_logger.file )
|
||||
context.logger = to_odin_logger( & Memory_App.logger )
|
||||
|
||||
// Setup memory for the first time
|
||||
{
|
||||
using Memory_App;
|
||||
persistent = persistent_mem
|
||||
frame = frame_mem
|
||||
transient = transient_mem
|
||||
files_buffer = files_buffer_mem
|
||||
|
||||
context.allocator = transient_allocator()
|
||||
context.temp_allocator = transient_allocator()
|
||||
// TODO(Ed) : Put on the transient allocator a slab allocator (transient slab)
|
||||
}
|
||||
|
||||
state := new( State, persistent_allocator() )
|
||||
Memory_App.state = state
|
||||
using state
|
||||
|
||||
// Setup Persistent Slabs & String Cache
|
||||
{
|
||||
alignment := uint(mem.DEFAULT_ALIGNMENT)
|
||||
|
||||
policy_ptr := & default_slab_policy
|
||||
push( policy_ptr, SlabSizeClass { 128 * Kilobyte, 1 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 256 * Kilobyte, 2 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 512 * Kilobyte, 4 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 1 * Megabyte, 16 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 1 * Megabyte, 32 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 1 * Megabyte, 64 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 128 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 256 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 512 * Kilobyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 1 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 2 * Megabyte, 2 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 4 * Megabyte, 4 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 8 * Megabyte, 8 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 16 * Megabyte, 16 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 32 * Megabyte, 32 * Megabyte, alignment })
|
||||
push( policy_ptr, SlabSizeClass { 64 * Megabyte, 64 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 128 * Megabyte, 128 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 256 * Megabyte, 256 * Megabyte, alignment })
|
||||
// push( policy_ptr, SlabSizeClass { 512 * Megabyte, 512 * Megabyte, alignment })
|
||||
|
||||
alloc_error : AllocatorError
|
||||
persistent_slab, alloc_error = slab_init( policy_ptr, allocator = persistent_allocator(), dbg_name = Persistent_Slab_DBG_Name )
|
||||
verify( alloc_error == .None, "Failed to allocate the persistent slab" )
|
||||
|
||||
transient_slab, alloc_error = slab_init( & default_slab_policy, allocator = transient_allocator(), dbg_name = Transient_Slab_DBG_Name )
|
||||
verify( alloc_error == .None, "Failed to allocate transient slab" )
|
||||
|
||||
transient_clear_time = 120 // Seconds, 2 Minutes
|
||||
|
||||
string_cache = str_cache_init()
|
||||
}
|
||||
|
||||
// Setup input frame poll references
|
||||
input = & input_data[1]
|
||||
input_prev = & input_data[0]
|
||||
for & input in input_data {
|
||||
using input
|
||||
error : AllocatorError
|
||||
keyboard_events.keys_pressed, error = array_init_reserve(KeyCode, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.keys_pressed array")
|
||||
keyboard_events.chars_pressed, error = array_init_reserve(rune, persistent_slab_allocator(), Kilo)
|
||||
ensure(error == AllocatorError.None, "Failed to allocate input.keyboard_events.chars_pressed array")
|
||||
}
|
||||
|
||||
// Configuration Load
|
||||
// TODO(Ed): Make this actually load from an ini
|
||||
{
|
||||
using config
|
||||
resolution_width = 1000
|
||||
resolution_height = 600
|
||||
refresh_rate = 0
|
||||
|
||||
cam_min_zoom = 0.10
|
||||
cam_max_zoom = 30.0
|
||||
cam_zoom_mode = .Smooth
|
||||
cam_zoom_smooth_snappiness = 4.0
|
||||
cam_zoom_sensitivity_digital = 0.2
|
||||
cam_zoom_sensitivity_smooth = 4.0
|
||||
|
||||
engine_refresh_hz = 0
|
||||
|
||||
timing_fps_moving_avg_alpha = 0.9
|
||||
|
||||
ui_resize_border_width = 5
|
||||
|
||||
color_theme = App_Thm_Dusk
|
||||
}
|
||||
|
||||
Desired_OS_Scheduler_MS :: 1
|
||||
sleep_is_granular = set__scheduler_granularity( Desired_OS_Scheduler_MS )
|
||||
|
||||
// Rough setup of window with rl stuff
|
||||
{
|
||||
// rl.Odin_SetMalloc( RL_MALLOC )
|
||||
|
||||
rl.SetConfigFlags( {
|
||||
rl.ConfigFlag.WINDOW_RESIZABLE,
|
||||
rl.ConfigFlag.WINDOW_TOPMOST,
|
||||
})
|
||||
|
||||
window_width : i32 = cast(i32) config.resolution_width
|
||||
window_height : i32 = cast(i32) config.resolution_height
|
||||
win_title : cstring = "Sectr Prototype"
|
||||
rl.InitWindow( window_width, window_height, win_title )
|
||||
log( "Raylib initialized and window opened" )
|
||||
|
||||
window := & state.app_window
|
||||
window.extent.x = f32(window_width) * 0.5
|
||||
window.extent.y = f32(window_height) * 0.5
|
||||
|
||||
// We do not support non-uniform DPI.
|
||||
window.dpi_scale = rl.GetWindowScaleDPI().x
|
||||
window.ppcm = os_default_ppcm * window.dpi_scale
|
||||
|
||||
// Determining current monitor and setting the target frametime based on it..
|
||||
monitor_id = rl.GetCurrentMonitor()
|
||||
monitor_refresh_hz = rl.GetMonitorRefreshRate( monitor_id )
|
||||
|
||||
if config.engine_refresh_hz == 0 {
|
||||
config.engine_refresh_hz = uint(monitor_refresh_hz)
|
||||
}
|
||||
}
|
||||
|
||||
// Basic Font Setup
|
||||
{
|
||||
font_provider_startup()
|
||||
// path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" })
|
||||
// font_rec_mono_semicasual_reg = font_load( path_rec_mono_semicasual_reg, 24.0, "RecMonoSemiCasual_Regular" )
|
||||
|
||||
// path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } )
|
||||
// font_squidgy_slimes = font_load( path_squidgy_slimes, 24.0, "Squidgy_Slime" )
|
||||
|
||||
path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" }, transient_allocator() )
|
||||
font_firacode = font_load( path_firacode, 24.0, "FiraCode" )
|
||||
default_font = font_firacode
|
||||
log( "Default font loaded" )
|
||||
}
|
||||
|
||||
// Setup the screen ui state
|
||||
{
|
||||
ui_startup( & screen_ui.base, cache_allocator = persistent_slab_allocator() )
|
||||
ui_floating_startup( & screen_ui.floating, persistent_slab_allocator(), 1 * Kilobyte, 1 * Kilobyte, "screen ui floating manager" )
|
||||
|
||||
using screen_ui
|
||||
menu_bar.pos = { -60, 0 }
|
||||
// menu_bar.pos = Vec2(app_window.extent) * { -1, 1 }
|
||||
menu_bar.size = {140, 40}
|
||||
|
||||
settings_menu.min_size = {250, 200}
|
||||
}
|
||||
|
||||
// Demo project setup
|
||||
// TODO(Ed): This will eventually have to occur when the user either creates or loads a workspace. I don't know
|
||||
{
|
||||
using project
|
||||
path = str_intern("./")
|
||||
name = str_intern( "First Project" )
|
||||
workspace.name = str_intern( "First Workspace" )
|
||||
{
|
||||
using project.workspace
|
||||
cam = {
|
||||
target = { 0, 0 },
|
||||
offset = transmute(Vec2) app_window.extent,
|
||||
rotation = 0,
|
||||
zoom = 1.0,
|
||||
}
|
||||
// cam = {
|
||||
// position = { 0, 0, -100 },
|
||||
// target = { 0, 0, 0 },
|
||||
// up = { 0, 1, 0 },
|
||||
// fovy = 90,
|
||||
// projection = rl.CameraProjection.ORTHOGRAPHIC,
|
||||
// }
|
||||
|
||||
// Setup workspace UI state
|
||||
ui_startup( & workspace.ui, cache_allocator = persistent_slab_allocator() )
|
||||
}
|
||||
|
||||
debug.path_lorem = str_fmt("C:/projects/SectrPrototype/examples/Lorem Ipsum.txt", allocator = persistent_slab_allocator())
|
||||
|
||||
alloc_error : AllocatorError; success : bool
|
||||
debug.lorem_content, success = os.read_entire_file( debug.path_lorem, persistent_slab_allocator() )
|
||||
|
||||
debug.lorem_parse, alloc_error = pws_parser_parse( transmute(string) debug.lorem_content, persistent_slab_allocator() )
|
||||
verify( alloc_error == .None, "Faield to parse due to allocation failure" )
|
||||
|
||||
// Render texture test
|
||||
// debug.viewport_rt = rl.LoadRenderTexture( 1280, 720 )
|
||||
|
||||
// debug.proto_text_shader = rl.LoadShader( "C:/projects/SectrPrototype/code/shaders/text_shader.vs", "C:/projects/SectrPrototype/code/shaders/text_shader.fs" )
|
||||
}
|
||||
|
||||
startup_ms := duration_ms( time.tick_lap_time( & startup_tick))
|
||||
log( str_fmt_tmp("Startup time: %v ms", startup_ms) )
|
||||
|
||||
// Make sure to cleanup transient before continuing...
|
||||
// From here on, tarnsinet usage has to be done with care.
|
||||
// For most cases, the frame allocator should be more than enough.
|
||||
}
|
||||
|
||||
// For some reason odin's symbols conflict with native foreign symbols...
|
||||
@export
|
||||
sectr_shutdown :: proc()
|
||||
{
|
||||
context.logger = to_odin_logger( & Memory_App.logger )
|
||||
|
||||
if Memory_App.persistent == nil {
|
||||
return
|
||||
}
|
||||
state := get_state()
|
||||
|
||||
// Replay
|
||||
{
|
||||
file_close( Memory_App.replay.active_file )
|
||||
}
|
||||
|
||||
font_provider_shutdown()
|
||||
|
||||
log("Module shutdown complete")
|
||||
}
|
||||
|
||||
@export
|
||||
reload :: proc( prof : ^SpallProfiler, persistent_mem, frame_mem, transient_mem, files_buffer_mem : ^VArena, host_logger : ^ Logger )
|
||||
{
|
||||
spall.SCOPED_EVENT( & prof.ctx, & prof.buffer, #procedure )
|
||||
Memory_App.profiler = prof
|
||||
|
||||
context.logger = to_odin_logger( & Memory_App.logger )
|
||||
using Memory_App;
|
||||
|
||||
persistent = persistent_mem
|
||||
frame = frame_mem
|
||||
transient = transient_mem
|
||||
files_buffer = files_buffer_mem
|
||||
|
||||
context.allocator = persistent_allocator()
|
||||
context.temp_allocator = transient_allocator()
|
||||
|
||||
Memory_App.state = get_state()
|
||||
using state
|
||||
|
||||
// Procedure Addresses are not preserved on hot-reload. They must be restored for persistent data.
|
||||
// The only way to alleviate this is to either do custom handles to allocators
|
||||
// Or as done below, correct containers using allocators on reload.
|
||||
// Thankfully persistent dynamic allocations are rare, and thus we know exactly which ones they are.
|
||||
|
||||
slab_reload( persistent_slab, persistent_allocator() )
|
||||
|
||||
hmap_chained_reload( font_provider_data.font_cache, persistent_allocator())
|
||||
|
||||
slab_reload( string_cache.slab, persistent_allocator() )
|
||||
zpl_hmap_reload( & string_cache.table, persistent_slab_allocator())
|
||||
|
||||
slab_reload( frame_slab, frame_allocator())
|
||||
slab_reload( transient_slab, transient_allocator())
|
||||
|
||||
ui_reload( & get_state().project.workspace.ui, cache_allocator = persistent_slab_allocator() )
|
||||
|
||||
log("Module reloaded")
|
||||
}
|
||||
|
||||
@export
|
||||
tick :: proc( host_delta_time : f64, host_delta_ns : Duration ) -> b32
|
||||
{
|
||||
profile( "Client Tick" )
|
||||
context.logger = to_odin_logger( & Memory_App.logger )
|
||||
state := get_state(); using state
|
||||
|
||||
should_close : b32
|
||||
|
||||
client_tick := time.tick_now()
|
||||
{
|
||||
profile("Work frame")
|
||||
|
||||
// Setup Frame Slab
|
||||
{
|
||||
alloc_error : AllocatorError
|
||||
frame_slab, alloc_error = slab_init( & default_slab_policy, bucket_reserve_num = 0,
|
||||
allocator = frame_allocator(),
|
||||
dbg_name = Frame_Slab_DBG_Name,
|
||||
should_zero_buckets = true )
|
||||
verify( alloc_error == .None, "Failed to allocate frame slab" )
|
||||
}
|
||||
|
||||
context.allocator = frame_slab_allocator()
|
||||
context.temp_allocator = transient_allocator()
|
||||
|
||||
rl.PollInputEvents()
|
||||
|
||||
debug.draw_ui_box_bounds_points = false
|
||||
debug.draw_UI_padding_bounds = false
|
||||
debug.draw_ui_content_bounds = false
|
||||
|
||||
// config.color_theme = App_Thm_Light
|
||||
// config.color_theme = App_Thm_Dusk
|
||||
config.color_theme = App_Thm_Dark
|
||||
|
||||
should_close = update( host_delta_time )
|
||||
render()
|
||||
|
||||
rl.SwapScreenBuffer()
|
||||
}
|
||||
|
||||
// Timing
|
||||
{
|
||||
// profile("Client tick timing processing")
|
||||
// config.engine_refresh_hz = uint(monitor_refresh_hz)
|
||||
// config.engine_refresh_hz = 6
|
||||
frametime_target_ms = 1.0 / f64(config.engine_refresh_hz) * S_To_MS
|
||||
sub_ms_granularity_required := frametime_target_ms <= Frametime_High_Perf_Threshold_MS
|
||||
|
||||
frametime_delta_ns = time.tick_lap_time( & client_tick )
|
||||
frametime_delta_ms = duration_ms( frametime_delta_ns )
|
||||
frametime_delta_seconds = duration_seconds( frametime_delta_ns )
|
||||
frametime_elapsed_ms = frametime_delta_ms + host_delta_time
|
||||
|
||||
if frametime_elapsed_ms < frametime_target_ms
|
||||
{
|
||||
sleep_ms := frametime_target_ms - frametime_elapsed_ms
|
||||
pre_sleep_tick := time.tick_now()
|
||||
|
||||
if sleep_ms > 0 {
|
||||
thread_sleep( cast(Duration) sleep_ms * MS_To_NS )
|
||||
// thread__highres_wait( sleep_ms )
|
||||
}
|
||||
|
||||
sleep_delta_ns := time.tick_lap_time( & pre_sleep_tick)
|
||||
sleep_delta_ms := duration_ms( sleep_delta_ns )
|
||||
|
||||
if sleep_delta_ms < sleep_ms {
|
||||
// log( str_fmt_tmp("frametime sleep was off by: %v ms", sleep_delta_ms - sleep_ms ))
|
||||
}
|
||||
|
||||
frametime_elapsed_ms += sleep_delta_ms
|
||||
for ; frametime_elapsed_ms < frametime_target_ms; {
|
||||
sleep_delta_ns = time.tick_lap_time( & pre_sleep_tick)
|
||||
sleep_delta_ms = duration_ms( sleep_delta_ns )
|
||||
|
||||
frametime_elapsed_ms += sleep_delta_ms
|
||||
}
|
||||
}
|
||||
|
||||
config.timing_fps_moving_avg_alpha = 0.99
|
||||
frametime_avg_ms = mov_avg_exp( f64(config.timing_fps_moving_avg_alpha), frametime_elapsed_ms, frametime_avg_ms )
|
||||
fps_avg = 1 / (frametime_avg_ms * MS_To_S)
|
||||
|
||||
if frametime_elapsed_ms > 60.0 {
|
||||
context.allocator = transient_allocator()
|
||||
log( str_fmt("Big tick! %v ms", frametime_elapsed_ms), LogLevel.Warning )
|
||||
}
|
||||
}
|
||||
return should_close
|
||||
}
|
||||
|
||||
@export
|
||||
clean_frame :: proc()
|
||||
{
|
||||
// profile( #procedure)
|
||||
state := get_state(); using state
|
||||
context.logger = to_odin_logger( & Memory_App.logger )
|
||||
|
||||
free_all( frame_allocator() )
|
||||
|
||||
transient_clear_elapsed += frametime_delta32()
|
||||
if transient_clear_elapsed >= transient_clear_time && ! transinet_clear_lock
|
||||
{
|
||||
transient_clear_elapsed = 0
|
||||
free_all( transient_allocator() )
|
||||
|
||||
alloc_error : AllocatorError
|
||||
transient_slab, alloc_error = slab_init( & default_slab_policy, allocator = transient_allocator(), dbg_name = Transient_Slab_DBG_Name )
|
||||
verify( alloc_error == .None, "Failed to allocate transient slab" )
|
||||
}
|
||||
}
|
||||
|
||||
} // when false
|
@ -26,8 +26,9 @@ sokol_app_frame_callback :: proc "c" () {
|
||||
|
||||
window := & state.app_window
|
||||
if int(window.extent.x) != int(sokol_width) || int(window.extent.y) != int(sokol_height) {
|
||||
window.extent.x = sokol_width
|
||||
window.extent.y = sokol_height
|
||||
window.resized = true
|
||||
window.extent.x = sokol_width * 0.5
|
||||
window.extent.y = sokol_height * 0.5
|
||||
log("sokol_app: Event-based frame callback triggered (detected a resize")
|
||||
}
|
||||
|
||||
@ -38,6 +39,8 @@ sokol_app_frame_callback :: proc "c" () {
|
||||
client_tick := time.tick_now()
|
||||
should_close |= tick_work_frame( sokol_delta_ms )
|
||||
tick_frametime( & client_tick, sokol_delta_ms, sokol_delta_ns )
|
||||
|
||||
window.resized = false
|
||||
}
|
||||
|
||||
sokol_app_cleanup_callback :: proc "c" () {
|
||||
|
@ -1,403 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
when false {
|
||||
range2_to_rl_rect :: #force_inline proc "contextless"( range : Range2 ) -> rl.Rectangle
|
||||
{
|
||||
rect := rl.Rectangle {
|
||||
range.min.x,
|
||||
range.max.y,
|
||||
abs(range.max.x - range.min.x),
|
||||
abs(range.max.y - range.min.y),
|
||||
}
|
||||
return rect
|
||||
}
|
||||
|
||||
draw_rectangle :: #force_inline proc "contextless" ( rect : rl.Rectangle, box : ^UI_RenderBoxInfo ) {
|
||||
using box
|
||||
if style.corner_radii[0] > 0 {
|
||||
rl.DrawRectangleRounded( rect, style.corner_radii[0], 9, style.bg_color )
|
||||
}
|
||||
else {
|
||||
rl.DrawRectangleRec( rect, style.bg_color )
|
||||
}
|
||||
}
|
||||
|
||||
draw_rectangle_lines :: #force_inline proc "contextless" ( rect : rl.Rectangle, box : ^UI_RenderBoxInfo, color : Color, thickness : f32 ) {
|
||||
using box
|
||||
if style.corner_radii[0] > 0 {
|
||||
rl.DrawRectangleRoundedLines( rect, style.corner_radii[0], 9, thickness, color )
|
||||
}
|
||||
else {
|
||||
rl.DrawRectangleLinesEx( rect, thickness, color )
|
||||
}
|
||||
}
|
||||
|
||||
render :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
render_mode_3d()
|
||||
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground( app_color_theme().bg )
|
||||
|
||||
render_mode_2d_workspace()
|
||||
render_mode_screenspace()
|
||||
|
||||
rl.EndDrawing()
|
||||
}
|
||||
|
||||
// Experimental 3d viewport, not really the focus of this prototype
|
||||
// Until we can have a native or interpreted program render to it its not very useful.
|
||||
// Note(Ed): Other usecase could be 3d vis notes & math/graphical debug
|
||||
render_mode_3d :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
|
||||
state := get_state(); using state
|
||||
|
||||
rl.BeginDrawing()
|
||||
rl.BeginTextureMode( debug.viewport_rt )
|
||||
rl.BeginMode3D( debug.cam_vp )
|
||||
rl.ClearBackground( Color_3D_BG )
|
||||
|
||||
rl.EndMode3D()
|
||||
rl.EndTextureMode()
|
||||
rl.EndDrawing()
|
||||
}
|
||||
|
||||
// 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
|
||||
cam := & project.workspace.cam
|
||||
|
||||
win_extent := state.app_window.extent
|
||||
|
||||
rl.BeginMode2D( project.workspace.cam )
|
||||
|
||||
// Draw 3D Viewport
|
||||
when false
|
||||
{
|
||||
viewport_size := Vec2 { 1280.0, 720.0 }
|
||||
vp_half_size := viewport_size * 0.5
|
||||
viewport_box := range2( -vp_half_size, vp_half_size )
|
||||
viewport_render := range2(
|
||||
ws_view_to_render_pos( viewport_box.min),
|
||||
ws_view_to_render_pos( viewport_box.max),
|
||||
)
|
||||
viewport_rect := range2_to_rl_rect( viewport_render )
|
||||
rl.DrawTextureRec( debug.viewport_rt.texture, viewport_rect, -vp_half_size, Color_White )
|
||||
}
|
||||
|
||||
// draw_text( "This is text in world space", { 0, 200 }, 16.0 )
|
||||
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
|
||||
view_bounds := view_get_bounds()
|
||||
when false
|
||||
{
|
||||
render_view := Range2 { pts = {
|
||||
ws_view_to_render_pos( view_bounds.min),
|
||||
ws_view_to_render_pos( view_bounds.max),
|
||||
}}
|
||||
view_rect := rl.Rectangle {
|
||||
render_view.min.x,
|
||||
render_view.max.y,
|
||||
abs(render_view.max.x - render_view.min.x),
|
||||
abs(render_view.max.y - render_view.min.y),
|
||||
}
|
||||
rl.DrawRectangleRounded( view_rect, 0.3, 9, { 255, 0, 0, 20 } )
|
||||
}
|
||||
|
||||
ImguiRender:
|
||||
{
|
||||
profile("Imgui Render")
|
||||
ui := & state.project.workspace.ui
|
||||
root := ui.root
|
||||
if root == nil || root.num_children == 0 {
|
||||
break ImguiRender
|
||||
}
|
||||
state.ui_context = ui
|
||||
|
||||
current := root.first
|
||||
for & current in array_to_slice(ui.render_queue)
|
||||
{
|
||||
profile("Box")
|
||||
style := current.style
|
||||
computed := current.computed
|
||||
|
||||
if ! intersects_range2( view_bounds, computed.bounds ) {
|
||||
continue
|
||||
}
|
||||
|
||||
profile_begin("render space calc")
|
||||
render_bounds := range2(
|
||||
ws_view_to_render_pos(computed.bounds.min),
|
||||
ws_view_to_render_pos(computed.bounds.max),
|
||||
)
|
||||
render_padding := range2(
|
||||
ws_view_to_render_pos(computed.padding.min),
|
||||
ws_view_to_render_pos(computed.padding.max),
|
||||
)
|
||||
render_content := range2(
|
||||
ws_view_to_render_pos(computed.content.min),
|
||||
ws_view_to_render_pos(computed.content.max),
|
||||
)
|
||||
|
||||
rect_bounds := range2_to_rl_rect( render_bounds )
|
||||
rect_padding := range2_to_rl_rect( render_padding )
|
||||
rect_content := range2_to_rl_rect( render_content )
|
||||
profile_end()
|
||||
|
||||
profile_begin("raylib drawing")
|
||||
if style.bg_color.a != 0
|
||||
{
|
||||
draw_rectangle( rect_bounds, & current )
|
||||
}
|
||||
if current.border_width > 0 {
|
||||
draw_rectangle_lines( rect_bounds, & current, style.border_color, current.border_width )
|
||||
}
|
||||
|
||||
line_thickness := 1 * cam_zoom_ratio
|
||||
if debug.draw_UI_padding_bounds && equal_range2(computed.content, computed.padding) {
|
||||
draw_rectangle_lines( rect_padding, & current, Color_Debug_UI_Padding_Bounds, line_thickness )
|
||||
}
|
||||
else if debug.draw_ui_content_bounds {
|
||||
draw_rectangle_lines( rect_content, & current, Color_Debug_UI_Content_Bounds, line_thickness )
|
||||
}
|
||||
|
||||
point_radius := 3 * cam_zoom_ratio
|
||||
|
||||
// profile_begin("circles")
|
||||
if debug.draw_ui_box_bounds_points
|
||||
{
|
||||
computed_size := computed.bounds.p1 - computed.bounds.p0
|
||||
// center := Vec2 {
|
||||
// render_bounds.p0.x + computed_size.x * 0.5,
|
||||
// render_bounds.p0.y - computed_size.y * 0.5,
|
||||
// }
|
||||
// rl.DrawCircleV( center, point_radius, Color_White )
|
||||
|
||||
rl.DrawCircleV( render_bounds.p0, point_radius, Color_Red )
|
||||
rl.DrawCircleV( render_bounds.p1, point_radius, Color_Blue )
|
||||
}
|
||||
// profile_end()
|
||||
|
||||
profile_end()
|
||||
|
||||
if len(current.text.str) > 0 {
|
||||
ws_view_draw_text( current.text, ws_view_to_render_pos(computed.text_pos * {1, -1}), current.font_size, style.text_color )
|
||||
}
|
||||
}
|
||||
}
|
||||
//endregion Imgui Render
|
||||
|
||||
|
||||
if debug.mouse_vis {
|
||||
cursor_world_pos := screen_to_ws_view_pos(input.mouse.pos)
|
||||
rl.DrawCircleV( ws_view_to_render_pos(cursor_world_pos), 5, Color_GreyRed )
|
||||
}
|
||||
|
||||
rl.DrawCircleV( { 0, 0 }, 1 * cam_zoom_ratio, Color_White )
|
||||
|
||||
rl.EndMode2D()
|
||||
}
|
||||
|
||||
render_mode_screenspace :: proc ()
|
||||
{
|
||||
profile("Render Screenspace")
|
||||
|
||||
state := get_state(); using state
|
||||
replay := & Memory_App.replay
|
||||
cam := & project.workspace.cam
|
||||
win_extent := state.app_window.extent
|
||||
|
||||
render_screen_ui()
|
||||
|
||||
debug_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@static draw_text_scratch : [Kilobyte * 64]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
|
||||
}
|
||||
|
||||
if debug.debug_text_vis
|
||||
{
|
||||
fps_msg := str_fmt( "FPS: %f", fps_avg)
|
||||
fps_msg_width := measure_text_size( fps_msg, default_font, 12.0, 0.0 ).x
|
||||
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 = rl.GREEN )
|
||||
|
||||
// debug_text( "Screen Width : %v", rl.GetScreenWidth () )
|
||||
// debug_text( "Screen Height: %v", rl.GetScreenHeight() )
|
||||
// debug_text( "frametime_target_ms : %f ms", frametime_target_ms )
|
||||
debug_text( "frametime : %f ms", frametime_delta_ms )
|
||||
// debug_text( "frametime_last_elapsed_ms : %f ms", frametime_elapsed_ms )
|
||||
if replay.mode == ReplayMode.Record {
|
||||
debug_text( "Recording Input")
|
||||
}
|
||||
if replay.mode == ReplayMode.Playback {
|
||||
debug_text( "Replaying Input")
|
||||
}
|
||||
// debug_text("Zoom Target: %v", project.workspace.zoom_target)
|
||||
|
||||
if debug.mouse_vis {
|
||||
debug_text("Mouse Vertical Wheel: %v", input.mouse.vertical_wheel )
|
||||
debug_text("Mouse Delta : %v", input.mouse.delta )
|
||||
debug_text("Mouse Position (Render) : %v", input.mouse.raw_pos )
|
||||
debug_text("Mouse Position (Screen) : %v", input.mouse.pos )
|
||||
debug_text("Mouse Position (Workspace View): %v", screen_to_ws_view_pos(input.mouse.pos) )
|
||||
rl.DrawCircleV( input.mouse.raw_pos, 10, Color_White_A125 )
|
||||
rl.DrawCircleV( screen_to_render_pos(input.mouse.pos), 2, Color_BG )
|
||||
}
|
||||
|
||||
ui := & project.workspace.ui
|
||||
|
||||
if true
|
||||
{
|
||||
debug_text("Box Count (Workspace): %v", ui.built_box_count )
|
||||
|
||||
hot_box := ui_box_from_key( ui.curr_cache, ui.hot )
|
||||
active_box := ui_box_from_key( ui.curr_cache, ui.active )
|
||||
if hot_box != nil {
|
||||
debug_text("Worksapce Hot Box : %v", hot_box.label.str )
|
||||
debug_text("Workspace Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
}
|
||||
if active_box != nil{
|
||||
debug_text("Workspace Active Box: %v", active_box.label.str )
|
||||
}
|
||||
}
|
||||
|
||||
ui = & screen_ui
|
||||
|
||||
if true
|
||||
{
|
||||
debug_text("Box Count: %v", ui.built_box_count )
|
||||
|
||||
hot_box := ui_box_from_key( ui.curr_cache, ui.hot )
|
||||
active_box := ui_box_from_key( ui.curr_cache, ui.active )
|
||||
if hot_box != nil {
|
||||
debug_text("Hot Box : %v", hot_box.label.str )
|
||||
debug_text("Hot Range2: %v", hot_box.computed.bounds.pts)
|
||||
}
|
||||
if active_box != nil{
|
||||
debug_text("Active Box: %v", active_box.label.str )
|
||||
}
|
||||
}
|
||||
|
||||
debug.draw_debug_text_y = 14
|
||||
}
|
||||
}
|
||||
|
||||
// A non-zoomable static-view for ui
|
||||
// Only a scalar factor may be applied to the size of widgets & fonts
|
||||
// 'Window tiled' panels reside here
|
||||
render_screen_ui :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
|
||||
using state := get_state()
|
||||
|
||||
//region App UI
|
||||
Render_App_UI:
|
||||
{
|
||||
profile("App UI")
|
||||
ui := & state.screen_ui
|
||||
state.ui_context = ui
|
||||
root := ui.root
|
||||
if root.num_children == 0 {
|
||||
break Render_App_UI
|
||||
}
|
||||
|
||||
for & current in array_to_slice(ui.render_queue)
|
||||
{
|
||||
profile("Box")
|
||||
|
||||
style := current.style
|
||||
computed := & current.computed
|
||||
|
||||
profile_begin("Coordinate space conversion")
|
||||
render_bounds := range2(
|
||||
screen_to_render_pos(computed.bounds.min),
|
||||
screen_to_render_pos(computed.bounds.max),
|
||||
)
|
||||
render_padding := range2(
|
||||
screen_to_render_pos(computed.padding.min),
|
||||
screen_to_render_pos(computed.padding.max),
|
||||
)
|
||||
render_content := range2(
|
||||
screen_to_render_pos(computed.content.min),
|
||||
screen_to_render_pos(computed.content.max),
|
||||
)
|
||||
rect_bounds := range2_to_rl_rect( render_bounds )
|
||||
rect_padding := range2_to_rl_rect( render_padding )
|
||||
rect_content := range2_to_rl_rect( render_content )
|
||||
profile_end()
|
||||
|
||||
profile_begin("raylib drawing")
|
||||
if style.bg_color.a != 0
|
||||
{
|
||||
draw_rectangle( rect_bounds, & current )
|
||||
}
|
||||
if current.border_width > 0 {
|
||||
draw_rectangle_lines( rect_bounds, & current, style.border_color, current.border_width )
|
||||
}
|
||||
|
||||
line_thickness : f32 = 1
|
||||
|
||||
if debug.draw_UI_padding_bounds && equal_range2(computed.content, computed.padding) {
|
||||
draw_rectangle_lines( rect_padding, & current, Color_Debug_UI_Padding_Bounds, line_thickness )
|
||||
}
|
||||
else if debug.draw_ui_content_bounds {
|
||||
draw_rectangle_lines( rect_content, & current, Color_Debug_UI_Content_Bounds, line_thickness )
|
||||
}
|
||||
|
||||
point_radius : f32 = 3
|
||||
|
||||
if debug.draw_ui_box_bounds_points
|
||||
{
|
||||
computed_size := computed.bounds.p1 - computed.bounds.p0
|
||||
if false
|
||||
{
|
||||
center := Vec2 {
|
||||
render_bounds.p0.x + computed_size.x * 0.5,
|
||||
render_bounds.p0.y - computed_size.y * 0.5,
|
||||
}
|
||||
rl.DrawCircleV( center, point_radius, Color_White )
|
||||
}
|
||||
rl.DrawCircleV( render_bounds.p0, point_radius, Color_Red )
|
||||
rl.DrawCircleV( render_bounds.p1, point_radius, Color_Blue )
|
||||
}
|
||||
|
||||
if len(current.text.str) > 0 && style.font.key != 0 {
|
||||
draw_text_screenspace( current.text, screen_to_render_pos(computed.text_pos), current.font_size, style.text_color )
|
||||
}
|
||||
profile_end()
|
||||
}
|
||||
}
|
||||
//endregion App UI
|
||||
}
|
||||
} // when false
|
@ -22,7 +22,7 @@ render :: proc()
|
||||
}
|
||||
|
||||
// Triangle Demo
|
||||
if true
|
||||
if false
|
||||
{
|
||||
using debug.gfx_tri_demo_state
|
||||
sokol_gfx.begin_pass(sokol_gfx.Pass { action = pass_action, swapchain = sokol_glue.swapchain() })
|
||||
@ -34,4 +34,14 @@ render :: proc()
|
||||
sokol_gfx.end_pass()
|
||||
sokol_gfx.commit()
|
||||
}
|
||||
|
||||
|
||||
// Batching Enqueue Boxes
|
||||
// Mixed with the batching enqueue for text
|
||||
|
||||
|
||||
//Begin
|
||||
// Flush boxs
|
||||
// flush text
|
||||
// End
|
||||
}
|
||||
|
@ -1,226 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import "core:math"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf8"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
when false {
|
||||
debug_draw_text :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content ) == 0 {
|
||||
return
|
||||
}
|
||||
runes, alloc_error := to_runes( content, frame_allocator() )
|
||||
// runes, alloc_error := to_runes( content, context.temp_allocator )
|
||||
// verify( alloc_error == AllocatorError.None, "Failed to temp allocate runes" )
|
||||
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
// if ( len(font) == 0 ) {
|
||||
font = default_font
|
||||
}
|
||||
pos := screen_to_render_pos(pos)
|
||||
|
||||
px_size := size
|
||||
|
||||
rl_font := to_rl_Font(font, px_size )
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
}
|
||||
|
||||
draw_text_screenspace :: proc( content : StrRunesPair, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content.str ) == 0 {
|
||||
return
|
||||
}
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
font = default_font
|
||||
}
|
||||
pos := pos
|
||||
|
||||
rl_font := to_rl_Font(font, size )
|
||||
runes := content.runes
|
||||
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
}
|
||||
|
||||
ws_view_draw_text_string :: proc( content : string, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
// profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content ) == 0 {
|
||||
return
|
||||
}
|
||||
runes, alloc_error := to_runes( content, frame_allocator() )
|
||||
verify( alloc_error == AllocatorError.None, "Failed to temp allocate runes" )
|
||||
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
// if len(font) == 0 {
|
||||
font = default_font
|
||||
}
|
||||
pos := ws_view_to_render_pos(pos)
|
||||
|
||||
px_size := size
|
||||
zoom_adjust := px_size * project.workspace.cam.zoom
|
||||
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
rl.DrawTextCodepoints( rl_font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color );
|
||||
rl.SetTextureFilter(rl_font.texture, rl.TextureFilter.POINT)
|
||||
}
|
||||
|
||||
when true
|
||||
{
|
||||
ws_view_draw_text_StrRunesPair :: proc( content : StrRunesPair, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
if len( content.str ) == 0 {
|
||||
return
|
||||
}
|
||||
font := font
|
||||
if font.key == Font_Default.key {
|
||||
font = default_font
|
||||
}
|
||||
pos := ws_view_to_render_pos(pos)
|
||||
|
||||
px_size := size
|
||||
zoom_adjust := px_size * project.workspace.cam.zoom
|
||||
rl_font := to_rl_Font(font, zoom_adjust )
|
||||
runes := content.runes
|
||||
|
||||
profile_begin("raylib draw codepoints related")
|
||||
// rl.DrawTextCodepoints( rl_font,
|
||||
// raw_data(runes), cast(i32) len(runes),
|
||||
// position = transmute(rl.Vector2) pos,
|
||||
// fontSize = px_size,
|
||||
// spacing = 0.0,
|
||||
// tint = color );
|
||||
rl.DrawTextEx(rl_font,
|
||||
strings.clone_to_cstring(content.str),
|
||||
position = transmute(rl.Vector2) pos,
|
||||
fontSize = px_size,
|
||||
spacing = 0.0,
|
||||
tint = color
|
||||
)
|
||||
profile_end()
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ws_view_draw_text_StrRunesPair :: proc( content : StrRunesPair, pos : Vec2, size : f32, color : rl.Color = rl.WHITE, font : FontID = Font_Default )
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state(); using state
|
||||
|
||||
// We need an alternative way to draw text to the screen (the above is way to expensive)
|
||||
// Possibly need to watch handmade hero...
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Raylib's equivalent doesn't take a length for the string (making it a pain in the ass)
|
||||
// So this is a 1:1 copy except it takes Odin strings
|
||||
measure_text_size_raylib :: proc( text : string, font : FontID, font_size := Font_Use_Default_Size, spacing : f32 ) -> Vec2
|
||||
{
|
||||
// profile(#procedure)
|
||||
px_size := math.round( points_to_pixels( font_size ) )
|
||||
rl_font := to_rl_Font( font, font_size )
|
||||
|
||||
// This is a static var within raylib. We don't have getter access to it.
|
||||
// Note(Ed) : raylib font size is in pixels so this is also.
|
||||
@static text_line_spacing : f32 = 15
|
||||
|
||||
text_size : Vec2
|
||||
|
||||
if rl_font.texture.id == 0 || len(text) == 0 {
|
||||
return text_size
|
||||
}
|
||||
|
||||
temp_byte_counter : i32 = 0 // Used to count longer text line num chars
|
||||
byte_counter : i32 = 0
|
||||
|
||||
text_width : f32 = 0.0
|
||||
temp_text_width : f32 = 0.0 // Used to counter longer text line width
|
||||
|
||||
text_height := cast(f32) rl_font.baseSize
|
||||
scale_factor := px_size / text_height
|
||||
|
||||
letter : rune
|
||||
index : i32 = 0
|
||||
|
||||
for id : i32 = 0; id < i32(len(text));
|
||||
{
|
||||
byte_counter += 1
|
||||
|
||||
next : i32 = 0
|
||||
|
||||
ctext := cast(cstring) ( & raw_data( text )[id] )
|
||||
letter = rl.GetCodepointNext( ctext, & next )
|
||||
index = rl.GetGlyphIndex( rl_font, letter )
|
||||
|
||||
id += 1
|
||||
|
||||
if letter != rune('\n')
|
||||
{
|
||||
if rl_font.glyphs[index].advanceX != 0 {
|
||||
text_width += f32(rl_font.glyphs[index].advanceX)
|
||||
}
|
||||
else {
|
||||
text_width += rl_font.recs[index].width + f32(rl_font.glyphs[index].offsetX)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if temp_text_width < text_width {
|
||||
temp_text_width = text_width
|
||||
}
|
||||
byte_counter = 0
|
||||
text_width = 0
|
||||
|
||||
text_height += text_line_spacing
|
||||
|
||||
if temp_byte_counter < byte_counter {
|
||||
temp_byte_counter = byte_counter
|
||||
}
|
||||
}
|
||||
}
|
||||
if temp_text_width < text_width {
|
||||
temp_text_width = text_width
|
||||
}
|
||||
text_size.x = temp_text_width * scale_factor + f32(temp_byte_counter - 1) * spacing
|
||||
text_size.y = text_height * scale_factor
|
||||
|
||||
return text_size
|
||||
}
|
||||
} // when false
|
@ -6,8 +6,6 @@ import "core:math/linalg"
|
||||
import "core:os"
|
||||
import str "core:strings"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
DebugActions :: struct {
|
||||
load_project : b32,
|
||||
save_project : b32,
|
||||
@ -75,12 +73,9 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
workspace := & project.workspace
|
||||
cam := & workspace.cam
|
||||
|
||||
if rl.IsWindowResized() {
|
||||
window := & state.app_window
|
||||
window.extent.x = f32(rl.GetScreenWidth()) * 0.5
|
||||
window.extent.y = f32(rl.GetScreenHeight()) * 0.5
|
||||
|
||||
project.workspace.cam.offset = transmute(Vec2) window.extent
|
||||
window := & state.app_window
|
||||
if window.resized {
|
||||
project.workspace.cam.view = transmute(Vec2) window.extent
|
||||
}
|
||||
|
||||
state.input, state.input_prev = swap( state.input, state.input_prev )
|
||||
@ -189,13 +184,13 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
- cast(f32) i32(debug_actions.cam_move_up) + cast(f32) i32(debug_actions.cam_move_down),
|
||||
}
|
||||
move_velocity *= digital_move_speed * f32(delta_time)
|
||||
cam.target += move_velocity
|
||||
cam.position += move_velocity
|
||||
|
||||
if debug_actions.cam_mouse_pan
|
||||
{
|
||||
if is_within_screenspace(input.mouse.pos) {
|
||||
pan_velocity := input.mouse.delta * vec2(1, -1) * ( 1 / cam.zoom )
|
||||
cam.target -= pan_velocity
|
||||
cam.position -= pan_velocity
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -252,6 +247,7 @@ update :: proc( delta_time : f64 ) -> b32
|
||||
|
||||
debug.last_mouse_pos = input.mouse.pos
|
||||
|
||||
should_shutdown : b32 = ! cast(b32) rl.WindowShouldClose()
|
||||
// should_shutdown : b32 = ! cast(b32) rl.WindowShouldClose()
|
||||
should_shutdown : b32 = false
|
||||
return should_shutdown
|
||||
}
|
||||
|
@ -1,2 +1,2 @@
|
||||
package sectr
|
||||
|
||||
package sectr
|
353
code/sectr/font/fontstash.odin
Normal file
353
code/sectr/font/fontstash.odin
Normal file
@ -0,0 +1,353 @@
|
||||
/*
|
||||
Yet another port of fontstash.
|
||||
|
||||
I decided t use this instead of the odin port as it already deviated from the original impl.
|
||||
So The code was small enough that I mine as well learn it by porting for my use case.
|
||||
|
||||
Original copyright for fonstash.h:
|
||||
------------------------------------------------------------------------------
|
||||
Copyright (c) 2009-2013 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
package sectr
|
||||
|
||||
import stbtt "vendor:stb/truetype"
|
||||
|
||||
Range2_i16 :: struct #raw_union {
|
||||
using pts : Vec2_i16,
|
||||
using xy : struct {
|
||||
x0, y0, x1, y1 : i16,
|
||||
}
|
||||
}
|
||||
|
||||
Vec2_i16 :: [2]i16
|
||||
|
||||
FSTASH_Invalid :: -1
|
||||
|
||||
FSTASH_Hash_Lut_Size :: 256
|
||||
FSTASH_Max_Fallbacks :: 20
|
||||
FSTASH_Max_States :: 20
|
||||
FSTASH_Vertex_Count :: 1024
|
||||
FSTASH_Init_Atlas_Nodes :: 256
|
||||
|
||||
FSTASH_FontLuts :: [FSTASH_Hash_Lut_Size]i32
|
||||
FSTASH_FontFallbacks :: [FSTASH_Max_Fallbacks]i32
|
||||
|
||||
FSTASH_HandleErrorProc :: #type proc( uptr : rawptr, error, val : i32 )
|
||||
|
||||
FSTASH_RenderCreateProc :: #type proc( uptr : rawptr, width, height : i32 )
|
||||
FSTASH_RenderResizeProc :: #type proc( uptr : rawptr, width, height : i32 )
|
||||
FSTASH_RenderUpdateProc :: #type proc( uptr : rawptr, rect : ^i32, data : ^u8 )
|
||||
FSTASH_RenderDrawProc :: #type proc( uptr : rawptr, verts : ^f32, tcoords : ^f32, colors : ^i32, num_verts : i32 )
|
||||
FSTASH_RenderDelete :: #type proc( uptr : rawptr )
|
||||
|
||||
FSTASH_AlignFlag :: enum u32 {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
Top,
|
||||
Middle,
|
||||
Bottom,
|
||||
Baseline,
|
||||
}
|
||||
FSTASH_AlignFlags :: bit_set[ FSTASH_AlignFlag; u32 ]
|
||||
|
||||
// FONSflags
|
||||
FSTASH_QuadLocation :: enum u32 {
|
||||
Top_Left = 1,
|
||||
Bottom_Left = 2,
|
||||
}
|
||||
|
||||
FSTASH_Atlas :: struct {
|
||||
dud : i32,
|
||||
}
|
||||
|
||||
FSTASH_AtlasNode :: struct {
|
||||
x, y, width : i16,
|
||||
}
|
||||
|
||||
FSTASH_ErrorCode :: enum u32 {
|
||||
Atlas_Full,
|
||||
Scratch_Full,
|
||||
States_Overflow,
|
||||
States_Underflow,
|
||||
}
|
||||
|
||||
FSTASH_Quad :: struct {
|
||||
x0, y0, s0, t0 : f32,
|
||||
x1, y1, s1, t1 : f32,
|
||||
}
|
||||
|
||||
FSTASH_Font :: struct {
|
||||
info : stbtt.fontinfo,
|
||||
name : string,
|
||||
data : []byte,
|
||||
free_data : bool,
|
||||
|
||||
ascender : f32,
|
||||
descender : f32,
|
||||
line_height : f32,
|
||||
|
||||
glyphs : Array(FSTASH_Glyph),
|
||||
lut : FSTASH_FontLuts,
|
||||
fallbacks : FSTASH_FontFallbacks,
|
||||
num_fallbacks : i32,
|
||||
}
|
||||
|
||||
FSTASH_Glyph :: struct {
|
||||
codepoint : rune,
|
||||
index, next : i32,
|
||||
size, blur : i16,
|
||||
x_advance : i16,
|
||||
box : Range2_i16,
|
||||
offset : Vec2_i16,
|
||||
}
|
||||
|
||||
FSTASH_Params :: struct {
|
||||
width, height : i32,
|
||||
quad_location : FSTASH_QuadLocation, // (flags)
|
||||
render_create : FSTASH_RenderCreateProc,
|
||||
render_resize : FSTASH_RenderResizeProc,
|
||||
render_update : FSTASH_RenderUpdateProc,
|
||||
render_draw : FSTASH_RenderDrawProc,
|
||||
render_delete : FSTASH_RenderDelete,
|
||||
}
|
||||
|
||||
FSTASH_State :: struct {
|
||||
font : i32,
|
||||
alignment : i32,
|
||||
size : f32,
|
||||
color : [4]u8,
|
||||
blur : f32,
|
||||
spacing : f32,
|
||||
}
|
||||
|
||||
FSTASH_TextIter :: struct {
|
||||
x, y : f32,
|
||||
next_x, next_y : f32,
|
||||
scale, spacing : f32,
|
||||
|
||||
isize, iblur : i16,
|
||||
|
||||
font : ^FSTASH_Font,
|
||||
prev_glyph_id : i32,
|
||||
|
||||
codepoint : rune,
|
||||
utf8_state : rune,
|
||||
|
||||
str : string,
|
||||
next : string,
|
||||
end : string,
|
||||
}
|
||||
|
||||
FSTASH_Context :: struct {
|
||||
params : FSTASH_Params,
|
||||
|
||||
// Atlas
|
||||
atlas : Array(FSTASH_AtlasNode),
|
||||
texture_data : []byte,
|
||||
width, height : i32,
|
||||
// ----
|
||||
|
||||
normalized_size : Vec2,
|
||||
|
||||
verts : [FSTASH_Vertex_Count * 2]f32,
|
||||
tcoords : [FSTASH_Vertex_Count * 2]f32,
|
||||
colors : [FSTASH_Vertex_Count ]f32,
|
||||
|
||||
states : [FSTASH_Max_States]FSTASH_State,
|
||||
num_states : i32,
|
||||
|
||||
handle_error : FSTASH_HandleErrorProc,
|
||||
error_uptr : rawptr,
|
||||
}
|
||||
|
||||
fstash_decode_utf8 :: proc( state : ^rune, codepoint : ^rune, to_decode : byte ) -> bool
|
||||
{
|
||||
UTF8_Accept :: 0
|
||||
UTF8_Reject :: 1
|
||||
|
||||
@static UTF8_Decode_Table := [?]u8 {
|
||||
// The first part of the table maps bytes to character classes that
|
||||
// to reduce the size of the transition table and create bitmasks.
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1F
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3F
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5F
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7F
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9F
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // A0..BF
|
||||
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // C0..DF
|
||||
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, // E0..FF
|
||||
|
||||
// The second part is a transition table that maps a combination
|
||||
// of a state of the automaton and a character class to a state.
|
||||
0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12,
|
||||
12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12,
|
||||
12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12,
|
||||
12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12,
|
||||
12,36,12,12,12,12,12,12,12,12,12,12,
|
||||
}
|
||||
|
||||
to_decode_rune := rune(to_decode)
|
||||
type := UTF8_Decode_Table[to_decode_rune]
|
||||
|
||||
// Update codepoint otherwise initialize it.
|
||||
(codepoint^) = ((state^) != UTF8_Accept) ? \
|
||||
((to_decode_rune & 0x3F) | ((codepoint^) << 6)) \
|
||||
: ((0xFF >> type) & (to_decode_rune))
|
||||
|
||||
(state^) = cast(rune)(UTF8_Decode_Table[256 + (state^) * 16 + rune(type)])
|
||||
return (state^) == UTF8_Accept
|
||||
}
|
||||
|
||||
fstash_atlas_delete :: proc ( ctx : ^FSTASH_Context ) {
|
||||
using ctx
|
||||
array_free( ctx.atlas )
|
||||
}
|
||||
|
||||
fstash_atlas_expand :: proc( ctx : ^FSTASH_Context, width, height : i32 )
|
||||
{
|
||||
if width > ctx.width {
|
||||
fstash_atlas_insert( ctx, ctx.atlas.num, ctx.width, 0, width - ctx.width )
|
||||
}
|
||||
|
||||
ctx.width = width
|
||||
ctx.height = height
|
||||
}
|
||||
|
||||
fstash_atlas_init :: proc( ctx : ^FSTASH_Context, width, height : i32, num_nodes : u32 = FSTASH_Init_Atlas_Nodes )
|
||||
{
|
||||
error : AllocatorError
|
||||
ctx.atlas, error = array_init_reserve( FSTASH_AtlasNode, context.allocator, u64(num_nodes), dbg_name = "font atlas" )
|
||||
ensure(error != AllocatorError.None, "Failed to allocate font atlas")
|
||||
|
||||
ctx.width = width
|
||||
ctx.height = height
|
||||
|
||||
array_append( & ctx.atlas, FSTASH_AtlasNode{ width = i16(width)} )
|
||||
}
|
||||
|
||||
fstash_atlas_insert :: proc( ctx : ^FSTASH_Context, id : u64, x, y, width : i32 ) -> (error : AllocatorError)
|
||||
{
|
||||
error = array_append_at( & ctx.atlas, FSTASH_AtlasNode{ i16(x), i16(y), i16(width) }, id )
|
||||
return
|
||||
}
|
||||
|
||||
fstash_atlas_remove :: proc( ctx : ^FSTASH_Context, id : u64 )
|
||||
{
|
||||
array_remove_at( ctx.atlas, id )
|
||||
}
|
||||
|
||||
fstash_atlas_reset :: proc( ctx : ^FSTASH_Context, width, height : i32 )
|
||||
{
|
||||
ctx.width = width
|
||||
ctx.height = height
|
||||
array_clear( ctx.atlas )
|
||||
|
||||
array_append( & ctx.atlas, FSTASH_AtlasNode{ width = i16(width)} )
|
||||
}
|
||||
|
||||
fstash_atlas_add_skyline_level :: proc (ctx : ^FSTASH_Context, id : u64, x, y, width, height : i32 ) -> (error : AllocatorError)
|
||||
{
|
||||
insert :: fstash_atlas_insert
|
||||
remove :: fstash_atlas_remove
|
||||
|
||||
error = insert( ctx, id, x, y + height, width)
|
||||
if error != AllocatorError.None {
|
||||
ensure( false, "Failed to insert into atlas")
|
||||
return
|
||||
}
|
||||
|
||||
// Delete skyline segments that fall under the shadow of the new segment.
|
||||
for sky_id := id; sky_id < ctx.atlas.num; sky_id += 1
|
||||
{
|
||||
curr := & ctx.atlas.data[sky_id ]
|
||||
next := & ctx.atlas.data[sky_id + 1]
|
||||
if curr.x >= next.x + next.width do break
|
||||
|
||||
shrink := i16(next.x + next.width - curr.x)
|
||||
curr.x += shrink
|
||||
curr.width -= shrink
|
||||
|
||||
if curr.width > 0 do break
|
||||
|
||||
remove(ctx, sky_id)
|
||||
sky_id -= 1
|
||||
}
|
||||
|
||||
|
||||
// Merge same height skyline segments that are next to each other.
|
||||
for sky_id := id; sky_id < ctx.atlas.num - 1;
|
||||
{
|
||||
curr := & ctx.atlas.data[sky_id ]
|
||||
next := & ctx.atlas.data[sky_id + 1]
|
||||
|
||||
if curr.y == next.y {
|
||||
curr.width += next.width
|
||||
remove(ctx, sky_id + 1)
|
||||
}
|
||||
else {
|
||||
sky_id += 1
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
fstash_atlas_rect_fits :: proc( ctx : ^FSTASH_Context, location, width, height : i32 ) -> (max_height : i32)
|
||||
{
|
||||
// Checks if there is enough space at the location of skyline span 'i',
|
||||
// and return the max height of all skyline spans under that at that location,
|
||||
// (think tetris block being dropped at that position). Or -1 if no space found.
|
||||
atlas := array_to_slice(ctx.atlas)
|
||||
node := atlas[location]
|
||||
|
||||
space_left : i32
|
||||
if i32(node.x) + width > ctx.width {
|
||||
max_height = -1
|
||||
return
|
||||
}
|
||||
|
||||
space_left = width;
|
||||
|
||||
y := i32(node.y)
|
||||
location := location
|
||||
for ; space_left > 0;
|
||||
{
|
||||
if u64(location) == ctx.atlas.num {
|
||||
max_height = -1
|
||||
return
|
||||
}
|
||||
|
||||
node := atlas[location]
|
||||
|
||||
y := max(y, i32(node.y))
|
||||
if y + height > ctx.height {
|
||||
max_height = -1
|
||||
return
|
||||
}
|
||||
|
||||
space_left -= i32(node.width)
|
||||
location += 1
|
||||
}
|
||||
max_height = y
|
||||
return
|
||||
}
|
||||
|
||||
fstash_atlas_add_rect :: proc( ctx : ^FSTASH_Context, )
|
||||
{
|
||||
|
||||
}
|
@ -1,13 +1,5 @@
|
||||
package sectr
|
||||
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:mem"
|
||||
import "core:path/filepath"
|
||||
import "core:os"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Font_Largest_Px_Size :: 32
|
||||
|
||||
Font_Size_Interval :: 2
|
||||
@ -35,158 +27,30 @@ FontTag :: struct {
|
||||
point_size : f32
|
||||
}
|
||||
|
||||
FontGlyphsRender :: struct {
|
||||
size : i32,
|
||||
count : i32,
|
||||
padding : i32,
|
||||
texture : rl.Texture2D,
|
||||
recs : [^]rl.Rectangle, // Characters rectangles in texture
|
||||
glyphs : [^]rl.GlyphInfo, // Characters info data
|
||||
}
|
||||
|
||||
FontDef :: struct {
|
||||
path_file : string,
|
||||
|
||||
// TODO(Ed) : you may have to store font data in the future if we render on demand
|
||||
// data : []u8,
|
||||
|
||||
default_size : i32,
|
||||
size_table : [Font_Largest_Px_Size / Font_Size_Interval] FontGlyphsRender,
|
||||
placeholder : int,
|
||||
}
|
||||
|
||||
FontProviderData :: struct {
|
||||
// font_cache : HMapZPL(FontDef),
|
||||
font_cache : HMapChainedPtr(FontDef),
|
||||
}
|
||||
|
||||
font_provider_startup :: proc()
|
||||
{
|
||||
profile(#procedure)
|
||||
state := get_state()
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
font_cache_alloc_error : AllocatorError
|
||||
font_cache, font_cache_alloc_error = hmap_chained_init(FontDef, hmap_closest_prime(1 * Kilo), persistent_allocator(), dbg_name = "font_cache" )
|
||||
verify( font_cache_alloc_error == AllocatorError.None, "Failed to allocate font_cache" )
|
||||
|
||||
log("font_cache created")
|
||||
log("font_provider initialized")
|
||||
}
|
||||
|
||||
font_provider_shutdown :: proc()
|
||||
{
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
for & entry in font_cache.lookup
|
||||
{
|
||||
if entry == nil do continue
|
||||
|
||||
def := entry.value
|
||||
for & px_render in def.size_table {
|
||||
using px_render
|
||||
rl.UnloadFontData( glyphs, count )
|
||||
rl.UnloadTexture ( texture )
|
||||
rl.MemFree( recs )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
font_load :: proc( path_file : string,
|
||||
font_load :: proc(ath_file : string,
|
||||
default_size : f32 = Font_Load_Use_Default_Size,
|
||||
desired_id : string = Font_Load_Gen_ID
|
||||
) -> FontID
|
||||
{
|
||||
profile(#procedure)
|
||||
log( str_fmt("Loading font: %v", path_file))
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
font_data, read_succeded : = os.read_entire_file( path_file )
|
||||
verify( b32(read_succeded), str_fmt("Failed to read font file for: %v", path_file) )
|
||||
font_data_size := cast(i32) len(font_data)
|
||||
|
||||
desired_id := desired_id
|
||||
// Use file name as key
|
||||
if len(desired_id) == 0 {
|
||||
// NOTE(Ed): This should never be used except for laziness so I'll be throwing a warning everytime.
|
||||
log("desired_key not provided, using file name. Give it a proper name!", LogLevel.Warning)
|
||||
// desired_id = cast(FontID) file_name_from_path(path_file)
|
||||
desired_id = file_name_from_path(path_file)
|
||||
}
|
||||
|
||||
default_size := default_size
|
||||
if default_size == Font_Load_Use_Default_Size {
|
||||
default_size = Font_Default_Point_Size
|
||||
}
|
||||
|
||||
key := cast(u64) crc32( transmute([]byte) desired_id )
|
||||
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.default_size = i32(points_to_pixels(default_size))
|
||||
|
||||
// TODO(Ed): this is slow & eats quite a bit of memory early on. Setup a more on demand load for a specific size.
|
||||
// Also, we need to eventually switch to a SDF shader for rendering
|
||||
|
||||
// Render all sizes at once
|
||||
// Note(Ed) : We only generate textures for even multiples of the font.
|
||||
for font_size : i32 = Font_Size_Interval; font_size <= Font_Largest_Px_Size; font_size += Font_Size_Interval
|
||||
{
|
||||
profile("font size render")
|
||||
id := (font_size / Font_Size_Interval) + (font_size % Font_Size_Interval)
|
||||
|
||||
px_render := & def.size_table[id - 1]
|
||||
using px_render
|
||||
size = font_size
|
||||
count = 95 // This is the default codepoint count from raylib when loading a font.
|
||||
padding = Font_TTF_Default_Chars_Padding
|
||||
glyphs = rl.LoadFontData( raw_data(font_data), font_data_size,
|
||||
fontSize = size,
|
||||
codepoints = nil,
|
||||
codepointCount = count,
|
||||
type = rl.FontType.DEFAULT )
|
||||
verify( glyphs != nil, str_fmt("Failed to load glyphs for font: %v at desired size: %v", desired_id, size ) )
|
||||
|
||||
atlas := rl.GenImageFontAtlas( glyphs, & recs, count, size, padding, i32(Font_Atlas_Packing_Method.Raylib_Basic) )
|
||||
texture = rl.LoadTextureFromImage( atlas )
|
||||
|
||||
// glyphs_slice := slice_ptr( glyphs, count )
|
||||
// for glyph in glyphs_slice {
|
||||
// TODO(Ed) : See if above can properly reference
|
||||
|
||||
// NOTE(raylib): Update glyphs[i].image to use alpha, required to be used on image_draw_text()
|
||||
for glyph_id : i32 = 0; glyph_id < count; glyph_id += 1 {
|
||||
glyph := & glyphs[glyph_id]
|
||||
|
||||
rl.UnloadImage( glyph.image )
|
||||
glyph.image = rl.ImageFromImage( atlas, recs[glyph_id] )
|
||||
}
|
||||
rl.UnloadImage( atlas )
|
||||
}
|
||||
|
||||
return { key, desired_id }
|
||||
}
|
||||
|
||||
Font_Use_Default_Size :: f32(0.0)
|
||||
|
||||
to_rl_Font :: proc( id : FontID, size := Font_Use_Default_Size ) -> rl.Font
|
||||
{
|
||||
font_provider_data := & get_state().font_provider_data; using font_provider_data
|
||||
|
||||
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_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)
|
||||
px_render := & def.size_table[ id - 1 ]
|
||||
|
||||
rl_font : rl.Font
|
||||
rl_font.baseSize = px_render.size
|
||||
rl_font.glyphCount = px_render.count
|
||||
rl_font.glyphPadding = px_render.padding
|
||||
rl_font.glyphs = px_render.glyphs
|
||||
rl_font.recs = px_render.recs
|
||||
rl_font.texture = px_render.texture
|
||||
return rl_font
|
||||
return {}
|
||||
}
|
||||
|
@ -1,6 +1,27 @@
|
||||
package sectr
|
||||
|
||||
context_ext :: proc( $ Type : typeid ) -> (^Type) {
|
||||
context_usr :: #force_inline proc( $ Type : typeid ) -> (^Type) {
|
||||
return cast(^Type) context.user_ptr
|
||||
}
|
||||
|
||||
ContextExt :: struct {
|
||||
stack : StackFixed(rawptr, 1024),
|
||||
}
|
||||
|
||||
// Assign return value to context.user_ptr
|
||||
// context_ext_init :: proc() -> rawptr
|
||||
// {
|
||||
|
||||
// }
|
||||
|
||||
context_ext :: #force_inline proc() -> ^ContextExt {
|
||||
return cast(^ContextExt) context.user_ptr
|
||||
}
|
||||
|
||||
context_push :: proc( value : ^($Type) ) {
|
||||
push( & context_ext().stack, value )
|
||||
}
|
||||
|
||||
context_pop :: proc( value : ^($Type) ) {
|
||||
pop( & context_ext().stack )
|
||||
}
|
||||
|
@ -19,14 +19,14 @@ MemoryTracker :: struct {
|
||||
|
||||
Track_Memory :: false
|
||||
|
||||
tracker_msg_buffer : [Kilobyte * 16]u8
|
||||
// tracker_msg_buffer : [Kilobyte * 16]u8
|
||||
|
||||
memtracker_clear :: proc ( tracker : MemoryTracker ) {
|
||||
when ! Track_Memory {
|
||||
return
|
||||
}
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
logf("Clearing tracker: %v", tracker.name)
|
||||
memtracker_dump_entries(tracker);
|
||||
@ -38,8 +38,8 @@ memtracker_init :: proc ( tracker : ^MemoryTracker, allocator : Allocator, num_e
|
||||
when ! Track_Memory {
|
||||
return
|
||||
}
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
tracker.name = name
|
||||
|
||||
@ -56,8 +56,8 @@ memtracker_register :: proc( tracker : ^MemoryTracker, new_entry : MemoryTracker
|
||||
return
|
||||
}
|
||||
profile(#procedure)
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
if tracker.entries.num == tracker.entries.capacity {
|
||||
ensure(false, "Memory tracker entries array full, can no longer register any more allocations")
|
||||
@ -110,8 +110,8 @@ memtracker_unregister :: proc( tracker : MemoryTracker, to_remove : MemoryTracke
|
||||
return
|
||||
}
|
||||
profile(#procedure)
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
entries := array_to_slice(tracker.entries)
|
||||
for idx in 0..< tracker.entries.num
|
||||
@ -139,8 +139,8 @@ memtracker_check_for_collisions :: proc ( tracker : MemoryTracker )
|
||||
return
|
||||
}
|
||||
profile(#procedure)
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
entries := array_to_slice(tracker.entries)
|
||||
for idx in 1 ..< tracker.entries.num {
|
||||
@ -161,8 +161,8 @@ memtracker_dump_entries :: proc( tracker : MemoryTracker )
|
||||
when ! Track_Memory {
|
||||
return
|
||||
}
|
||||
temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
// temp_arena : Arena; arena_init(& temp_arena, tracker_msg_buffer[:])
|
||||
// context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
log( "Dumping Memory Tracker:")
|
||||
for idx in 0 ..< tracker.entries.num {
|
||||
|
1
code/sectr/input/input_sokol.odin
Normal file
1
code/sectr/input/input_sokol.odin
Normal file
@ -0,0 +1 @@
|
||||
package sectr
|
@ -118,15 +118,22 @@ logger_interface :: proc(
|
||||
str_to_file_ln( logger.file, to_string(builder) )
|
||||
}
|
||||
|
||||
// TODO(Ed): Use a fixed size block allocation for message formatting used by core_log
|
||||
// This will prevent stack overflows with the virtual arena debug logs at worst case and not need to do
|
||||
// some inline arena allocation on-site such as with the memory tracker
|
||||
|
||||
// This buffer is used below excluisvely to prevent any allocator recusion when verbose logging from allocators.
|
||||
Logger_Allocator_Buffer : [32 * Kilobyte]u8
|
||||
|
||||
log :: proc( msg : string, level := LogLevel.Info, loc := #caller_location ) {
|
||||
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
||||
context.allocator = arena_allocator(& temp_arena)
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
core_log.log( level, msg, location = loc )
|
||||
}
|
||||
|
||||
logf :: proc( fmt : string, args : ..any, level := LogLevel.Info, loc := #caller_location ) {
|
||||
// context.allocator = transient_allocator()
|
||||
temp_arena : Arena; arena_init(& temp_arena, Logger_Allocator_Buffer[:])
|
||||
context.allocator = arena_allocator(& temp_arena)
|
||||
context.temp_allocator = arena_allocator(& temp_arena)
|
||||
|
||||
core_log.logf( level, fmt, ..args, location = loc )
|
||||
}
|
@ -134,7 +134,7 @@ pws_parser_lex :: proc ( text : string, allocator : Allocator ) -> ( PWS_LexResu
|
||||
|
||||
rune_type :: proc( codepoint : rune ) -> PWS_TokenType
|
||||
{
|
||||
using self := context_ext( PWS_LexerData)
|
||||
using self := context_usr( PWS_LexerData)
|
||||
|
||||
switch codepoint
|
||||
{
|
||||
@ -177,7 +177,7 @@ pws_parser_lex :: proc ( text : string, allocator : Allocator ) -> ( PWS_LexResu
|
||||
|
||||
make_token :: proc ( byte_offset : int ) -> AllocatorError
|
||||
{
|
||||
self := context_ext( PWS_LexerData); using self
|
||||
self := context_usr( PWS_LexerData); using self
|
||||
|
||||
if previous_rune == Rune_Carriage_Return && current_rune != Rune_Line_Feed {
|
||||
ensure(false, "Rouge Carriage Return")
|
||||
@ -268,7 +268,7 @@ pws_parser_parse :: proc( text : string, allocator : Allocator ) -> ( PWS_ParseR
|
||||
//region Helper procs
|
||||
eat_line :: #force_inline proc()
|
||||
{
|
||||
self := context_ext( PWS_ParseData); using self
|
||||
self := context_usr( PWS_ParseData); using self
|
||||
tok := cast( ^PWS_Token) head
|
||||
|
||||
line.type = .Line
|
||||
|
@ -13,7 +13,7 @@ vec2_json_unmarshal :: proc( value : ^ json.Value ) -> Vec2 {
|
||||
}
|
||||
}
|
||||
|
||||
color_json_unmarshal :: proc( value : ^ json.Value ) -> Color {
|
||||
color_json_unmarshal :: proc( value : ^ json.Value ) -> RGBA8 {
|
||||
json_color := value.(json.Array)
|
||||
r := u8(json_color[0].(json.Float))
|
||||
g := u8(json_color[1].(json.Float))
|
||||
|
@ -6,8 +6,6 @@ Ultimately the user's window ppcm (pixels-per-centimeter) determins how all virt
|
||||
*/
|
||||
package sectr
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
// The points to pixels and pixels to points are our only reference to accurately converting
|
||||
// an object from world space to screen-space.
|
||||
// This prototype engine will have all its spacial unit base for distances in virtual pixels.
|
||||
@ -97,7 +95,13 @@ range2_pixels_to_cm :: #force_inline proc "contextless"( range : Range2 ) -> Ran
|
||||
|
||||
//endregion
|
||||
|
||||
Camera :: rl.Camera2D
|
||||
Camera :: struct {
|
||||
view : Extents2,
|
||||
position : Vec2,
|
||||
zoom : f32,
|
||||
}
|
||||
|
||||
Camera_Default := Camera { zoom = 1 }
|
||||
|
||||
CameraZoomMode :: enum u32 {
|
||||
Digital,
|
||||
@ -117,8 +121,8 @@ BoundsCorners2 :: struct {
|
||||
top_left, top_right, bottom_left, bottom_right: Vec2,
|
||||
}
|
||||
|
||||
Extents2 :: distinct Vec2
|
||||
Extents2i :: distinct Vec2i
|
||||
Extents2 :: Vec2
|
||||
Extents2i :: Vec2i
|
||||
|
||||
WS_Pos :: struct {
|
||||
tile_id : Vec2i,
|
||||
@ -162,8 +166,8 @@ view_get_bounds :: #force_inline proc "contextless"() -> Range2 {
|
||||
cam := & project.workspace.cam
|
||||
screen_extent := state.app_window.extent
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
bottom_left := Vec2 { cam.target.x, -cam.target.y } + Vec2 { -screen_extent.x, -screen_extent.y} * cam_zoom_ratio
|
||||
top_right := Vec2 { cam.target.x, -cam.target.y } + Vec2 { screen_extent.x, screen_extent.y} * cam_zoom_ratio
|
||||
bottom_left := Vec2 { cam.position.x, -cam.position.y } + Vec2 { -screen_extent.x, -screen_extent.y} * cam_zoom_ratio
|
||||
top_right := Vec2 { cam.position.x, -cam.position.y } + Vec2 { screen_extent.x, screen_extent.y} * cam_zoom_ratio
|
||||
return range2( bottom_left, top_right )
|
||||
}
|
||||
|
||||
@ -173,10 +177,10 @@ view_get_corners :: #force_inline proc "contextless"() -> BoundsCorners2 {
|
||||
cam := & project.workspace.cam
|
||||
cam_zoom_ratio := 1.0 / cam.zoom
|
||||
screen_extent := state.app_window.extent * cam_zoom_ratio
|
||||
top_left := cam.target + Vec2 { -screen_extent.x, screen_extent.y }
|
||||
top_right := cam.target + Vec2 { screen_extent.x, screen_extent.y }
|
||||
bottom_left := cam.target + Vec2 { -screen_extent.x, -screen_extent.y }
|
||||
bottom_right := cam.target + Vec2 { screen_extent.x, -screen_extent.y }
|
||||
top_left := cam.position + Vec2 { -screen_extent.x, screen_extent.y }
|
||||
top_right := cam.position + Vec2 { screen_extent.x, screen_extent.y }
|
||||
bottom_left := cam.position + Vec2 { -screen_extent.x, -screen_extent.y }
|
||||
bottom_right := cam.position + Vec2 { screen_extent.x, -screen_extent.y }
|
||||
return { top_left, top_right, bottom_left, bottom_right }
|
||||
}
|
||||
|
||||
@ -196,7 +200,7 @@ render_to_ws_view_pos :: #force_inline proc "contextless" (pos : Vec2) -> Vec2 {
|
||||
screen_to_ws_view_pos :: #force_inline proc "contextless" (pos: Vec2) -> Vec2 {
|
||||
state := get_state(); using state
|
||||
cam := & project.workspace.cam
|
||||
result := Vec2 { cam.target.x, -cam.target.y} + Vec2 { pos.x, pos.y } * (1 / cam.zoom)
|
||||
result := Vec2 { cam.position.x, -cam.position.y} + Vec2 { pos.x, pos.y } * (1 / cam.zoom)
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -62,9 +62,9 @@ UI_LayoutSide :: struct {
|
||||
|
||||
UI_LayoutFlag :: enum u32 {
|
||||
|
||||
// Will perform scissor pass on children to their parent's bounds
|
||||
// Will NOT perform scissor pass on children to their parent's bounds
|
||||
// (Specified in the parent)
|
||||
Clip_Children_To_Bounds,
|
||||
Dont_Clip_Children_To_bounds,
|
||||
|
||||
// Enforces the box will always remain in a specific position relative to the parent.
|
||||
// Overriding the anchors and margins.
|
||||
|
@ -86,6 +86,7 @@ UI_Parent_Stack_Size :: 512
|
||||
// UI_Built_Boxes_Array_Size :: 8
|
||||
UI_Built_Boxes_Array_Size :: 128 * Kilobyte
|
||||
|
||||
// TODO(Ed): Rename to UI_Context
|
||||
UI_State :: struct {
|
||||
// TODO(Ed) : Use these
|
||||
// build_arenas : [2]Arena,
|
||||
|
@ -17,8 +17,8 @@ UI_StylePreset :: enum u32 {
|
||||
}
|
||||
|
||||
UI_Style :: struct {
|
||||
bg_color : Color,
|
||||
border_color : Color,
|
||||
bg_color : RGBA8,
|
||||
border_color : RGBA8,
|
||||
|
||||
// TODO(Ed): We cannot support individual corners unless we add it to raylib (or finally change the rendering backend)
|
||||
corner_radii : [Corner.Count]f32,
|
||||
@ -33,7 +33,7 @@ UI_Style :: struct {
|
||||
// shader : UI_Shader,
|
||||
|
||||
font : FontID,
|
||||
text_color : Color,
|
||||
text_color : RGBA8,
|
||||
|
||||
// TODO(Ed) : Support setting the cursor state
|
||||
cursor : UI_Cursor,
|
||||
|
Loading…
Reference in New Issue
Block a user