Karl Zylinski 6 miesięcy temu
rodzic
commit
061908c52c

+ 1 - 1
api_doc_builder/api_doc_builder.odin

@@ -23,7 +23,7 @@ main :: proc() {
 
 
 	pln :: fmt.fprintln
 	pln :: fmt.fprintln
 
 
-	pln(o, "// This file is purely documentational and never built.")
+	pln(o, `/* This file is purely documentational. It is generated from the contents of 'karl2d.odin'.*/`)
 	pln(o, "#+build ignore")
 	pln(o, "#+build ignore")
 	pln(o, "package karl2d")
 	pln(o, "package karl2d")
 
 

+ 14 - 14
examples/raylib_ports/2d_camera/2d_camera.odin

@@ -74,32 +74,32 @@ main :: proc() {
 
 
 		k2.clear({ 245, 245, 245, 255 })
 		k2.clear({ 245, 245, 245, 255 })
 		k2.set_camera(camera)
 		k2.set_camera(camera)
-		k2.draw_rect({-6000, 320, 13000, 8000}, k2.DARKGRAY)
+		k2.draw_rect({-6000, 320, 13000, 8000}, k2.RL_DARKGRAY)
 
 
 		for i in 0..<MAX_BUILDINGS {
 		for i in 0..<MAX_BUILDINGS {
 			k2.draw_rect(buildings[i], building_colors[i])
 			k2.draw_rect(buildings[i], building_colors[i])
 		}
 		}
 
 
-		k2.draw_rect(player, k2.RED)
-		k2.draw_line({camera.target.x, -SCREEN_HEIGHT * 10}, {camera.target.x, SCREEN_HEIGHT * 10 }, 1, k2.GREEN)
-		k2.draw_line({-SCREEN_WIDTH*10, camera.target.y}, {SCREEN_WIDTH*10, camera.target.y}, 1, k2.GREEN)
+		k2.draw_rect(player, k2.RL_RED)
+		k2.draw_line({camera.target.x, -SCREEN_HEIGHT * 10}, {camera.target.x, SCREEN_HEIGHT * 10 }, 1, k2.RL_GREEN)
+		k2.draw_line({-SCREEN_WIDTH*10, camera.target.y}, {SCREEN_WIDTH*10, camera.target.y}, 1, k2.RL_GREEN)
 
 
 		k2.set_camera(nil)
 		k2.set_camera(nil)
-		k2.draw_text("SCREEN AREA", {640, 10}, 20, k2.RED)
+		k2.draw_text("SCREEN AREA", {640, 10}, 20, k2.RL_RED)
 
 
-		k2.draw_rect({0, 0, SCREEN_WIDTH, 5}, k2.RED)
-		k2.draw_rect({0, 5, 5, SCREEN_HEIGHT - 10}, k2.RED)
-		k2.draw_rect({SCREEN_WIDTH - 5, 5, 5, SCREEN_HEIGHT - 10}, k2.RED)
-		k2.draw_rect({0, SCREEN_HEIGHT - 5, SCREEN_WIDTH, 5}, k2.RED)
+		k2.draw_rect({0, 0, SCREEN_WIDTH, 5}, k2.RL_RED)
+		k2.draw_rect({0, 5, 5, SCREEN_HEIGHT - 10}, k2.RL_RED)
+		k2.draw_rect({SCREEN_WIDTH - 5, 5, 5, SCREEN_HEIGHT - 10}, k2.RL_RED)
+		k2.draw_rect({0, SCREEN_HEIGHT - 5, SCREEN_WIDTH, 5}, k2.RL_RED)
 
 
 		k2.draw_rect({10, 10, 250, 113}, {102, 191, 255, 128})
 		k2.draw_rect({10, 10, 250, 113}, {102, 191, 255, 128})
-		k2.draw_rect_outline({10, 10, 250, 113}, 1, k2.BLUE)
+		k2.draw_rect_outline({10, 10, 250, 113}, 1, k2.RL_BLUE)
 
 
 		k2.draw_text("Free 2d camera controls:", {20, 20}, 10, k2.BLACK)
 		k2.draw_text("Free 2d camera controls:", {20, 20}, 10, k2.BLACK)
-		k2.draw_text("- Right/Left to move Offset", {40, 40}, 10, k2.DARKGRAY)
-		k2.draw_text("- Mouse Wheel to Zoom in-out", {40, 60}, 10, k2.DARKGRAY)
-		k2.draw_text("- A / S to Rotate", {40, 80}, 10, k2.DARKGRAY)
-		k2.draw_text("- R to reset Zoom and Rotation", {40, 100}, 10, k2.DARKGRAY)
+		k2.draw_text("- Right/Left to move Offset", {40, 40}, 10, k2.RL_DARKGRAY)
+		k2.draw_text("- Mouse Wheel to Zoom in-out", {40, 60}, 10, k2.RL_DARKGRAY)
+		k2.draw_text("- A / S to Rotate", {40, 80}, 10, k2.RL_DARKGRAY)
+		k2.draw_text("- R to reset Zoom and Rotation", {40, 100}, 10, k2.RL_DARKGRAY)
 
 
 		k2.present()
 		k2.present()
 	}
 	}

+ 11 - 11
examples/raylib_ports/shaders_texture_waves/shaders_texture_waves.odin

