Odin is nice.
This commit is contained in:
parent
d0c016a355
commit
3b259f2893
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -8,9 +8,9 @@
|
||||
"type": "lldb",
|
||||
"request": "launch",
|
||||
"name": "Debug",
|
||||
"program": "${workspaceFolder}/<executable file>",
|
||||
"program": "${workspaceFolder}/build/sectr_host.exe",
|
||||
"args": [],
|
||||
"cwd": "${workspaceFolder}"
|
||||
"cwd": "${workspaceFolder}/build"
|
||||
}
|
||||
]
|
||||
}
|
BIN
Debug.rdbg
BIN
Debug.rdbg
Binary file not shown.
@ -2,3 +2,4 @@ package sectr
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Font :: rl.Font
|
||||
|
120
code/api.odin
Normal file
120
code/api.odin
Normal file
@ -0,0 +1,120 @@
|
||||
package sectr
|
||||
|
||||
import "core:dynlib"
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Path_Assets :: "../assets/"
|
||||
|
||||
ModuleAPI :: struct {
|
||||
lib : dynlib.Library,
|
||||
load_time : os.File_Time,
|
||||
lib_version : i32,
|
||||
|
||||
startup : type_of( startup ),
|
||||
shutdown : type_of( sectr_shutdown),
|
||||
reload : type_of( reload ),
|
||||
update : type_of( update ),
|
||||
render : type_of( render )
|
||||
}
|
||||
|
||||
Memory :: struct {
|
||||
persistent : ^ mem.Arena,
|
||||
transient : ^ mem.Arena
|
||||
}
|
||||
|
||||
memory : Memory
|
||||
|
||||
@export
|
||||
startup :: proc( persistent, transient : ^ mem.Arena )
|
||||
{
|
||||
memory.persistent = persistent
|
||||
memory.transient = transient
|
||||
context.allocator = mem.arena_allocator( transient )
|
||||
context.temp_allocator = mem.arena_allocator( transient )
|
||||
|
||||
state := cast(^State) memory.persistent
|
||||
|
||||
// Rough setup of window with rl stuff
|
||||
screen_width : i32 = 1280
|
||||
screen_height : i32 = 1000
|
||||
win_title : cstring = "Sectr Prototype"
|
||||
rl.InitWindow( screen_width, screen_height, win_title )
|
||||
|
||||
// Determining current monitor and setting the target frametime based on it..
|
||||
monitor_id := rl.GetCurrentMonitor()
|
||||
monitor_refresh_hz := rl.GetMonitorRefreshRate( monitor_id )
|
||||
rl.SetTargetFPS( monitor_refresh_hz )
|
||||
fmt.println( "Set target FPS to: %v", monitor_refresh_hz )
|
||||
|
||||
// Basic Font Setup
|
||||
{
|
||||
path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" })
|
||||
cstr := strings.clone_to_cstring(path_rec_mono_semicasual_reg)
|
||||
font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, 24, nil, 0 )
|
||||
delete( cstr)
|
||||
|
||||
rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything?
|
||||
default_font = font_rec_mono_semicasual_reg
|
||||
}
|
||||
}
|
||||
|
||||
// For some reason odin's symbols conflict with native foreign symbols...
|
||||
@export
|
||||
sectr_shutdown :: proc()
|
||||
{
|
||||
rl.UnloadFont( font_rec_mono_semicasual_reg )
|
||||
rl.CloseWindow()
|
||||
}
|
||||
|
||||
@export
|
||||
reload :: proc( persistent, transient : ^ mem.Arena )
|
||||
{
|
||||
memory.persistent = persistent
|
||||
memory.transient = transient
|
||||
context.allocator = mem.arena_allocator( persistent )
|
||||
context.temp_allocator = mem.arena_allocator( transient )
|
||||
}
|
||||
|
||||
@export
|
||||
update :: proc() -> b32
|
||||
{
|
||||
should_shutdown : b32 = ! cast(b32) rl.WindowShouldClose()
|
||||
return should_shutdown
|
||||
}
|
||||
|
||||
draw_text_y : f32 = 50
|
||||
@export
|
||||
render :: proc()
|
||||
{
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground( Color_BG )
|
||||
defer {
|
||||
rl.DrawFPS( 0, 0 )
|
||||
rl.EndDrawing()
|
||||
// Note(Ed) : Polls input as well.
|
||||
}
|
||||
|
||||
draw_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@static
|
||||
draw_text_scratch : [Kilobyte * 64]u8
|
||||
if ( draw_text_y > 500 ) {
|
||||
draw_text_y = 50
|
||||
}
|
||||
|
||||
content := fmt.bprintf( draw_text_scratch[:], format, ..args )
|
||||
debug_text( content, 25, draw_text_y )
|
||||
|
||||
draw_text_y += 16
|
||||
}
|
||||
|
||||
draw_text( "Monitor : %v", rl.GetMonitorName(0) )
|
||||
draw_text( "Screen Width : %v", rl.GetScreenWidth() )
|
||||
draw_text( "Screen Height: %v", rl.GetScreenHeight() )
|
||||
|
||||
draw_text_y = 50
|
||||
}
|
@ -2,7 +2,9 @@ package sectr
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Color_BG :: rl.Color { 41, 41, 45, 255 }
|
||||
Color_BG_TextBox :: rl.Color { 32, 32, 32, 255 }
|
||||
Color_Frame_Hover :: rl.Color { 122, 122, 125, 255 }
|
||||
Color_Frame_Select :: rl.Color { 188, 188, 188, 255 }
|
||||
Color :: rl.Color
|
||||
|
||||
Color_BG :: Color { 41, 41, 45, 255 }
|
||||
Color_BG_TextBox :: Color { 32, 32, 32, 255 }
|
||||
Color_Frame_Hover :: Color { 122, 122, 125, 255 }
|
||||
Color_Frame_Select :: Color { 188, 188, 188, 255 }
|
||||
|
@ -1,51 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
draw_text_y : f32 = 50
|
||||
|
||||
run_cycle :: proc( running : ^b32 )
|
||||
{
|
||||
for ; running^ ;
|
||||
{
|
||||
if rl.WindowShouldClose() {
|
||||
running^ = false;
|
||||
}
|
||||
|
||||
// Logic Update
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Rendering
|
||||
{
|
||||
rl.BeginDrawing()
|
||||
rl.ClearBackground( Color_BG )
|
||||
defer {
|
||||
rl.DrawFPS( 0, 0 )
|
||||
rl.EndDrawing()
|
||||
// Note(Ed) : Polls input as well.
|
||||
}
|
||||
|
||||
draw_text :: proc( format : string, args : ..any )
|
||||
{
|
||||
@static draw_text_scratch : [65536]u8
|
||||
if ( draw_text_y > 500 ) {
|
||||
draw_text_y = 50
|
||||
}
|
||||
content := fmt.bprintf( draw_text_scratch[:], format, ..args )
|
||||
debug_text( content, 25, draw_text_y )
|
||||
draw_text_y += 16
|
||||
}
|
||||
|
||||
draw_text( "Monitor : %v", rl.GetMonitorName(0) )
|
||||
draw_text( "Screen Width : %v", rl.GetScreenWidth() )
|
||||
draw_text( "Screen Height: %v", rl.GetScreenHeight() )
|
||||
|
||||
|
||||
draw_text_y = 50
|
||||
}
|
||||
}
|
||||
}
|
25
code/env.odin
Normal file
25
code/env.odin
Normal file
@ -0,0 +1,25 @@
|
||||
package sectr
|
||||
|
||||
State :: struct {
|
||||
project : Project,
|
||||
|
||||
screen_width : i32,
|
||||
screen_height : i32,
|
||||
|
||||
monitor_id : i32,
|
||||
monitor_refresh_hz : i32,
|
||||
|
||||
engine_refresh_hz : i32,
|
||||
engine_refresh_target : i32,
|
||||
|
||||
draw_debug_text_y : f32
|
||||
}
|
||||
|
||||
Project :: struct {
|
||||
// TODO(Ed) : Support multiple workspaces
|
||||
workspace : Workspace
|
||||
}
|
||||
|
||||
Workspace :: struct {
|
||||
|
||||
}
|
33
code/filesystem.odin
Normal file
33
code/filesystem.odin
Normal file
@ -0,0 +1,33 @@
|
||||
package sectr
|
||||
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
import "core:runtime"
|
||||
|
||||
copy_file_sync :: proc( path_src, path_dst: string ) -> bool
|
||||
{
|
||||
file_size : i64
|
||||
{
|
||||
path_info, result := os.stat( path_src, context.temp_allocator )
|
||||
if result != os.ERROR_NONE {
|
||||
fmt.println("Error getting file info: ", result )
|
||||
return false
|
||||
}
|
||||
file_size = path_info.size
|
||||
}
|
||||
|
||||
src_content, result := os.read_entire_file( path_src, context.temp_allocator )
|
||||
if ! result {
|
||||
fmt.println( "Failed to read file to copy" )
|
||||
runtime.debug_trap()
|
||||
return false
|
||||
}
|
||||
|
||||
result = os.write_entire_file( path_dst, src_content, false )
|
||||
if ! result {
|
||||
fmt.println( "Failed to copy file")
|
||||
runtime.debug_trap()
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
177
code/host/host.odin
Normal file
177
code/host/host.odin
Normal file
@ -0,0 +1,177 @@
|
||||
package host
|
||||
|
||||
import "core:dynlib"
|
||||
import "core:io"
|
||||
import "core:fmt"
|
||||
import "core:log"
|
||||
import "core:mem"
|
||||
import "core:mem/virtual"
|
||||
Byte :: 1
|
||||
Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
Petabyte :: 1024 * Terabyte
|
||||
Exabyte :: 1024 * Petabyte
|
||||
import "core:os"
|
||||
import "core:runtime"
|
||||
import "core:strings"
|
||||
import rl "vendor:raylib"
|
||||
import sectr "../."
|
||||
|
||||
RuntimeState :: struct {
|
||||
running : b32,
|
||||
|
||||
|
||||
memory : VMemChunk,
|
||||
|
||||
sectr_api : sectr.ModuleAPI,
|
||||
}
|
||||
|
||||
VMemChunk :: struct {
|
||||
sarena : virtual.Arena,
|
||||
eng_persistent : mem.Arena,
|
||||
eng_transient : mem.Arena,
|
||||
env_persistent : mem.Arena,
|
||||
env_transient : mem.Arena
|
||||
}
|
||||
|
||||
setup_engine_memory :: proc () -> VMemChunk
|
||||
{
|
||||
memory : VMemChunk
|
||||
using memory
|
||||
|
||||
arena_init :: mem.arena_init
|
||||
ptr_offset :: mem.ptr_offset
|
||||
slice_ptr :: mem.slice_ptr
|
||||
|
||||
// Setup the static arena for the entire application
|
||||
if result := virtual.arena_init_static( & sarena, Gigabyte * 2, Gigabyte * 2 );
|
||||
result != runtime.Allocator_Error.None
|
||||
{
|
||||
// TODO(Ed) : Setup a proper logging interface
|
||||
fmt. printf( "Failed to allocate memory for the engine" )
|
||||
runtime.debug_trap()
|
||||
os. exit( -1 )
|
||||
// TODO(Ed) : Figure out the error code enums..
|
||||
}
|
||||
|
||||
// For now I'm making persistent sections each 128 meg and transient sections w/e is left over / 2 (one for engine the other for the env)
|
||||
persistent_size := Megabyte * 128
|
||||
transient_size := (Gigabyte * 2 - persistent_size * 2) / 2
|
||||
|
||||
block := memory.sarena.curr_block
|
||||
|
||||
// Try to get a slice for each segment
|
||||
eng_persistent_slice := slice_ptr( block.base, persistent_size)
|
||||
eng_transient_slice := slice_ptr( & eng_persistent_slice[persistent_size - 1], transient_size)
|
||||
env_persistent_slice := slice_ptr( & eng_transient_slice [transient_size - 1], persistent_size)
|
||||
env_transient_slice := slice_ptr( & env_persistent_slice[persistent_size -1], transient_size)
|
||||
|
||||
arena_init( & eng_persistent, eng_persistent_slice )
|
||||
arena_init( & eng_transient, eng_transient_slice )
|
||||
arena_init( & env_persistent, env_persistent_slice )
|
||||
arena_init( & env_transient, env_transient_slice )
|
||||
|
||||
return memory;
|
||||
}
|
||||
|
||||
load_sectr_api :: proc ( version_id : i32 ) -> sectr.ModuleAPI
|
||||
{
|
||||
loaded_module : sectr.ModuleAPI
|
||||
|
||||
load_time,
|
||||
result := os.last_write_time_by_name("sectr.dll")
|
||||
if result != os.ERROR_NONE {
|
||||
fmt. println("Could not resolve the last write time for sectr.dll")
|
||||
runtime.debug_trap()
|
||||
return {}
|
||||
}
|
||||
|
||||
lock_file := fmt.tprintf( "sectr_{0}_locked.dll", version_id )
|
||||
sectr.copy_file_sync( "sectr.dll", lock_file )
|
||||
|
||||
lib, load_result := dynlib.load_library( lock_file )
|
||||
if ! load_result {
|
||||
fmt. println( "Failed to load the sectr module." )
|
||||
runtime.debug_trap()
|
||||
return {}
|
||||
}
|
||||
|
||||
loaded_module = {
|
||||
lib = lib,
|
||||
load_time = load_time,
|
||||
lib_version = version_id,
|
||||
|
||||
startup = cast( type_of( sectr.startup )) dynlib.symbol_address( lib, "startup" ),
|
||||
shutdown = cast( type_of( sectr.sectr_shutdown )) dynlib.symbol_address( lib, "sectr_shutdown" ),
|
||||
reload = cast( type_of( sectr.reload )) dynlib.symbol_address( lib, "reload" ),
|
||||
update = cast( type_of( sectr.update )) dynlib.symbol_address( lib, "update" ),
|
||||
render = cast( type_of( sectr.render )) dynlib.symbol_address( lib, "render" )
|
||||
}
|
||||
return loaded_module
|
||||
}
|
||||
|
||||
main :: proc()
|
||||
{
|
||||
fmt.println("Hellope!")
|
||||
|
||||
// Basic Giant VMem Block
|
||||
memory : VMemChunk
|
||||
{
|
||||
// By default odin uses a growing arena for the runtime context
|
||||
// We're going to make it static for the prototype and separate it from the 'project' memory.
|
||||
// Then shove the context allocator for the engine to it.
|
||||
// The project's context will use its own subsection arena allocator.
|
||||
memory = setup_engine_memory()
|
||||
context.allocator = mem.arena_allocator( & memory.eng_persistent )
|
||||
context.temp_allocator = mem.arena_allocator( & memory.eng_transient )
|
||||
}
|
||||
|
||||
// Load the Enviornment API for the first-time
|
||||
sectr_api : sectr.ModuleAPI
|
||||
{
|
||||
sectr_api = load_sectr_api( 1 )
|
||||
if sectr_api.lib_version == 0 {
|
||||
fmt. println( "Failed to initially load the sectr module" )
|
||||
runtime.debug_trap()
|
||||
os. exit( -1 )
|
||||
}
|
||||
}
|
||||
|
||||
state : RuntimeState
|
||||
state.running = true;
|
||||
// state.monitor_id = monitor_id
|
||||
// state.screen_width = screen_width
|
||||
// state.screen_height = screen_height
|
||||
// state.monitor_id = monitor_id
|
||||
// state.monitor_refresh_hz = monitor_refresh_hz
|
||||
state.memory = memory
|
||||
state.sectr_api = sectr_api
|
||||
|
||||
state.sectr_api.startup( & memory.env_persistent, & memory.env_persistent )
|
||||
|
||||
// TODO(Ed) : This should return a end status so that we know the reason the engine stopped.
|
||||
for ; state.running ;
|
||||
{
|
||||
// Hot-Reload
|
||||
// TODO(ED) : Detect if currently loaded code is outdated.
|
||||
{
|
||||
// state.sectr_api.reload()
|
||||
}
|
||||
|
||||
// Logic Update
|
||||
state.running = state.sectr_api.update()
|
||||
|
||||
// Rendering
|
||||
state.sectr_api.render()
|
||||
}
|
||||
|
||||
// Determine how the run_cyle completed, if it failed due to an error,
|
||||
// fallback the env to a failsafe state and reload the run_cycle.
|
||||
{
|
||||
// TODO(Ed): Implement this.
|
||||
}
|
||||
|
||||
state.sectr_api.shutdown()
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package sectr
|
||||
|
||||
import "core:strings"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
Path_Assets :: "../assets/"
|
||||
|
||||
|
||||
WindowState :: struct {
|
||||
|
||||
}
|
||||
|
||||
main :: proc()
|
||||
{
|
||||
// Rough setup of window with rl stuff
|
||||
screen_width : i32 = 1280
|
||||
screen_height : i32 = 1000
|
||||
win_title : cstring = "Sectr Prototype"
|
||||
rl.InitWindow( screen_width, screen_height, win_title )
|
||||
defer {
|
||||
rl.CloseWindow()
|
||||
}
|
||||
|
||||
monitor_id := rl.GetCurrentMonitor()
|
||||
monitor_refresh_rate := rl.GetMonitorRefreshRate( monitor_id )
|
||||
rl.SetTargetFPS( monitor_refresh_rate )
|
||||
|
||||
// Basic Font Setup
|
||||
{
|
||||
path_rec_mono_semicasual_reg := strings.concatenate( { Path_Assets, "RecMonoSemicasual-Regular-1.084.ttf" } )
|
||||
cstr := strings.clone_to_cstring(path_rec_mono_semicasual_reg)
|
||||
font_rec_mono_semicasual_reg = rl.LoadFontEx( cstr, 24, nil, 0 )
|
||||
delete( cstr )
|
||||
|
||||
rl.GuiSetFont( font_rec_mono_semicasual_reg ) // TODO(Ed) : Does this do anything?
|
||||
default_font = font_rec_mono_semicasual_reg
|
||||
}
|
||||
|
||||
running : b32 = true
|
||||
run_cycle( & running )
|
||||
}
|
@ -1,8 +1,21 @@
|
||||
package sectr
|
||||
|
||||
kilobytes :: proc ( kb : $integer_type ) -> integer_type {
|
||||
import "core:fmt"
|
||||
import "core:mem"
|
||||
import "core:mem/virtual"
|
||||
import "core:runtime"
|
||||
|
||||
Byte :: 1
|
||||
Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
Petabyte :: 1024 * Terabyte
|
||||
Exabyte :: 1024 * Petabyte
|
||||
|
||||
kilobytes :: proc ( kb : $ integer_type ) -> integer_type {
|
||||
return kb * 1024
|
||||
}
|
||||
megabytes :: proc ( kb : $integer_type ) -> integer_type {
|
||||
megabytes :: proc ( kb : $ integer_type ) -> integer_type {
|
||||
return kb * 1024 * 1024
|
||||
}
|
||||
|
@ -4,15 +4,15 @@ import "core:unicode/utf8"
|
||||
|
||||
import rl "vendor:raylib"
|
||||
|
||||
font_rec_mono_semicasual_reg : rl.Font;
|
||||
default_font : rl.Font
|
||||
font_rec_mono_semicasual_reg : Font;
|
||||
default_font : Font
|
||||
|
||||
debug_text :: proc( content : string, x, y : f32, size : f32 = 16.0, color : rl.Color = rl.WHITE, font : rl.Font = default_font )
|
||||
{
|
||||
if len( content ) == 0 {
|
||||
return
|
||||
}
|
||||
runes := utf8.string_to_runes( content )
|
||||
runes := utf8.string_to_runes( content, context.temp_allocator )
|
||||
|
||||
rl.DrawTextCodepoints( font,
|
||||
raw_data(runes), cast(i32) len(runes),
|
||||
|
@ -24,6 +24,7 @@ $flag_show_more_timings = '-show-more-timings'
|
||||
$flag_thread_count = '-thread-count:'
|
||||
$flag_collection = '-collection:'
|
||||
$flag_build_mode = '-build-mode:'
|
||||
$flag_build_mode_dll = '-build-mode:dll'
|
||||
$flag_no_bounds_check = '-no-bounds-check'
|
||||
$flag_disable_assert = '-disable-assert'
|
||||
$flag_no_thread_local = '-no-thread-local'
|
||||
@ -58,12 +59,12 @@ push-location $path_root
|
||||
push-location $path_code
|
||||
|
||||
$project_name = 'sectr'
|
||||
$executable = join-path $path_build ($project_name + '.exe')
|
||||
$pdb = join-path $path_build ($project_name + '.pdb')
|
||||
$executable = join-path $path_build ($project_name + '_host.exe')
|
||||
$pdb = join-path $path_build ($project_name + '_host.pdb')
|
||||
|
||||
$build_args = @()
|
||||
$build_args += $flag_build
|
||||
$build_args += '.'
|
||||
$build_args += './host'
|
||||
$build_args += $flag_output_path + $executable
|
||||
$build_args += $flag_optimize_none
|
||||
$build_args += $flag_debug
|
||||
@ -72,6 +73,20 @@ push-location $path_root
|
||||
|
||||
& odin $build_args
|
||||
|
||||
$module_dll = join-path $path_build ( $project_name + '.dll' )
|
||||
$pdb = join-path $path_build ( $project_name + '.pdb' )
|
||||
|
||||
$build_args = @()
|
||||
$build_args += $flag_build
|
||||
$build_args += '.'
|
||||
$build_args += $flag_build_mode_dll
|
||||
$build_args += $flag_output_path + $module_dll
|
||||
$build_args += $flag_optimize_none
|
||||
$build_args += $flag_debug
|
||||
$build_args += $flag_pdb_name + $pdb
|
||||
|
||||
& odin $build_args
|
||||
|
||||
Pop-Location
|
||||
}
|
||||
build-prototype
|
||||
|
Loading…
Reference in New Issue
Block a user