Got it to compile with sokol changes (UNTESTED)

This commit is contained in:
Edward R. Gonzalez 2024-05-22 03:28:16 -04:00
parent 405716e52b
commit 9cd0692e56
8 changed files with 600 additions and 3 deletions

View File

@ -351,7 +351,5 @@ main :: proc()
log("Succesfuly closed")
file_close( logger.file )
// TODO(Ed) : Add string interning!!!!!!!!!
// file_rename( logger.file_path, path_logger_finalized )
file_rename( str_fmt_buffer( fmt_backing[:], "%s/sectr.log", Path_Logs), path_logger_finalized )
}

View File

@ -249,6 +249,9 @@ State :: struct {
// The camera is considered the "context" for coodrinate space operations in rendering
cam_context : Camera,
// sokol_relay : SokolRelay,
sokol_context : runtime.Context,
}
get_state :: #force_inline proc "contextless" () -> ^ State {

View File

@ -12,6 +12,7 @@ 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"
@ -418,3 +419,5 @@ clean_frame :: proc()
verify( alloc_error == .None, "Failed to allocate transient slab" )
}
}
} // when false

View File

@ -0,0 +1,465 @@
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 sokol_app "thirdparty:sokol/app"
import rl "vendor:raylib"
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 = persistent_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 )
// Setup for sokol_app
{
sokol_context = context
desc := sokol_app.Desc {
init_cb = sokol_app_init_callback,
frame_cb = sokol_app_frame_callback,
cleanup_cb = sokol_app_cleanup_callback,
event_cb = sokol_app_event_callback,
width = cast(c.int) config.resolution_width,
height = cast(c.int) config.resolution_height,
sample_count = 0,
// swap_interval = config.monitor_refresh_hz,
high_dpi = false,
fullscreen = false,
alpha = false,
window_title = "Sectr Prototype",
// icon = { sokol_app.sokol_default },
enable_clipboard = false, // TODO(Ed): Implmeent this
enable_dragndrop = false, // TODO(Ed): Implmeent this
logger = { sokol_app_log_callback, nil },
allocator = { sokol_app_alloc, sokol_app_free, nil },
}
sokol_app.pre_client_init(desc)
sokol_app.client_init()
// 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
if false
{
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
if false
{
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
if false
{
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_alloc("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()
sokol_app.post_client_cleanup()
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
{
should_close : b32
profile_begin("sokol_app: pre_client_tick")
should_close |= cast(b32) sokol_app.pre_client_frame()
profile_end()
profile( "Client Tick" )
context.logger = to_odin_logger( & Memory_App.logger )
state := get_state(); using state
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 {
log( str_fmt_tmp("Big tick! %v ms", frametime_elapsed_ms), LogLevel.Warning )
}
profile_begin("sokol_app: post_client_tick")
sokol_app.post_client_frame()
profile_end()
}
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" )
}
}

View File

@ -0,0 +1,115 @@
package sectr
import "base:runtime"
import str "core:strings"
import sokol_app "thirdparty:sokol/app"
// SokolLogEntry :: struct {
// tag: cstring,
// log_level: u32,
// log_item_id: u32,
// message_or_null: cstring,
// line_nr: u32,
// filename_or_null : cstring,
// }
// SokolRelay :: struct {
// logs : StackFixed(SokolLogEntry, 512),
// }
// sokol_relay :: #force_inline proc "contextless" () -> ^SokolRelay {
// return & get_state().sokol_relay
// }
sokol_app_init_callback :: proc "c" () {
context = get_state().sokol_context
log("sokol_app: Confirmed initialization")
// stack_push_contextless( & sokol_relay().logs, { "", 3, 0, "sokol_app: Confirmed initialization", 29, #file })
}
// This is being filled in but we're directly controlling the lifetime of sokol_app's execution.
// Thus we have no need for it todo frame callbacks
sokol_app_frame_callback :: proc "c" () {
context = get_state().sokol_context
log("sokol_app: SHOULD NOT HAVE CALLED THE FRAME CALLABCK")
// stack_push_contextless( & sokol_relay().logs, { "", 3, 0, "sokol_app: SHOULD NOT HAVE CALLED THE FRAME CALLBACK", 29, #file })
}
sokol_app_cleanup_callback :: proc "c" () {
context = get_state().sokol_context
log("sokol_app: Confirmed cleanup")
// stack_push_contextless( & sokol_relay().logs, { "", 3, 0, "sokol_app: Confirmed cleanup", 29, #file })
}
sokol_app_alloc :: proc "c" ( size : u64, user_data : rawptr ) -> rawptr {
context = get_state().sokol_context
block, error := alloc( int(size), allocator = persistent_slab_allocator() )
ensure(error != AllocatorError.None, "sokol_app allocation failed")
return block
}
sokol_app_free :: proc "c" ( data : rawptr, user_data : rawptr ) {
context = get_state().sokol_context
free(data, allocator = persistent_slab_allocator() )
}
sokol_app_log_callback :: proc "c" (
tag: cstring,
log_level: u32,
log_item_id: u32,
message_or_null: cstring,
line_nr: u32,
filename_or_null: cstring,
user_data: rawptr) {
context = get_state().sokol_context
odin_level : LogLevel
switch log_level {
case 0: odin_level = .Fatal
case 1: odin_level = .Error
case 2: odin_level = .Warning
case 3: odin_level = .Info
}
cloned_msg : string = ""
if message_or_null != nil {
cloned_msg = str.clone_from_cstring(message_or_null, context.temp_allocator)
}
cloned_fname : string = ""
if filename_or_null != nil {
cloned_fname = str.clone_from_cstring(filename_or_null, context.temp_allocator)
}
logf( "%-80s %v : %s::%s", cloned_msg, cloned_fname, str.clone_from_cstring(tag), level = odin_level )
// push( & sokol_relay().logs, {tag, log_level, log_item_id, message_or_null, line_nr, filename_or_null, user_data })
}
// sokol_app_relay_update :: proc()
// {
// logs := & sokol_relay().logs
// for ; logs.idx != 0; pop( logs ) {
// odin_level : LogLevel
// switch log_level {
// case 0: odin_level = .Fatal
// case 1: odin_level = .Error
// case 2: odin_level = .Warning
// case 3: odin_level = .Info
// }
// cloned_msg : string = ""
// if message != nil {
// cloned_msg = str.clone_from_cstring(message, context.temp_allocator)
// }
// cloned_fname : string = ""
// if filename_or_null {
// cloned_fname = str.clone_from_cstring(filename_or_null, context.temp_allocator)
// }
// logf( "%-80s %v : %s::%s", cloned_msg, cloned_fname, str.clone_from_cstring(tag), level = odin_level )
// }
// }
sokol_app_event_callback :: proc "c" (event : ^sokol_app.Event) {
}

View File

@ -65,7 +65,8 @@ logger_interface :: proc(
first_line_length := len(text) > Max_Logger_Message_Width ? Max_Logger_Message_Width : len(text)
first_line := transmute(string) text[ 0 : first_line_length ]
str_fmt_builder( & builder, "%-*s ", Max_Logger_Message_Width, first_line )
// str_fmt_builder( & builder, "%-s ", Max_Logger_Message_Width, first_line )
str_fmt_builder( & builder, "%-180s ", first_line )
// Signature
{

View File

@ -41,6 +41,11 @@ stack_peek :: #force_inline proc "contextless" ( using stack : ^StackFixed( $ Ty
return items[last]
}
stack_push_contextless :: #force_inline proc "contextless" ( stack : ^StackFixed( $Type, $Size), value : Type ) {
items[idx] = value
idx += 1
}
//endregion Fixed Stack
//region Stack Allocator

View File

@ -106,10 +106,17 @@ else
$path_vendor = join-path $path_odin 'vendor'
$path_vendor_raylib = join-path $path_vendor 'raylib'
$path_sokol_dlls = join-path $path_thirdparty 'sokol'
$path_raylib_dlls = join-path $path_vendor_raylib 'windows'
if ( $binaries_dirty -or $true )
{
$third_party_dlls = Get-ChildItem -Path $path_sokol_dlls -Filter '*.dll'
foreach ($dll in $third_party_dlls) {
$destination = join-path $path_build $dll.Name
Copy-Item $dll.FullName -Destination $destination -Force
}
$third_party_dlls = Get-ChildItem -Path $path_raylib_dlls -Filter '*.dll'
foreach ($dll in $third_party_dlls) {
$destination = join-path $path_build $dll.Name