@@ -19,13 +19,13 @@ main :: proc() {
     WAVE_SHADER_DATA :: #load("wave.hlsl")
     WAVE_SHADER_DATA :: #load("wave.hlsl")
 
 
     shader := k2.load_shader(string(WAVE_SHADER_DATA))
     shader := k2.load_shader(string(WAVE_SHADER_DATA))
-    seconds_loc := k2.get_shader_constant_location(shader, "seconds")
-    freq_x_loc := k2.get_shader_constant_location(shader, "freqX")
-    freq_y_loc := k2.get_shader_constant_location(shader, "freqY")
-    amp_x_loc := k2.get_shader_constant_location(shader, "ampX")
-    amp_y_loc := k2.get_shader_constant_location(shader, "ampY")
-    speed_x_loc := k2.get_shader_constant_location(shader, "speedX")
-    speed_y_loc := k2.get_shader_constant_location(shader, "speedY")
+    seconds_loc := shader.constant_lookup["seconds"]
+    freq_x_loc := shader.constant_lookup["freqX"]
+    freq_y_loc := shader.constant_lookup["freqY"]
+    amp_x_loc := shader.constant_lookup["ampX"]
+    amp_y_loc := shader.constant_lookup["ampY"]
+    speed_x_loc := shader.constant_lookup["speedX"]
+    speed_y_loc := shader.constant_lookup["speedY"]
 
 
     freq_x := f32(25)
     freq_x := f32(25)
     freq_y := f32(25)
     freq_y := f32(25)
@@ -35,7 +35,7 @@ main :: proc() {
     speed_y := f32(8)
     speed_y := f32(8)
 
 
     screen_size := [2]f32 { f32(k2.get_screen_width()),	f32(k2.get_screen_height()) }
     screen_size := [2]f32 { f32(k2.get_screen_width()),	f32(k2.get_screen_height()) }
-    k2.set_shader_constant(shader, k2.get_shader_constant_location(shader, "size"), screen_size)
+    k2.set_shader_constant(shader, shader.constant_lookup["size"], screen_size)
     k2.set_shader_constant(shader, freq_x_loc, freq_x)
     k2.set_shader_constant(shader, freq_x_loc, freq_x)
     k2.set_shader_constant(shader, freq_y_loc, freq_y)
     k2.set_shader_constant(shader, freq_y_loc, freq_y)
     k2.set_shader_constant(shader, amp_x_loc, amp_x)
     k2.set_shader_constant(shader, amp_x_loc, amp_x)
@@ -47,20 +47,20 @@ main :: proc() {
 
 
     last_frame_time := time.now()
     last_frame_time := time.now()
 
 
-    for !k2.window_should_close() {
+    for !k2.shutdown_wanted() {
     	k2.process_events()
     	k2.process_events()
     	now := time.now()
     	now := time.now()
     	dt := f32(time.duration_seconds(time.diff(last_frame_time, now)))
     	dt := f32(time.duration_seconds(time.diff(last_frame_time, now)))
     	last_frame_time = now
     	last_frame_time = now
     	seconds += dt
     	seconds += dt
 
 
-		k2.set_shader_constant_f32(shader, seconds_loc, seconds)
+		k2.set_shader_constant(shader, seconds_loc, seconds)
 		k2.set_shader(shader)
 		k2.set_shader(shader)
 
 
 		k2.draw_texture(texture, {0, 0})
 		k2.draw_texture(texture, {0, 0})
 		k2.draw_texture(texture, {f32(texture.width), 0})
 		k2.draw_texture(texture, {f32(texture.width), 0})
 
 
-		k2.set_shader(k2.SHADER_NONE)
+		k2.set_shader(nil)
 		k2.present()
 		k2.present()
     }
     }
 
 

+ 4 - 4
examples/snake/snake.odin

@@ -175,12 +175,12 @@ main :: proc() {
 		time_since_food := time.duration_seconds(time.diff(food_eaten_at, time_now))
 		time_since_food := time.duration_seconds(time.diff(food_eaten_at, time_now))
 
 
 		if time_since_food < 0.5 && total_time > 1 {
 		if time_since_food < 0.5 && total_time > 1 {
-			shader.input_overrides[3] = k2.create_vertex_input_override(k2.Vec2{f32(math.cos(total_time*100)*4), f32(math.sin(total_time*120 + 3)*4)})
+			k2.override_shader_input(shader, 3, k2.Vec2{f32(math.cos(total_time*100)*4), f32(math.sin(total_time*120 + 3)*4)})
 		}
 		}
 
 
 		k2.draw_texture(food_sprite, {f32(food_pos.x), f32(food_pos.y)}*CELL_SIZE)
 		k2.draw_texture(food_sprite, {f32(food_pos.x), f32(food_pos.y)}*CELL_SIZE)
 
 
-		shader.input_overrides[3] = {}
+		k2.override_shader_input(shader, 3, nil)
 
 
 		for i in 0..<snake_length {
 		for i in 0..<snake_length {
 			part_sprite := body_sprite
 			part_sprite := body_sprite
@@ -214,13 +214,13 @@ main :: proc() {
 		}
 		}
 
 
 		if game_over {
 		if game_over {
-			k2.draw_text("Game Over!", {4, 4}, 25, k2.RED)
+			k2.draw_text("Game Over!", {4, 4}, 25, k2.RL_RED)
 			k2.draw_text("Press Enter to play again", {4, 30}, 15, k2.BLACK)
 			k2.draw_text("Press Enter to play again", {4, 30}, 15, k2.BLACK)
 		}
 		}
 
 
 		score := snake_length - 3
 		score := snake_length - 3
 		score_str := fmt.tprintf("Score: %v", score)
 		score_str := fmt.tprintf("Score: %v", score)
-		k2.draw_text(score_str, {4, CANVAS_SIZE - 14}, 10, k2.GRAY)
+		k2.draw_text(score_str, {4, CANVAS_SIZE - 14}, 10, k2.RL_GRAY)
 		k2.present()
 		k2.present()
 
 
 		free_all(context.temp_allocator)
 		free_all(context.temp_allocator)

+ 88 - 52
karl2d.doc.odin

@@ -1,10 +1,10 @@
-// This file is purely documentational and never built.
+/* This file is purely documentational. It is generated from the contents of 'karl2d.odin'.*/
 #+build ignore
 #+build ignore
 package karl2d
 package karl2d
 
 
-// --------------------- //
-// KARL2D API PROCEDURES //
-// --------------------- //
+//-----------------------------------------------//
+// SETUP, WINDOW MANAGEMENT AND FRAME MANAGEMENT //
+//-----------------------------------------------//
 
 
 /* Opens a window and initializes some internal state. The internal state will use `allocator` for
 /* Opens a window and initializes some internal state. The internal state will use `allocator` for
 all dynamically allocated memory. The return value can be ignored unless you need to later call
 all dynamically allocated memory. The return value can be ignored unless you need to later call
@@ -33,6 +33,14 @@ present :: proc()
 WARNING: Not calling this will make your program impossible to interact with. */
 WARNING: Not calling this will make your program impossible to interact with. */
 process_events :: proc()
 process_events :: proc()
 
 
+get_screen_width :: proc() -> int
+
+get_screen_height :: proc() -> int
+
+set_window_position :: proc(x: int, y: int)
+
+set_window_size :: proc(width: int, height: int)
+
 /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
 /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
 current batch. Normally, you do not need to do this manually. It is done automatically when these
 current batch. Normally, you do not need to do this manually. It is done automatically when these
 procedures run:
 procedures run:
@@ -44,26 +52,35 @@ TODO: complete this list and motivate why it needs to happen on those procs (or
 docs for those procs). */
 docs for those procs). */
 draw_current_batch :: proc()
 draw_current_batch :: proc()
 
 
-get_screen_width :: proc() -> int
-
-get_screen_height :: proc() -> int
+//-------//
+// INPUT //
+//-------//
 
 
+/* Returns true if a keyboard key went down between the current and the previous frame. Set when
+'process_events' runs (probably once per frame). */
 key_went_down :: proc(key: Keyboard_Key) -> bool
 key_went_down :: proc(key: Keyboard_Key) -> bool
 
 
+/* Returns true if a keyboard key went up (was released) between the current and the previous frame.
+Set when 'process_events' runs (probably once per frame). */
 key_went_up :: proc(key: Keyboard_Key) -> bool
 key_went_up :: proc(key: Keyboard_Key) -> bool
 
 
+/* Returns true if a keyboard is currently being held down. Set when 'process_events' runs (probably
+once per frame). */
 key_is_held :: proc(key: Keyboard_Key) -> bool
 key_is_held :: proc(key: Keyboard_Key) -> bool
 
 
-set_window_position :: proc(x: int, y: int)
+mouse_button_went_down :: proc(button: Mouse_Button) -> bool
 
 
-set_window_size :: proc(width: int, height: int)
+mouse_button_went_up :: proc(button: Mouse_Button) -> bool
 
 
-set_camera :: proc(camera: Maybe(Camera))
+mouse_button_is_held :: proc(button: Mouse_Button) -> bool
 
 
-load_texture_from_file :: proc(filename: string) -> Texture
+get_mouse_wheel_delta :: proc() -> f32
 
 
-destroy_texture :: proc(tex: Texture)
+get_mouse_position :: proc() -> Vec2
 
 
+//---------//
+// DRAWING //
+//---------//
 draw_rect :: proc(r: Rect, c: Color)
 draw_rect :: proc(r: Rect, c: Color)
 
 
 draw_rect_ex :: proc(r: Rect, origin: Vec2, rot: f32, c: Color)
 draw_rect_ex :: proc(r: Rect, origin: Vec2, rot: f32, c: Color)
@@ -80,55 +97,51 @@ draw_texture_rect :: proc(tex: Texture, rect: Rect, pos: Vec2, tint := WHITE)
 
 
 draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rotation: f32, tint := WHITE)
 draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rotation: f32, tint := WHITE)
 
 
-load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader
-
-get_shader_input_default_type :: proc(name: string, type: Shader_Input_Type) -> Shader_Default_Inputs
-
-get_shader_input_format :: proc(name: string, type: Shader_Input_Type) -> Shader_Input_Format
-
-destroy_shader :: proc(shader: Shader)
-
-set_shader :: proc(shader: Maybe(Shader))
-
-maybe_handle_equal :: proc(m1: Maybe($T), m2: Maybe(T)) -> bool
-
-set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: $T)
+draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color)
 
 
-set_shader_constant_mat4 :: proc(shader: Shader, loc: Shader_Constant_Location, val: matrix[4,4]f32)
+//--------------------//
+// TEXTURE MANAGEMENT //
+//--------------------//
+load_texture_from_file :: proc(filename: string) -> Texture
 
 
-set_shader_constant_f32 :: proc(shader: Shader, loc: Shader_Constant_Location, val: f32)
+destroy_texture :: proc(tex: Texture)
 
 
-set_shader_constant_vec2 :: proc(shader: Shader, loc: Shader_Constant_Location, val: Vec2)
+//---------//
+// SHADERS //
+//---------//
+load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader
 
 
-create_vertex_input_override :: proc(val: $T) -> Shader_Input_Value_Override
+destroy_shader :: proc(shader: Shader)
 
 
 get_default_shader :: proc() -> Shader
 get_default_shader :: proc() -> Shader
 
 
