summaryrefslogtreecommitdiff
path: root/archive/src/systems
diff options
context:
space:
mode:
Diffstat (limited to 'archive/src/systems')
-rw-r--r--archive/src/systems/grid.c84
-rw-r--r--archive/src/systems/grid.h21
-rw-r--r--archive/src/systems/input.c105
-rw-r--r--archive/src/systems/input.h53
-rw-r--r--archive/src/systems/keys.h59
-rw-r--r--archive/src/systems/screenspace.h53
-rw-r--r--archive/src/systems/terrain.c204
-rw-r--r--archive/src/systems/terrain.h72
-rw-r--r--archive/src/systems/text.c1
-rw-r--r--archive/src/systems/text.h53
10 files changed, 705 insertions, 0 deletions
diff --git a/archive/src/systems/grid.c b/archive/src/systems/grid.c
new file mode 100644
index 0000000..e907865
--- /dev/null
+++ b/archive/src/systems/grid.c
@@ -0,0 +1,84 @@
+#include "grid.h"
+#include "file.h"
+#include "log.h"
+#include "maths.h"
+#include "maths_types.h"
+#include "primitives.h"
+#include "ral_common.h"
+#include "ral_impl.h"
+#include "ral_types.h"
+#include "render.h"
+#include "render_types.h"
+#include "shader_layouts.h"
+
+void Grid_Init(Grid_Storage* storage) {
+ INFO("Infinite Grid initialisation");
+ Geometry plane_geo = Geo_CreatePlane(f32x2(1.0, 1.0), 1, 1);
+ Mesh plane_mesh = Mesh_Create(&plane_geo, true);
+ storage->plane_vertices = plane_mesh.vertex_buffer;
+
+ u32 indices[6] = { 5, 4, 3, 2, 1, 0 };
+ storage->plane_indices =
+ GPU_BufferCreate(6 * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, &indices);
+
+ GPU_RenderpassDesc rpass_desc = {
+ .default_framebuffer = true,
+ };
+ storage->renderpass = GPU_Renderpass_Create(rpass_desc);
+
+ arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024);
+
+ Str8 vert_path = str8("assets/shaders/grid.vert");
+ Str8 frag_path = str8("assets/shaders/grid.frag");
+ str8_opt vertex_shader = str8_from_file(&scratch, vert_path);
+ str8_opt fragment_shader = str8_from_file(&scratch, frag_path);
+ if (!vertex_shader.has_value || !fragment_shader.has_value) {
+ ERROR_EXIT("Failed to load shaders from disk")
+ }
+
+ ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL);
+
+ GraphicsPipelineDesc pipeline_desc = {
+ .debug_name = "Infinite grid pipeline",
+ .vertex_desc = static_3d_vertex_description(),
+ .data_layouts = { camera_data },
+ .data_layouts_count = 1,
+ .vs = {
+ .debug_name = "Grid vertex shader",
+ .filepath = vert_path,
+ .code = vertex_shader.contents,
+ },
+ .fs = {
+ .debug_name = "Grid fragment shader",
+ .filepath = frag_path,
+ .code = fragment_shader.contents,
+ },
+ .wireframe = false,
+ };
+ storage->pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->renderpass);
+}
+
+void Grid_Draw() {
+ Grid_Storage* grid = Render_GetGridStorage();
+ Grid_Execute(grid);
+}
+
+void Grid_Execute(Grid_Storage* storage) {
+ RenderScene* scene = Render_GetScene();
+ GPU_CmdEncoder* enc = GPU_GetDefaultEncoder();
+ GPU_CmdEncoder_BeginRender(enc, storage->renderpass);
+ GPU_EncodeBindPipeline(enc, storage->pipeline);
+ Mat4 view, proj;
+ u32x2 dimensions = GPU_Swapchain_GetDimensions();
+ Camera camera = scene->camera;
+ Camera_ViewProj(&camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj);
+ Binding_Camera camera_data = { .view = view,
+ .projection = proj,
+ .viewPos = vec4(camera.position.x, camera.position.y,
+ camera.position.z, 1.0) };
+ GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data));
+ GPU_EncodeSetVertexBuffer(enc, storage->plane_vertices);
+ GPU_EncodeSetIndexBuffer(enc, storage->plane_indices);
+ GPU_EncodeDrawIndexedTris(enc, 6);
+ GPU_CmdEncoder_EndRender(enc);
+}
diff --git a/archive/src/systems/grid.h b/archive/src/systems/grid.h
new file mode 100644
index 0000000..d8bc567
--- /dev/null
+++ b/archive/src/systems/grid.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "ral_impl.h"
+#include "ral_types.h"
+
+typedef struct Grid_Storage {
+ GPU_Renderpass* renderpass;
+ GPU_Pipeline* pipeline;
+ BufferHandle plane_vertices;
+ BufferHandle plane_indices;
+} Grid_Storage;
+
+// --- Public API
+PUB void Grid_Init(Grid_Storage* storage);
+// void Grid_Shutdown(Grid_Storage* storage);
+PUB void Grid_Draw();
+
+// --- Internal
+void Grid_Execute(Grid_Storage* storage);
+// typedef struct GridUniforms {} GridUniforms;
+// ShaderDataLayout GridUniforms_GetLayout(void* data); \ No newline at end of file
diff --git a/archive/src/systems/input.c b/archive/src/systems/input.c
new file mode 100644
index 0000000..c3af96a
--- /dev/null
+++ b/archive/src/systems/input.c
@@ -0,0 +1,105 @@
+#include "input.h"
+
+#include <assert.h>
+#include <glfw3.h>
+#include <string.h>
+
+#include "keys.h"
+#include "log.h"
+
+static Input_State* g_input; // Use a global to simplify caller code
+
+bool Input_Init(Input_State* input, GLFWwindow* window) {
+ INFO("Input init");
+ memset(input, 0, sizeof(Input_State));
+
+ input->window = window;
+ // Set everything to false. Could just set memory to zero but where's the fun in that
+ for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) {
+ input->depressed_keys[i] = false;
+ input->just_pressed_keys[i] = false;
+ input->just_released_keys[i] = false;
+ }
+
+ g_input = input;
+
+ assert(input->mouse.x_delta == 0);
+ assert(input->mouse.y_delta == 0);
+
+ INFO("Finish input init");
+ return true;
+}
+
+void Input_Shutdown(Input_State* input) {}
+
+void Input_Update(Input_State* input) {
+ glfwPollEvents();
+ // --- update keyboard input
+
+ // if we go from un-pressed -> pressed, set as "just pressed"
+ // if we go from pressed -> un-pressed, set as "just released"
+ for (int i = KEYCODE_SPACE; i < KEYCODE_MAX; i++) {
+ bool new_state = false;
+ if (glfwGetKey(input->window, i) == GLFW_PRESS) {
+ new_state = true;
+ } else {
+ new_state = false;
+ }
+ if (!input->depressed_keys[i] == false && new_state) {
+ input->just_pressed_keys[i] = true;
+ } else {
+ input->just_pressed_keys[i] = false;
+ }
+
+ if (input->depressed_keys[i] && !new_state) {
+ input->just_released_keys[i] = true;
+ } else {
+ input->just_released_keys[i] = false;
+ }
+
+ input->depressed_keys[i] = new_state;
+ }
+
+ // --- update mouse input
+
+ // cursor position
+ f64 current_x, current_y;
+ glfwGetCursorPos(input->window, &current_x, &current_y);
+ i32 quantised_cur_x = (i32)current_x;
+ i32 quantised_cur_y = (i32)current_y;
+
+ mouse_state new_mouse_state = { 0 };
+ new_mouse_state.x = quantised_cur_x;
+ new_mouse_state.y = quantised_cur_y;
+ new_mouse_state.x_delta = quantised_cur_x - input->mouse.x;
+ new_mouse_state.y_delta = quantised_cur_y - input->mouse.y;
+
+ // buttons
+ int left_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_LEFT);
+ int right_state = glfwGetMouseButton(input->window, GLFW_MOUSE_BUTTON_RIGHT);
+
+ for (int i = 0; i < 3; i++) {
+ new_mouse_state.prev_pressed_states[i] = input->mouse.cur_pressed_states[i];
+ }
+ new_mouse_state.cur_pressed_states[MOUSEBTN_LEFT] = left_state == GLFW_PRESS;
+ new_mouse_state.cur_pressed_states[MOUSEBTN_RIGHT] = right_state == GLFW_PRESS;
+
+ // this was dumb! need to also check button state changes lol
+ // if (new_mouse_state.x != input->mouse.x || new_mouse_state.y != input->mouse.y)
+ // TRACE("Mouse (x,y) = (%d,%d)", input->mouse.x, input->mouse.y);
+
+ input->mouse = new_mouse_state;
+}
+
+bool key_is_pressed(keycode key) { return g_input->depressed_keys[key]; }
+
+bool key_just_pressed(keycode key) { return g_input->just_pressed_keys[key]; }
+
+bool key_just_released(keycode key) { return g_input->just_released_keys[key]; }
+
+bool MouseBtn_Held(MouseBtn btn) {
+ assert(btn < 3);
+ return g_input->mouse.prev_pressed_states[btn] && g_input->mouse.cur_pressed_states[btn];
+}
+
+mouse_state Input_GetMouseState() { return g_input->mouse; } \ No newline at end of file
diff --git a/archive/src/systems/input.h b/archive/src/systems/input.h
new file mode 100644
index 0000000..c3b2500
--- /dev/null
+++ b/archive/src/systems/input.h
@@ -0,0 +1,53 @@
+/**
+ * @brief
+ */
+#pragma once
+
+#include "defines.h"
+#include "keys.h"
+
+struct GLFWWindow;
+
+typedef enum MouseBtn {
+ MOUSEBTN_LEFT = 0,
+ MOUSEBTN_RIGHT = 1,
+ MOUSEBTN_MIDDLE = 2,
+} MouseBtn;
+
+typedef struct mouse_state {
+ i32 x;
+ i32 y;
+ i32 x_delta;
+ i32 y_delta;
+ bool prev_pressed_states[3];
+ bool cur_pressed_states[3];
+} mouse_state;
+
+typedef struct Input_State {
+ struct GLFWwindow* window;
+ mouse_state mouse;
+ bool depressed_keys[KEYCODE_MAX];
+ bool just_pressed_keys[KEYCODE_MAX];
+ bool just_released_keys[KEYCODE_MAX];
+} Input_State;
+
+/** @brief `key` is currently being held down */
+PUB bool key_is_pressed(keycode key);
+
+/** @brief `key` was just pressed */
+PUB bool key_just_pressed(keycode key);
+
+/** @brief `key` was just released */
+PUB bool key_just_released(keycode key);
+
+// TODO: right btn as well
+PUB bool MouseBtn_Held(MouseBtn btn);
+
+// --- Lifecycle
+
+PUB bool Input_Init(Input_State* input, struct GLFWwindow* window);
+PUB void Input_Shutdown(Input_State* input);
+
+PUB void Input_Update(Input_State* state); // must be run once per main loop
+
+PUB mouse_state Input_GetMouseState(); \ No newline at end of file
diff --git a/archive/src/systems/keys.h b/archive/src/systems/keys.h
new file mode 100644
index 0000000..6082a59
--- /dev/null
+++ b/archive/src/systems/keys.h
@@ -0,0 +1,59 @@
+#pragma once
+
+typedef enum keycode {
+ // TODO: add all keycodes
+ KEYCODE_SPACE = 32,
+ KEYCODE_APOSTROPHE = 39,
+ KEYCODE_COMMA = 44,
+ KEYCODE_MINUS = 45,
+ KEYCODE_PERIOD = 46,
+ KEYCODE_SLASH = 47,
+ KEYCODE_0 = 48,
+ KEYCODE_1 = 49,
+ KEYCODE_2 = 50,
+ KEYCODE_3 = 51,
+ KEYCODE_4 = 52,
+ KEYCODE_5 = 53,
+ KEYCODE_6 = 54,
+ KEYCODE_7 = 55,
+ KEYCODE_8 = 56,
+ KEYCODE_9 = 57,
+ KEYCODE_SEMICOLON = 59,
+ KEYCODE_EQUAL = 61,
+ KEYCODE_A = 65,
+ KEYCODE_B = 66,
+ KEYCODE_C = 67,
+ KEYCODE_D = 68,
+ KEYCODE_E = 69,
+ KEYCODE_F = 70,
+ KEYCODE_G = 71,
+ KEYCODE_H = 72,
+ KEYCODE_I = 73,
+ KEYCODE_J = 74,
+ KEYCODE_K = 75,
+ KEYCODE_L = 76,
+ KEYCODE_M = 77,
+ KEYCODE_N = 78,
+ KEYCODE_O = 79,
+ KEYCODE_P = 80,
+ KEYCODE_Q = 81,
+ KEYCODE_R = 82,
+ KEYCODE_S = 83,
+ KEYCODE_T = 84,
+ KEYCODE_U = 85,
+ KEYCODE_V = 86,
+ KEYCODE_W = 87,
+ KEYCODE_X = 88,
+ KEYCODE_Y = 89,
+ KEYCODE_Z = 90,
+
+ KEYCODE_ESCAPE = 256,
+ KEYCODE_ENTER = 257,
+ KEYCODE_TAB = 258,
+ KEYCODE_BACKSPACE = 259,
+ KEYCODE_KEY_RIGHT = 262,
+ KEYCODE_KEY_LEFT = 263,
+ KEYCODE_KEY_DOWN = 264,
+ KEYCODE_KEY_UP = 265,
+ KEYCODE_MAX = 348
+} keycode;
diff --git a/archive/src/systems/screenspace.h b/archive/src/systems/screenspace.h
new file mode 100644
index 0000000..5f0c579
--- /dev/null
+++ b/archive/src/systems/screenspace.h
@@ -0,0 +1,53 @@
+/**
+ * @brief Drawing shapes for UI or other reasons in screenspace
+ */
+#pragma once
+
+#include "colours.h"
+#include "darray.h"
+#include "defines.h"
+#include "render_types.h"
+
+/** A draw_cmd packet for rendering a rectangle */
+struct draw_rect {
+ i32 x, y; // signed ints so we can draw things offscreen (e.g. a window half inside the viewport)
+ u32 width, height;
+ rgba colour;
+ // TODO: border colour, gradients
+};
+
+/** A draw_cmd packet for rendering a circle */
+struct draw_circle {
+ i32 x, y;
+ f32 radius;
+ rgba colour;
+};
+
+/** @brief Tagged union that represents a UI shape to be drawn. */
+typedef struct draw_cmd {
+ enum { DRAW_RECT, CIRCLE } draw_cmd_type;
+ union {
+ struct draw_rect rect;
+ struct draw_circle circle;
+ };
+} draw_cmd;
+
+KITC_DECL_TYPED_ARRAY(draw_cmd)
+
+typedef struct screenspace_state {
+ u32 rect_vbo;
+ u32 rect_vao;
+ // shader rect_shader;
+ draw_cmd_darray* draw_cmd_buf;
+} screenspace_state;
+
+// --- Lifecycle
+bool screenspace_2d_init(screenspace_state* state);
+void screenspace_2d_shutdown(screenspace_state* state);
+/** Drains the draw_cmd buffer and emits draw calls to render each one */
+void screenspace_2d_render(screenspace_state* state);
+
+struct core;
+
+/** @brief Draw a rectangle to the screen. (0,0) is the bottom-left */
+void draw_rectangle(struct core* core, rgba colour, i32 x, i32 y, u32 width, u32 height); \ No newline at end of file
diff --git a/archive/src/systems/terrain.c b/archive/src/systems/terrain.c
new file mode 100644
index 0000000..069000e
--- /dev/null
+++ b/archive/src/systems/terrain.c
@@ -0,0 +1,204 @@
+/**
+ * @brief
+ */
+#include "terrain.h"
+#include <assert.h>
+#include "file.h"
+#include "glad/glad.h"
+#include "log.h"
+#include "maths.h"
+#include "mem.h"
+#include "ral_common.h"
+#include "ral_impl.h"
+#include "ral_types.h"
+#include "render.h"
+#include "shader_layouts.h"
+#include "str.h"
+
+#define TERRAIN_GRID_U 505
+#define TERRAIN_GRID_V 505
+
+bool Terrain_Init(Terrain_Storage* storage) {
+ storage->grid_dimensions = u32x2(TERRAIN_GRID_U, TERRAIN_GRID_V);
+ storage->hmap_loaded = false;
+
+ GPU_RenderpassDesc rpass_desc = {
+ .default_framebuffer = true,
+ };
+ storage->hmap_renderpass = GPU_Renderpass_Create(rpass_desc);
+
+ arena scratch = arena_create(malloc(1024 * 1024), 1024 * 1024);
+
+ Str8 vert_path = str8("assets/shaders/terrain.vert");
+ Str8 frag_path = str8("assets/shaders/terrain.frag");
+ str8_opt vertex_shader = str8_from_file(&scratch, vert_path);
+ str8_opt fragment_shader = str8_from_file(&scratch, frag_path);
+ if (!vertex_shader.has_value || !fragment_shader.has_value) {
+ ERROR_EXIT("Failed to load shaders from disk")
+ }
+
+ ShaderDataLayout camera_data = Binding_Camera_GetLayout(NULL);
+ ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(NULL);
+
+ GraphicsPipelineDesc pipeline_desc = {
+ .debug_name = "terrain rendering pipeline",
+ .vertex_desc = static_3d_vertex_description(),
+ .data_layouts = { camera_data, terrain_data },
+ .data_layouts_count = 2,
+ .vs = {
+ .debug_name = "terrain vertex shader",
+ .filepath = vert_path,
+ .code = vertex_shader.contents,
+ },
+ .fs = {
+ .debug_name = "terrain fragment shader",
+ .filepath = frag_path,
+ .code = fragment_shader.contents,
+ },
+ .wireframe = false,
+ };
+ storage->hmap_pipeline = GPU_GraphicsPipeline_Create(pipeline_desc, storage->hmap_renderpass);
+
+ storage->texture = TextureLoadFromFile("assets/demo/textures/grass2.png");
+
+ return true;
+}
+
+void Terrain_Shutdown(Terrain_Storage* storage) {}
+
+void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale,
+ bool free_on_upload) {
+ // If there's a current one we will delete it and reallocate buffers
+ if (storage->hmap_loaded) {
+ GPU_BufferDestroy(storage->vertex_buffer);
+ GPU_BufferDestroy(storage->index_buffer);
+ }
+
+ u32 width = hmap.pixel_dimensions.x;
+ u32 height = hmap.pixel_dimensions.y;
+ storage->grid_scale = grid_scale;
+
+ size_t num_vertices = storage->grid_dimensions.x * storage->grid_dimensions.y;
+ storage->num_vertices = num_vertices;
+
+ Vertex_darray* vertices = Vertex_darray_new(num_vertices);
+ u32 index = 0;
+ for (u32 i = 0; i < storage->grid_dimensions.x; i++) {
+ for (u32 j = 0; j < storage->grid_dimensions.y; j++) {
+ size_t position = j * storage->grid_dimensions.x + i;
+ u8* bytes = hmap.image_data;
+ u8 channel = bytes[position];
+ float value = (float)channel / 255.0;
+ // printf("(%d, %d) %d : %f \n", i, j, channel, value);
+
+ assert(index < num_vertices);
+ f32 height = Heightmap_HeightXZ(&hmap, i, j);
+ Vec3 v_pos = vec3_create(i * grid_scale, height, j * grid_scale);
+ Vec3 v_normal = VEC3_Y;
+ float tiling_factor = 505.0f;
+ Vec2 v_uv = vec2((f32)i / width * tiling_factor, (f32)j / height * tiling_factor);
+ Vertex v = { .static_3d = { .position = v_pos, .normal = v_normal, .tex_coords = v_uv } };
+ Vertex_darray_push(vertices, v);
+ index++;
+ }
+ }
+ BufferHandle vertices_handle = GPU_BufferCreate(num_vertices * sizeof(Vertex), BUFFER_VERTEX,
+ BUFFER_FLAG_GPU, vertices->data);
+ storage->vertex_buffer = vertices_handle;
+
+ u32 quad_count = (width - 1) * (height - 1);
+ u32 indices_count = quad_count * 6;
+ storage->indices_count = indices_count;
+ u32_darray* indices = u32_darray_new(indices_count);
+ for (u32 i = 0; i < (width - 1); i++) { // row
+ for (u32 j = 0; j < (height - 1); j++) { // col
+ u32 bot_left = i * width + j;
+ u32 top_left = (i + 1) * width + j;
+ u32 top_right = (i + 1) * width + (j + 1);
+ u32 bot_right = i * width + j + 1;
+
+ // top left tri
+ u32_darray_push(indices, top_right);
+ u32_darray_push(indices, top_left);
+ u32_darray_push(indices, bot_left);
+
+ // bottom right tri
+ u32_darray_push(indices, bot_right);
+ u32_darray_push(indices, top_right);
+ u32_darray_push(indices, bot_left);
+ }
+ }
+
+ BufferHandle indices_handle =
+ GPU_BufferCreate(indices_count * sizeof(u32), BUFFER_INDEX, BUFFER_FLAG_GPU, indices->data);
+ storage->index_buffer = indices_handle;
+}
+
+Heightmap Heightmap_FromImage(Str8 filepath) {
+ size_t max_size = MB(16);
+ arena arena = arena_create(malloc(max_size), max_size);
+ // str8_opt maybe_file = str8_from_file(&arena, filepath);
+ // assert(maybe_file.has_value);
+
+ TextureData hmap_tex = TextureDataLoad(Str8_to_cstr(&arena, filepath), false);
+
+ // arena_free_storage(&arena);
+
+ return (Heightmap){
+ .pixel_dimensions = hmap_tex.description.extents,
+ .filepath = filepath,
+ .image_data = hmap_tex.image_data,
+ .num_channels = hmap_tex.description.num_channels,
+ .is_uploaded = false,
+ };
+}
+
+void Terrain_Draw(Terrain_Storage* storage) {
+ GPU_CmdEncoder* enc = GPU_GetDefaultEncoder();
+ GPU_EncodeBindPipeline(enc, storage->hmap_pipeline);
+ RenderScene* scene = Render_GetScene();
+
+ Mat4 view, proj;
+ u32x2 dimensions = GPU_Swapchain_GetDimensions();
+ Camera_ViewProj(&scene->camera, (f32)dimensions.x, (f32)dimensions.y, &view, &proj);
+ Binding_Camera camera_data = { .view = view,
+ .projection = proj,
+ .viewPos = vec4(scene->camera.position.x, scene->camera.position.y,
+ scene->camera.position.z, 1.0) };
+ GPU_EncodeBindShaderData(enc, 0, Binding_Camera_GetLayout(&camera_data));
+
+ TerrainUniforms uniforms = { .tex_slot_1 = storage->texture };
+ ShaderDataLayout terrain_data = TerrainUniforms_GetLayout(&uniforms);
+ GPU_EncodeBindShaderData(enc, 1, terrain_data);
+
+ GPU_EncodeSetVertexBuffer(enc, storage->vertex_buffer);
+ GPU_EncodeSetIndexBuffer(enc, storage->index_buffer);
+
+ GPU_EncodeDrawIndexedTris(enc, storage->indices_count);
+ // glDrawArrays(GL_POINTS, 0, storage->num_vertices);
+}
+
+f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z) {
+ // its single channel so only one byte per pixel
+ size_t position = x * hmap->pixel_dimensions.x + z;
+ u8* bytes = hmap->image_data;
+ u8 channel = bytes[position];
+ float value = (float)channel / 2.0; /// 255.0;
+ return value;
+}
+
+ShaderDataLayout TerrainUniforms_GetLayout(void* data) {
+ TerrainUniforms* d = data;
+ bool has_data = data != NULL;
+
+ ShaderBinding b1 = {
+ .label = "TextureSlot1",
+ .kind = BINDING_TEXTURE,
+ .vis = VISIBILITY_FRAGMENT,
+ };
+
+ if (has_data) {
+ b1.data.texture.handle = d->tex_slot_1;
+ }
+ return (ShaderDataLayout){ .bindings = { b1 }, .binding_count = 1 };
+}
diff --git a/archive/src/systems/terrain.h b/archive/src/systems/terrain.h
new file mode 100644
index 0000000..5a96132
--- /dev/null
+++ b/archive/src/systems/terrain.h
@@ -0,0 +1,72 @@
+/**
+ * @file terrain.h
+ * @brief
+ */
+
+#pragma once
+
+/*
+Future:
+ - Chunked terrain
+ - Dynamic LOD
+*/
+
+#include "defines.h"
+#include "maths_types.h"
+#include "ral_types.h"
+#include "render.h"
+#include "str.h"
+
+typedef struct Heightmap {
+ Str8 filepath;
+ u32x2 pixel_dimensions;
+ void* image_data;
+ u32 num_channels;
+ bool is_uploaded;
+} Heightmap;
+
+typedef struct Terrain_Storage {
+ // arena terrain_allocator;
+ u32x2 grid_dimensions;
+ f32 grid_scale;
+ u32 num_vertices;
+ Heightmap heightmap; // NULL = no heightmap
+ GPU_Renderpass* hmap_renderpass;
+ GPU_Pipeline* hmap_pipeline;
+ TextureHandle texture;
+
+ bool hmap_loaded;
+ BufferHandle vertex_buffer;
+ BufferHandle index_buffer;
+ u32 indices_count;
+} Terrain_Storage;
+
+// --- Public API
+PUB bool Terrain_Init(Terrain_Storage* storage);
+PUB void Terrain_Shutdown(Terrain_Storage* storage);
+PUB void Terrain_Draw(
+ Terrain_Storage* storage); // NOTE: For now it renders directly to main framebuffer
+
+/** @brief Sets the active heightmap to be rendered and collided against. */
+PUB void Terrain_LoadHeightmap(Terrain_Storage* storage, Heightmap hmap, f32 grid_scale,
+ bool free_on_upload);
+PUB Heightmap Heightmap_FromImage(Str8 filepath);
+PUB Heightmap Heightmap_FromPerlin(/* TODO: perlin noise generation parameters */);
+
+PUB bool Terrain_IsActive(); // checks whether we have a loaded heightmap and it's being rendered
+
+/** @brief Get the height (the Y component) for a vertex at a particular coordinate in the heightmap
+ */
+PUB f32 Heightmap_HeightXZ(const Heightmap* hmap, u32 x, u32 z);
+
+/** @brief Calculate the normal vector of a vertex at a particular coordinate in the heightmap */
+PUB Vec3 Heightmap_NormalXZ(const Heightmap* hmap, f32 x, f32 z);
+
+// /** @brief Generate the `geometry_data` for a heightmap ready to be uploaded to the GPU */
+// Geometry geo_heightmap(arena* a, Heightmap heightmap);
+
+typedef struct TerrainUniforms {
+ TextureHandle tex_slot_1;
+} TerrainUniforms;
+
+ShaderDataLayout TerrainUniforms_GetLayout(void* data); \ No newline at end of file
diff --git a/archive/src/systems/text.c b/archive/src/systems/text.c
new file mode 100644
index 0000000..2bb5399
--- /dev/null
+++ b/archive/src/systems/text.c
@@ -0,0 +1 @@
+// TODO: Port from previous repo \ No newline at end of file
diff --git a/archive/src/systems/text.h b/archive/src/systems/text.h
new file mode 100644
index 0000000..983ffd6
--- /dev/null
+++ b/archive/src/systems/text.h
@@ -0,0 +1,53 @@
+/**
+ * @brief
+ */
+#pragma once
+
+#include <stb_truetype.h>
+
+#include "darray.h"
+#include "defines.h"
+#include "ral.h"
+#include "render_types.h"
+
+// struct core;
+
+// /** @brief internal font struct */
+// typedef struct font {
+// const char *name;
+// stbtt_fontinfo stbtt_font;
+// stbtt_bakedchar c_data[96];
+// texture_handle bitmap_tex;
+// } font;
+
+// typedef struct draw_text_packet {
+// char *contents;
+// f32 x;
+// f32 y;
+// } draw_text_packet;
+
+// KITC_DECL_TYPED_ARRAY(draw_text_packet)
+
+// typedef struct text_system_state {
+// font default_font;
+// shader_handle glyph_shader;
+// u32 glyph_vbo;
+// u32 glyph_vao;
+// draw_text_packet_darray *draw_cmd_buf;
+// // TODO: fonts array or hashtable
+// } text_system_state;
+
+// void text_system_render(text_system_state *text);
+
+// // --- Lifecycle functions
+// bool text_system_init(text_system_state *text);
+// void text_system_shutdown(text_system_state *text);
+
+// // --- Drawing
+
+// /**
+// * @brief immediate mode draw text.
+// * @note immediately emits draw calls causing a shader program switch if you weren't previously
+// drawing text in the current frame.
+// */
+// void draw_text(struct core *core, f32 x, f32 y, char *contents);