Odin is nice.
This commit is contained in:
		| @@ -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), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user