-set_scissor_rect :: proc(scissor_rect: Maybe(Rect))
-
-screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2
-
-draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color)
+set_shader :: proc(shader: Maybe(Shader))
 
 
-mouse_button_went_down :: proc(button: Mouse_Button) -> bool
+set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: any)
 
 
-mouse_button_went_up :: proc(button: Mouse_Button) -> bool
+override_shader_input :: proc(shader: Shader, input: int, val: any)
 
 
-mouse_button_is_held :: proc(button: Mouse_Button) -> bool
+shader_input_format_size :: proc(f: Shader_Input_Format) -> int
 
 
-get_mouse_wheel_delta :: proc() -> f32
+//-------------------------------//
+// CAMERA AND COORDINATE SYSTEMS //
+//-------------------------------//
+set_camera :: proc(camera: Maybe(Camera))
 
 
-get_mouse_position :: proc() -> Vec2
+screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2
 
 
-shader_input_format_size :: proc(f: Shader_Input_Format) -> int
+//------//
+// MISC //
+//------//
+set_scissor_rect :: proc(scissor_rect: Maybe(Rect))
 
 
 /* Restore the internal state using the pointer returned by `init`. Useful after reloading the
 /* Restore the internal state using the pointer returned by `init`. Useful after reloading the
 library (for example, when doing code hot reload). */
 library (for example, when doing code hot reload). */
 set_internal_state :: proc(state: ^State)
 set_internal_state :: proc(state: ^State)
 
 
