SectrPrototype/code/api.odin

237 lines
7.1 KiB
Odin
Raw Normal View History

2024-01-21 20:38:02 -08:00
package sectr
import "base:runtime"
import c "core:c/libc"
2024-01-21 20:38:02 -08:00
import "core:dynlib"
import "core:fmt"
import "core:mem"
import "core:mem/virtual"
2024-01-21 20:38:02 -08:00
import "core:os"
import "core:slice"
2024-01-21 20:38:02 -08:00
import "core:strings"
import rl "vendor:raylib"
Path_Assets :: "../assets/"
Path_Input_Replay :: "scratch.sectr_replay"
2024-01-21 20:38:02 -08:00
ModuleAPI :: struct {
lib : dynlib.Library,
2024-01-22 00:47:53 -08:00
write_time : os.File_Time,
2024-01-21 20:38:02 -08:00
lib_version : i32,
startup : type_of( startup ),
shutdown : type_of( sectr_shutdown ),
reload : type_of( reload ),
tick : type_of( tick ),
clean_temp : type_of( clean_temp ),
2024-01-21 20:38:02 -08:00
}
@export
startup :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ Logger )
2024-01-21 20:38:02 -08:00
{
init( & memory.logger, "Sectr", host_logger.file_path, host_logger.file )
context.logger = to_odin_logger( & memory.logger )
// Setup memory for the first time
{
arena_size :: size_of( mem.Arena)
internals_size :: 4 * Megabyte
using memory;
block := live_mem.curr_block
live = live_mem
snapshot = snapshot_mem
persistent_slice := slice_ptr( block.base, memory_persistent_size )
transient_slice := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size )
temp_slice := slice_ptr( memory_after( transient_slice), memory_trans_temp_size )
2024-02-13 14:16:39 -08:00
when Use_TrackingAllocator {
// We assign the beginning of the block to be the host's persistent memory's arena.
// Then we offset past the arena and determine its slice to be the amount left after for the size of host's persistent.
persistent = tracked_allocator_init_vmem( persistent_slice, internals_size )
transient = tracked_allocator_init_vmem( transient_slice, internals_size )
temp = tracked_allocator_init_vmem( temp_slice , internals_size )
}
else {
persistent = arena_allocator_init_vmem( persistent_slice )
transient = arena_allocator_init_vmem( transient_slice )
temp = arena_allocator_init_vmem( temp_slice )
}
context.allocator = transient_allocator()
context.temp_allocator = temp_allocator()
}
2024-02-13 14:16:39 -08:00
state := new( State, persistent_allocator() )
using state
2024-01-21 20:38:02 -08:00
context.user_ptr = state
input = & input_data[1]
input_prev = & input_data[0]
// rl.Odin_SetMalloc( RL_MALLOC )
2024-02-13 14:16:39 -08:00
rl.SetConfigFlags( { rl.ConfigFlag.WINDOW_RESIZABLE /*, rl.ConfigFlag.WINDOW_TOPMOST*/ } )
2024-01-21 20:38:02 -08:00
// Rough setup of window with rl stuff
window_width : i32 = 1000
window_height : i32 = 600
2024-01-21 20:38:02 -08:00
win_title : cstring = "Sectr Prototype"
rl.InitWindow( window_width, window_height, win_title )
log( "Raylib initialized and window opened" )
2024-01-21 20:38:02 -08:00
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
2024-02-13 14:16:39 -08:00
window.ppcm = os_default_ppcm * window.dpi_scale
2024-01-21 20:38:02 -08:00
// Determining current monitor and setting the target frametime based on it..
monitor_id = rl.GetCurrentMonitor()
2024-01-22 00:47:53 -08:00
monitor_refresh_hz = rl.GetMonitorRefreshRate( monitor_id )
2024-01-21 20:38:02 -08:00
rl.SetTargetFPS( monitor_refresh_hz )
log( fmt.tprintf( "Set target FPS to: %v", monitor_refresh_hz ) )
2024-01-21 20:38:02 -08:00
// Basic Font Setup
{
2024-02-13 14:16:39 -08:00
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" )
2024-02-13 14:16:39 -08:00
// path_squidgy_slimes := strings.concatenate( { Path_Assets, "Squidgy Slimes.ttf" } )
// font_squidgy_slimes = font_load( path_squidgy_slimes, 24.0, "Squidgy_Slime" )
2024-02-13 14:16:39 -08:00
path_firacode := strings.concatenate( { Path_Assets, "FiraCode-Regular.ttf" } )
font_firacode = font_load( path_firacode, 24.0, "FiraCode" )
2024-02-13 14:16:39 -08:00
// font_data, read_succeded : = os.read_entire_file( path_rec_mono_semicasual_reg )
// verify( ! read_succeded, fmt.tprintf("Failed to read font file for: %v", path_rec_mono_semicasual_reg) )
2024-01-21 20:38:02 -08:00
2024-02-13 14:16:39 -08:00
// cstr := strings.clone_to_cstring( path_rec_mono_semicasual_reg )
// font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, cast(i32) points_to_pixels(24.0), nil, 0 )
// delete( cstr)
// rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything?
default_font = font_firacode
log( "Default font loaded" )
2024-01-21 20:38:02 -08:00
}
// Demo project setup
{
using project
path = "./"
name = "First Project"
workspace.name = "First Workspace"
{
using project.workspace
cam = {
2024-02-13 14:16:39 -08:00
target = { 0, 0 },
offset = transmute(Vec2) window.extent,
rotation = 0,
2024-02-13 14:16:39 -08:00
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, persistent_allocator() )
}
}
2024-01-21 20:38:02 -08:00
}
// For some reason odin's symbols conflict with native foreign symbols...
@export
sectr_shutdown :: proc()
{
2024-01-22 00:47:53 -08:00
if memory.persistent == nil {
return
}
state := get_state()
// Replay
{
os.close( memory.replay.active_file )
}
2024-02-13 14:16:39 -08:00
font_provider_shutdown()
log("Module shutdown complete")
2024-01-21 20:38:02 -08:00
}
@export
reload :: proc( live_mem : virtual.Arena, snapshot_mem : []u8, host_logger : ^ Logger )
2024-01-21 20:38:02 -08:00
{
using memory;
block := live_mem.curr_block
live = live_mem
snapshot = snapshot_mem
persistent_slice := slice_ptr( block.base, memory_persistent_size )
transient_slice := slice_ptr( memory_after( persistent_slice), memory_trans_temp_size )
temp_slice := slice_ptr( memory_after( transient_slice), memory_trans_temp_size )
2024-02-13 14:16:39 -08:00
when Use_TrackingAllocator {
persistent = cast( ^ TrackedAllocator ) & persistent_slice[0]
transient = cast( ^ TrackedAllocator ) & transient_slice[0]
temp = cast( ^ TrackedAllocator ) & temp_slice[0]
}
else {
persistent = cast( ^ Arena ) & persistent_slice[0]
transient = cast( ^ Arena ) & transient_slice[0]
temp = cast( ^ Arena ) & temp_slice[0]
}
2024-02-13 14:16:39 -08:00
context.allocator = transient_allocator()
context.temp_allocator = temp_allocator()
// 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.
// font_provider_data := & get_state().font_provider_data
// font_provider_data.font_cache.allocator = arena_allocator( & font_provider_data.font_arena )
// Have to reload allocators for all dynamic allocating data-structures.
ui_reload( & get_state().project.workspace.ui, persistent_allocator() )
log("Module reloaded")
}
// TODO(Ed) : This lang really not have a fucking swap?
swap :: proc( a, b : ^ $Type ) -> ( ^ Type, ^ Type ) {
return b, a
2024-01-21 20:38:02 -08:00
}
@export
tick :: proc ( delta_time : f64 ) -> b32
2024-01-21 20:38:02 -08:00
{
context.allocator = transient_allocator()
context.temp_allocator = temp_allocator()
result := update( delta_time )
render()
return result
2024-01-21 20:38:02 -08:00
}
@export
2024-02-13 14:16:39 -08:00
clean_temp :: proc() {
when Use_TrackingAllocator {
mem.tracking_allocator_clear( & memory.temp.tracker )
}
else {
free_all( temp_allocator() )
}
}