-// ---------------------------- //
-// KARL2D API TYPES & CONSTANTS //
-// ---------------------------- //
+//---------------------//
+// TYPES AND CONSTANTS //
+//---------------------//
 
 
 // A RGBA (Red, Greeen, Blue, Alpha) color. Each channel can have a value between 0 and 255.
 // A RGBA (Red, Greeen, Blue, Alpha) color. Each channel can have a value between 0 and 255.
 Color :: [4]u8
 Color :: [4]u8
@@ -184,8 +197,10 @@ Shader_Constant_Buffer :: struct {
 	cpu_data: []u8,
 	cpu_data: []u8,
 }
 }
 
 
+SHADER_INPUT_VALUE_MAX_SIZE :: 256
+
 Shader_Input_Value_Override :: struct {
 Shader_Input_Value_Override :: struct {
-	val: [256]u8,
+	val: [SHADER_INPUT_VALUE_MAX_SIZE]u8,
 	used: int,
 	used: int,
 }
 }
 
 
@@ -281,16 +296,37 @@ Mouse_Button :: enum {
 	Max = 255,
 	Max = 255,
 }
 }
 
 
-// TODO: These are just copied from raylib, we probably want a list of our own "default colors"
 WHITE :: Color { 255, 255, 255, 255 }
 WHITE :: Color { 255, 255, 255, 255 }
 BLACK :: Color { 0, 0, 0, 255 }
 BLACK :: Color { 0, 0, 0, 255 }
-GRAY :: Color{ 130, 130, 130, 255 }
-RED :: Color { 230, 41, 55, 255 }
-YELLOW :: Color { 253, 249, 0, 255 }
-BLUE :: Color { 0, 121, 241, 255 }
-MAGENTA :: Color { 255, 0, 255, 255 }
-DARKGRAY :: Color{ 80, 80, 80, 255 }
-GREEN :: Color{ 0, 228, 48, 255 }
+BLANK :: Color { 0, 0, 0, 0}
+
+// These are from Raylib. They are here so you can easily port a Raylib program to Karl2D.
+RL_LIGHTGRAY  :: Color { 200, 200, 200, 255 }
+RL_GRAY       :: Color { 130, 130, 130, 255 }
+RL_DARKGRAY   :: Color { 80, 80, 80, 255 }
+RL_YELLOW     :: Color { 253, 249, 0, 255 }
+RL_GOLD       :: Color { 255, 203, 0, 255 }
+RL_ORANGE     :: Color { 255, 161, 0, 255 }
+RL_PINK       :: Color { 255, 109, 194, 255 }
+RL_RED        :: Color { 230, 41, 55, 255 }
+RL_MAROON     :: Color { 190, 33, 55, 255 }
+RL_GREEN      :: Color { 0, 228, 48, 255 }
+RL_LIME       :: Color { 0, 158, 47, 255 }
+RL_DARKGREEN  :: Color { 0, 117, 44, 255 }
+RL_SKYBLUE    :: Color { 102, 191, 255, 255 }
+RL_BLUE       :: Color { 0, 121, 241, 255 }
+RL_DARKBLUE   :: Color { 0, 82, 172, 255 }
+RL_PURPLE     :: Color { 200, 122, 255, 255 }
+RL_VIOLET     :: Color { 135, 60, 190, 255 }
+RL_DARKPURPLE :: Color { 112, 31, 126, 255 }
+RL_BEIGE      :: Color { 211, 176, 131, 255 }
+RL_BROWN      :: Color { 127, 106, 79, 255 }
+RL_DARKBROWN  :: Color { 76, 63, 47, 255 }
+RL_WHITE      :: WHITE
+RL_BLACK      :: BLACK
+RL_BLANK      :: BLANK
+RL_MAGENTA    :: Color { 255, 0, 255, 255 }
+RL_RAYWHITE   :: Color { 245, 245, 245, 255 }
 
 
 // Based on Raylib / GLFW
 // Based on Raylib / GLFW
 Keyboard_Key :: enum {
 Keyboard_Key :: enum {

+ 218 - 167
karl2d.odin

@@ -7,6 +7,7 @@ import "core:math"
 import "core:math/linalg"
 import "core:math/linalg"
 import "core:slice"
 import "core:slice"
 import "core:strings"
 import "core:strings"
+import "core:reflect"
 
 
 import "core:image"
 import "core:image"
 import "core:image/bmp"
 import "core:image/bmp"
@@ -15,9 +16,9 @@ import "core:image/tga"
 
 
 import hm "handle_map"
 import hm "handle_map"
 
 
-// --------------------- //
-// KARL2D API PROCEDURES //
-// --------------------- //
+//-----------------------------------------------//
+// SETUP, WINDOW MANAGEMENT AND FRAME MANAGEMENT //
+//-----------------------------------------------//
 
 
 /* Opens a window and initializes some internal state. The internal state will use `allocator` for
 /* Opens a window and initializes some internal state. The internal state will use `allocator` for
 all dynamically allocated memory. The return value can be ignored unless you need to later call
 all dynamically allocated memory. The return value can be ignored unless you need to later call
@@ -138,6 +139,22 @@ process_events :: proc() {
 	win.clear_events()
 	win.clear_events()
 }
 }
 
 
+get_screen_width :: proc() -> int {
+	return rb.get_swapchain_width()
+}
+
+get_screen_height :: proc() -> int  {
+	return rb.get_swapchain_height()
+}
+
+set_window_position :: proc(x: int, y: int) {
+	win.set_position(x, y)
+}
+
+set_window_size :: proc(width: int, height: int) {
+	panic("Not implemented")
+}
+
 /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
 /* Flushes the current batch. This sends off everything to the GPU that has been queued in the
 current batch. Normally, you do not need to do this manually. It is done automatically when these
 current batch. Normally, you do not need to do this manually. It is done automatically when these
 procedures run:
 procedures run:
@@ -153,76 +170,52 @@ draw_current_batch :: proc() {
 	s.vertex_buffer_cpu_used = 0
 	s.vertex_buffer_cpu_used = 0
 }
 }
 
 
-get_screen_width :: proc() -> int {
-	return rb.get_swapchain_width()
-}
-
-get_screen_height :: proc() -> int  {
-	return rb.get_swapchain_height()
-}
+//-------//
+// INPUT //
+//-------//
 
 
+/* Returns true if a keyboard key went down between the current and the previous frame. Set when
+'process_events' runs (probably once per frame). */
 key_went_down :: proc(key: Keyboard_Key) -> bool {
 key_went_down :: proc(key: Keyboard_Key) -> bool {
 	return s.keys_went_down[key]
 	return s.keys_went_down[key]
 }
 }
 
 
+/* Returns true if a keyboard key went up (was released) between the current and the previous frame.
+Set when 'process_events' runs (probably once per frame). */
 key_went_up :: proc(key: Keyboard_Key) -> bool {
 key_went_up :: proc(key: Keyboard_Key) -> bool {
 	return s.keys_went_up[key]
 	return s.keys_went_up[key]
 }
 }
 
 
+/* Returns true if a keyboard is currently being held down. Set when 'process_events' runs (probably
+once per frame). */
 key_is_held :: proc(key: Keyboard_Key) -> bool {
 key_is_held :: proc(key: Keyboard_Key) -> bool {
 	return s.keys_is_held[key]
 	return s.keys_is_held[key]
 }
 }
 
 
-set_window_position :: proc(x: int, y: int) {
-	win.set_position(x, y)
+mouse_button_went_down :: proc(button: Mouse_Button) -> bool {
+	panic("not implemented")
 }
 }
 
 
-set_window_size :: proc(width: int, height: int) {
-	panic("Not implemented")
+mouse_button_went_up :: proc(button: Mouse_Button) -> bool {
+	panic("not implemented")
 }
 }
 
 
-set_camera :: proc(camera: Maybe(Camera)) {
-	if camera == s.batch_camera {
-		return
-	}
-
-	draw_current_batch()
-	s.batch_camera = camera
-	s.proj_matrix = make_default_projection(s.width, s.height)
-
-	if c, c_ok := camera.?; c_ok {
-		origin_trans := linalg.matrix4_translate(vec3_from_vec2(-c.origin))
-		translate := linalg.matrix4_translate(vec3_from_vec2(c.target))
-		scale := linalg.matrix4_scale(Vec3{1/c.zoom, 1/c.zoom, 1})
-		rot := linalg.matrix4_rotate_f32(c.rotation * math.RAD_PER_DEG, {0, 0, 1})
-		camera_matrix := translate * scale * rot * origin_trans
-		s.view_matrix = linalg.inverse(camera_matrix)
-	} else {
-		s.view_matrix = 1
-	}
+mouse_button_is_held :: proc(button: Mouse_Button) -> bool {
+	panic("not implemented")
 }
 }
 
 
-load_texture_from_file :: proc(filename: string) -> Texture {
-	img, img_err := image.load_from_file(filename, options = {.alpha_add_if_missing}, allocator = context.temp_allocator)
-
-	if img_err != nil {
-		log.errorf("Error loading texture %v: %v", filename, img_err)
-		return {}
-	}
-
-	backend_tex := rb.load_texture(img.pixels.buf[:], img.width, img.height)
-
-	return {
-		handle = backend_tex,
-		width = img.width,
-		height = img.height,
-	}
+get_mouse_wheel_delta :: proc() -> f32 {
+	return s.mouse_wheel_delta
 }
 }
 
 
-destroy_texture :: proc(tex: Texture) {
-	rb.destroy_texture(tex.handle)
+get_mouse_position :: proc() -> Vec2 {
+	return s.mouse_position
 }
 }
 
 
+//---------//
+// DRAWING //
+//---------//
+
 draw_rect :: proc(r: Rect, c: Color) {
 draw_rect :: proc(r: Rect, c: Color) {
 	if s.batch_texture != TEXTURE_NONE && s.batch_texture != s.shape_drawing_texture {
 	if s.batch_texture != TEXTURE_NONE && s.batch_texture != s.shape_drawing_texture {
 		draw_current_batch()
 		draw_current_batch()
@@ -495,6 +488,40 @@ draw_texture_ex :: proc(tex: Texture, src: Rect, dst: Rect, origin: Vec2, rotati
 	batch_vertex(bl, uv5, c)
 	batch_vertex(bl, uv5, c)
 }
 }
 
 
+draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
+	
+}
+
+//--------------------//
+// TEXTURE MANAGEMENT //
+//--------------------//
+
+load_texture_from_file :: proc(filename: string) -> Texture {
+	img, img_err := image.load_from_file(filename, options = {.alpha_add_if_missing}, allocator = context.temp_allocator)
+
+	if img_err != nil {
+		log.errorf("Error loading texture %v: %v", filename, img_err)
+		return {}
+	}
+
+	backend_tex := rb.load_texture(img.pixels.buf[:], img.width, img.height)
+
+	return {
+		handle = backend_tex,
+		width = img.width,
+		height = img.height,
+	}
+}
+
+destroy_texture :: proc(tex: Texture) {
+	rb.destroy_texture(tex.handle)
+}
+
+
+//---------//
+// SHADERS //
+//---------//
+
 load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader {
 load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format = {}) -> Shader {
 	handle, desc := rb.load_shader(shader_source, context.temp_allocator, layout_formats)
 	handle, desc := rb.load_shader(shader_source, context.temp_allocator, layout_formats)
 
 
@@ -556,40 +583,6 @@ load_shader :: proc(shader_source: string, layout_formats: []Shader_Input_Format
 	return shd
 	return shd
 }
 }
 
 
-get_shader_input_default_type :: proc(name: string, type: Shader_Input_Type) -> Shader_Default_Inputs {
-	if name == "POS" && type == .Vec2 {
-		return .Position
-	} else if name == "UV" && type == .Vec2 {
-		return .UV
-	} else if name == "COL" && type == .Vec4 {
-		return .Color
-	}
-
-	return .Unknown
-}
-
-get_shader_input_format :: proc(name: string, type: Shader_Input_Type) -> Shader_Input_Format {
-	default_type := get_shader_input_default_type(name, type)
-
-	if default_type != .Unknown {
-		switch default_type {
-		case .Position: return .RG32_Float
-		case .UV: return .RG32_Float
-		case .Color: return .RGBA8_Norm
-		case .Unknown: unreachable()
-		}
-	}
-
-	switch type {
-	case .F32: return .R32_Float
-	case .Vec2: return .RG32_Float
-	case .Vec3: return .RGB32_Float
-	case .Vec4: return .RGBA32_Float
-	}
-
-	return .Unknown
-}
-
 destroy_shader :: proc(shader: Shader) {
 destroy_shader :: proc(shader: Shader) {
 	rb.destroy_shader(shader.handle)
 	rb.destroy_shader(shader.handle)
 
 
@@ -611,6 +604,10 @@ destroy_shader :: proc(shader: Shader) {
 	delete(shader.input_overrides)
 	delete(shader.input_overrides)
 }
 }
 
 
+get_default_shader :: proc() -> Shader {
+	return s.default_shader
+}
+
 set_shader :: proc(shader: Maybe(Shader)) {
 set_shader :: proc(shader: Maybe(Shader)) {
 	if maybe_handle_equal(shader, s.batch_shader) {
 	if maybe_handle_equal(shader, s.batch_shader) {
 		return
 		return
@@ -620,22 +617,7 @@ set_shader :: proc(shader: Maybe(Shader)) {
 	s.batch_shader = shader
 	s.batch_shader = shader
 }
 }
 
 
-maybe_handle_equal :: proc(m1: Maybe($T), m2: Maybe(T)) -> bool {
-	if m1 == nil && m2 == nil {
-		return true
-	}
-
-	m1v, m1v_ok := m1.?
-	m2v, m2v_ok := m2.?
-
-	if !m1v_ok || !m2v_ok {
-		return false
-	}
-
-	return m1v.handle == m2v.handle
-}
-
-set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: $T) {
+set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: any) {
 	draw_current_batch()
 	draw_current_batch()
 
 
 	if int(loc.buffer_idx) >= len(shd.constant_buffers) {
 	if int(loc.buffer_idx) >= len(shd.constant_buffers) {
@@ -643,72 +625,34 @@ set_shader_constant :: proc(shd: Shader, loc: Shader_Constant_Location, val: $T)
 		return
 		return
 	}
 	}
 
 
+	sz := reflect.size_of_typeid(val.id)
 	b := &shd.constant_buffers[loc.buffer_idx]
 	b := &shd.constant_buffers[loc.buffer_idx]
 
 
-	if int(loc.offset) + size_of(val) > len(b.cpu_data) {
+	if int(loc.offset) + sz > len(b.cpu_data) {
 		log.warnf("Constant buffer idx %v is trying to be written out of bounds by at offset %v with %v bytes", loc.buffer_idx, loc.offset, size_of(val))
 		log.warnf("Constant buffer idx %v is trying to be written out of bounds by at offset %v with %v bytes", loc.buffer_idx, loc.offset, size_of(val))
 		return
 		return
 	}
 	}
 
 
-	dst := (^T)(&b.cpu_data[loc.offset])
-	dst^ = val
+	mem.copy(&b.cpu_data[loc.offset], val.data, sz)
 }
 }
 
 
-set_shader_constant_mat4 :: proc(shader: Shader, loc: Shader_Constant_Location, val: matrix[4,4]f32) {
-	set_shader_constant(shader, loc, val)
-}
-
-set_shader_constant_f32 :: proc(shader: Shader, loc: Shader_Constant_Location, val: f32) {
-	set_shader_constant(shader, loc, val)
-}
-
-set_shader_constant_vec2 :: proc(shader: Shader, loc: Shader_Constant_Location, val: Vec2) {
-	set_shader_constant(shader, loc, val)
-}
-
-create_vertex_input_override :: proc(val: $T) -> Shader_Input_Value_Override {
-	assert(size_of(T) < 256)
-	res: Shader_Input_Value_Override
-	((^T)(raw_data(&res.val)))^ = val
-	res.used = size_of(T)
-	return res
-}
-
-get_default_shader :: proc() -> Shader {
-	return s.default_shader
-}
-
-set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
-	panic("not implemented")
-}
-
-
-screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
-	panic("not implemented")
-}
-
-draw_text :: proc(text: string, pos: Vec2, font_size: f32, color: Color) {
-	
-}
-
-mouse_button_went_down :: proc(button: Mouse_Button) -> bool {
-	panic("not implemented")
-}
+override_shader_input :: proc(shader: Shader, input: int, val: any) {
+	sz := reflect.size_of_typeid(val.id)
+	assert(sz < SHADER_INPUT_VALUE_MAX_SIZE)
+	if input >= len(shader.input_overrides) {
+		log.errorf("Input override out of range. Wanted to override input %v, but shader only has %v inputs", input, len(shader.input_overrides))
+		return
+	}
 
 
-mouse_button_went_up :: proc(button: Mouse_Button) -> bool {
-	panic("not implemented")
-}
+	o := &shader.input_overrides[input]
 
 
-mouse_button_is_held :: proc(button: Mouse_Button) -> bool {
-	panic("not implemented")
-}
+	o.val = {}
 
 
-get_mouse_wheel_delta :: proc() -> f32 {
-	return s.mouse_wheel_delta
-}
+	if sz > 0 {
+		mem.copy(raw_data(&o.val), val.data, sz)
+	}
 
 
-get_mouse_position :: proc() -> Vec2 {
-	return s.mouse_position
+	o.used = sz
 }
 }
 
 
 shader_input_format_size :: proc(f: Shader_Input_Format) -> int {
 shader_input_format_size :: proc(f: Shader_Input_Format) -> int {
@@ -725,6 +669,43 @@ shader_input_format_size :: proc(f: Shader_Input_Format) -> int {
 	return 0
 	return 0
 }
 }
 
 
+//-------------------------------//
+// CAMERA AND COORDINATE SYSTEMS //
+//-------------------------------//
+
+set_camera :: proc(camera: Maybe(Camera)) {
+	if camera == s.batch_camera {
+		return
+	}
+
+	draw_current_batch()
+	s.batch_camera = camera
+	s.proj_matrix = make_default_projection(s.width, s.height)
+
+	if c, c_ok := camera.?; c_ok {
+		origin_trans := linalg.matrix4_translate(vec3_from_vec2(-c.origin))
+		translate := linalg.matrix4_translate(vec3_from_vec2(c.target))
+		scale := linalg.matrix4_scale(Vec3{1/c.zoom, 1/c.zoom, 1})
+		rot := linalg.matrix4_rotate_f32(c.rotation * math.RAD_PER_DEG, {0, 0, 1})
+		camera_matrix := translate * scale * rot * origin_trans
+		s.view_matrix = linalg.inverse(camera_matrix)
+	} else {
+		s.view_matrix = 1
+	}
+}
+
+screen_to_world :: proc(pos: Vec2, camera: Camera) -> Vec2 {
+	panic("not implemented")
+}
+
+//------//
+// MISC //
+//------//
+
+set_scissor_rect :: proc(scissor_rect: Maybe(Rect)) {
+	panic("not implemented")
+}
+
 /* Restore the internal state using the pointer returned by `init`. Useful after reloading the
 /* Restore the internal state using the pointer returned by `init`. Useful after reloading the
 library (for example, when doing code hot reload). */
 library (for example, when doing code hot reload). */
 set_internal_state :: proc(state: ^State) {
 set_internal_state :: proc(state: ^State) {
@@ -735,9 +716,9 @@ set_internal_state :: proc(state: ^State) {
 	win.set_internal_state(s.window_state)
 	win.set_internal_state(s.window_state)
 }
 }
 
 
-// ---------------------------- //
-// KARL2D API TYPES & CONSTANTS //
-// ---------------------------- //
+//---------------------//
+// TYPES AND CONSTANTS //
+//---------------------//
 
 
 // A RGBA (Red, Greeen, Blue, Alpha) color. Each channel can have a value between 0 and 255.
 // A RGBA (Red, Greeen, Blue, Alpha) color. Each channel can have a value between 0 and 255.
 Color :: [4]u8
 Color :: [4]u8
@@ -793,8 +774,10 @@ Shader_Constant_Buffer :: struct {
 	cpu_data: []u8,
 	cpu_data: []u8,
 }
 }
 
 
+SHADER_INPUT_VALUE_MAX_SIZE :: 256
+
 Shader_Input_Value_Override :: struct {
 Shader_Input_Value_Override :: struct {
-	val: [256]u8,
+	val: [SHADER_INPUT_VALUE_MAX_SIZE]u8,
 	used: int,
 	used: int,
 }
 }
 
 
@@ -891,16 +874,38 @@ Mouse_Button :: enum {
 	Max = 255,
 	Max = 255,
 }
 }
 
 
-// TODO: These are just copied from raylib, we probably want a list of our own "default colors"
 WHITE :: Color { 255, 255, 255, 255 }
 WHITE :: Color { 255, 255, 255, 255 }
 BLACK :: Color { 0, 0, 0, 255 }
 BLACK :: Color { 0, 0, 0, 255 }
-GRAY :: Color{ 130, 130, 130, 255 }
-RED :: Color { 230, 41, 55, 255 }
-YELLOW :: Color { 253, 249, 0, 255 }
-BLUE :: Color { 0, 121, 241, 255 }
-MAGENTA :: Color { 255, 0, 255, 255 }
-DARKGRAY :: Color{ 80, 80, 80, 255 }
-GREEN :: Color{ 0, 228, 48, 255 }
+BLANK :: Color { 0, 0, 0, 0}
+
+// These are from Raylib. They are here so you can easily port a Raylib program to Karl2D.
+RL_LIGHTGRAY  :: Color { 200, 200, 200, 255 }
+RL_GRAY       :: Color { 130, 130, 130, 255 }
+RL_DARKGRAY   :: Color { 80, 80, 80, 255 }
+RL_YELLOW     :: Color { 253, 249, 0, 255 }
+RL_GOLD       :: Color { 255, 203, 0, 255 }
+RL_ORANGE     :: Color { 255, 161, 0, 255 }
+RL_PINK       :: Color { 255, 109, 194, 255 }
+RL_RED        :: Color { 230, 41, 55, 255 }
+RL_MAROON     :: Color { 190, 33, 55, 255 }
+RL_GREEN      :: Color { 0, 228, 48, 255 }
+RL_LIME       :: Color { 0, 158, 47, 255 }
+RL_DARKGREEN  :: Color { 0, 117, 44, 255 }
+RL_SKYBLUE    :: Color { 102, 191, 255, 255 }
+RL_BLUE       :: Color { 0, 121, 241, 255 }
+RL_DARKBLUE   :: Color { 0, 82, 172, 255 }
+RL_PURPLE     :: Color { 200, 122, 255, 255 }
+RL_VIOLET     :: Color { 135, 60, 190, 255 }
+RL_DARKPURPLE :: Color { 112, 31, 126, 255 }
+RL_BEIGE      :: Color { 211, 176, 131, 255 }
+RL_BROWN      :: Color { 127, 106, 79, 255 }
+RL_DARKBROWN  :: Color { 76, 63, 47, 255 }
+RL_WHITE      :: WHITE
+RL_BLACK      :: BLACK
+RL_BLANK      :: BLANK
+RL_MAGENTA    :: Color { 255, 0, 255, 255 }
+RL_RAYWHITE   :: Color { 245, 245, 245, 255 }
+
 
 
 // Based on Raylib / GLFW
 // Based on Raylib / GLFW
 Keyboard_Key :: enum {
 Keyboard_Key :: enum {
@@ -1073,8 +1078,54 @@ s: ^State
 win: Window_Interface
 win: Window_Interface
 rb: Rendering_Backend_Interface
 rb: Rendering_Backend_Interface
 
 
+maybe_handle_equal :: proc(m1: Maybe($T), m2: Maybe(T)) -> bool {
+	if m1 == nil && m2 == nil {
+		return true
+	}
 
 
+	m1v, m1v_ok := m1.?
+	m2v, m2v_ok := m2.?
+
+	if !m1v_ok || !m2v_ok {
+		return false
+	}
 
 
+	return m1v.handle == m2v.handle
+}
+
+get_shader_input_default_type :: proc(name: string, type: Shader_Input_Type) -> Shader_Default_Inputs {
+	if name == "POS" && type == .Vec2 {
+		return .Position
+	} else if name == "UV" && type == .Vec2 {
+		return .UV
+	} else if name == "COL" && type == .Vec4 {
+		return .Color
+	}
+
+	return .Unknown
+}
+
+get_shader_input_format :: proc(name: string, type: Shader_Input_Type) -> Shader_Input_Format {
+	default_type := get_shader_input_default_type(name, type)
+
+	if default_type != .Unknown {
+		switch default_type {
+		case .Position: return .RG32_Float
+		case .UV: return .RG32_Float
+		case .Color: return .RGBA8_Norm
+		case .Unknown: unreachable()
+		}
+	}
+
+	switch type {
+	case .F32: return .R32_Float
+	case .Vec2: return .RG32_Float
+	case .Vec3: return .RGB32_Float
+	case .Vec4: return .RGBA32_Float
+	}
+
+	return .Unknown
+}
 
 
 vec3_from_vec2 :: proc(v: Vec2) -> Vec3 {
 vec3_from_vec2 :: proc(v: Vec2) -> Vec3 {
 	return {
 	return {
@@ -1092,4 +1143,4 @@ make_default_projection :: proc(w, h: int) -> matrix[4,4]f32 {
 
 
 _ :: bmp
 _ :: bmp
 _ :: png
 _ :: png
-_ :: tga
+_ :: tga