summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpryazha <pryadeiniv@mail.ru>2025-06-15 16:07:54 +0500
committerpryazha <pryadeiniv@mail.ru>2025-06-15 16:07:54 +0500
commitf30a4eba44c77d5c743fe9308dc697a3225e8dd8 (patch)
treec171da2e8d1127409e2ffe9e56e2e027bac48e28
parent92a8eb610f40c9770569ca63ca1bd705a6d3497d (diff)
i don't even know
-rw-r--r--audio.h68
-rw-r--r--camera.h69
-rw-r--r--ctx.h39
-rw-r--r--draw.h92
-rw-r--r--gui.h67
-rw-r--r--input.h46
-rw-r--r--model.h246
-rw-r--r--phys.h95
-rw-r--r--prge.h51
-rw-r--r--prge_audio.c75
-rw-r--r--prge_audio.h6
-rw-r--r--prge_camera.c99
-rw-r--r--prge_camera.h7
-rw-r--r--prge_draw.c78
-rw-r--r--prge_draw.h8
-rw-r--r--prge_gui.c60
-rw-r--r--prge_gui.h6
-rw-r--r--prge_input.c51
-rw-r--r--prge_input.h5
-rw-r--r--prge_model.c187
-rw-r--r--prge_model.h11
-rw-r--r--prge_shader.c93
-rw-r--r--prge_shader.h12
-rw-r--r--prge_texture.c59
-rw-r--r--prge_texture.h1
-rw-r--r--prge_types.h166
-rw-r--r--prge_window.c10
-rw-r--r--prge_window.h4
-rw-r--r--shader.h105
-rw-r--r--texture.h55
-rw-r--r--types.h231
31 files changed, 1124 insertions, 978 deletions
diff --git a/audio.h b/audio.h
new file mode 100644
index 0000000..96dd11e
--- /dev/null
+++ b/audio.h
@@ -0,0 +1,68 @@
+extern i32 load_vorbis(arena_t *arena, sound_t *sounds, const char *filename);
+extern void play_sound(sound_t *sounds, sound_queue_t *queue, sound_queue_node_t *nodes, i32 id);
+
+i32 find_sound(sound_t *sounds, const char *name)
+{
+ for (i32 i = 0; i < MAX_SOUNDS_LOADED; i++) {
+ sound_t *sound = sounds+i;
+ if (streq(sound->name, name))
+ return i;
+ }
+ return -1;
+}
+
+i32 load_sound(sound_t *sounds, sound_t new_sound)
+{
+ assert(sounds);
+
+ i32 i;
+ sound_t *sound;
+ for (i = 0; i < MAX_SOUNDS_LOADED; ++i) {
+ sound = sounds+i;
+ if (!sound->data)
+ break;
+ }
+
+ if (i == MAX_SOUNDS_LOADED) {
+ printf("warning: max sounds loaded\n");
+ return -1;
+ }
+
+ *sound = new_sound;
+
+ return i;
+}
+
+i32 enqueue_sound(sound_queue_t *queue, sound_queue_node_t *nodes, sound_t *sound)
+{
+ if (queue->count == MAX_SOUNDS_PLAYING)
+ return 0;
+
+ sound_queue_node_t *node;
+ for (i32 i = 0; i < MAX_SOUNDS_PLAYING; ++i) {
+ node = nodes+i;
+ if (!node->sound)
+ break;
+ }
+
+ node->sound = sound;
+
+ dllpushfront(queue->first, queue->last, node);
+
+ queue->count++;
+
+ return 1;
+}
+
+sound_t *dequeue_sound(sound_queue_t *queue)
+{
+ if (queue->count == 0)
+ return 0;
+
+ sound_t *sound = queue->first->sound;
+ queue->first->sound = 0;
+ dllremove(queue->first, queue->last, queue->first);
+ queue->count--;
+
+ return sound;
+}
diff --git a/camera.h b/camera.h
new file mode 100644
index 0000000..0dad35d
--- /dev/null
+++ b/camera.h
@@ -0,0 +1,69 @@
+mat4 camera_get_view_mat(camera_t camera)
+{
+ mat4 view = mat4_make_transl(v3_inv(camera.position));
+ view = mat4_rotate(view, camera.angles);
+ return view;
+}
+
+void camera_get_vecs(camera_t camera, v3 *left, v3 *up, v3 *front)
+{
+ f32 angle = deg2rad(camera.angles.x);
+ f32 cp = fcos(angle);
+ f32 sp = fsin(angle);
+
+ angle = deg2rad(camera.angles.y);
+ f32 cy = fcos(angle);
+ f32 sy = fsin(angle);
+
+ angle = deg2rad(camera.angles.z);
+ f32 cr = fcos(angle);
+ f32 sr = fsin(angle);
+
+ *left = (v3){cy*cr, -cy*sr, sy};
+ *up = (v3){sp*sy*cr+cp*sr, -sp*sy*sr+cp*cr, -sp*cy};
+ *front = (v3){-cp*sy*cr+sp*sr, cp*sy*sr+sp*cr, cp*cy};
+}
+
+mat4 camera_lookat(camera_t camera, v3 target, v3 world_up)
+{
+ v3 front = v3_norm(v3_sub(camera.position, target));
+ v3 right = v3_norm(v3_cross(world_up, front));
+ v3 up = v3_cross(front, right);
+
+ mat4 translate = mat4_make_transl(v3_inv(camera.position));
+ mat4 rotate = mat4_transp(mat4_make_rotate(right, up, front));
+ mat4 result = mat4_mul(rotate, translate);
+
+ return result;
+}
+
+mat4 ortho(f32 l, f32 r, f32 b, f32 t, f32 n, f32 f)
+{
+ mat4 ortho = MAT4_IDENTITY;
+ ortho.c0.x = 2.0f/(r-l);
+ ortho.c1.y = 2.0f/(t-b);
+ ortho.c2.z = -2.0f/(f-n);
+ ortho.c3.x = -(r+l)/(r-l);
+ ortho.c3.y = -(t+b)/(t-b);
+ ortho.c3.z = -(f+n)/(f-n);
+ return ortho;
+}
+
+mat4 perspective(camera_t camera, f32 aspect_ratio)
+{
+ f32 n = camera.near;
+ f32 f = camera.far;
+
+ f32 r = n*ftan(deg2rad(camera.fov/2.0f));
+ f32 t = r/aspect_ratio;
+
+ mat4 perspective = MAT4_IDENTITY;
+ perspective.c0.x = n/r;
+ perspective.c1.y = n/t;
+ perspective.c2.z = -(f+n)/(f-n);
+ perspective.c2.w = -1.0f;
+ perspective.c3.z = (-2.0f*f*n)/(f-n);
+ perspective.c3.w = 0.0f;
+
+ return perspective;
+}
diff --git a/ctx.h b/ctx.h
new file mode 100644
index 0000000..3bc93f9
--- /dev/null
+++ b/ctx.h
@@ -0,0 +1,39 @@
+prge_context_t init_prge(void)
+{
+ prge_context_t ctx = {0};
+ ctx.arena = alloc_arena(ARENA_SIZE);
+ ctx.frame_arena = alloc_arena(FRAME_ARENA_SIZE);
+ ctx.input = init_input();
+ ctx.dir = sys_getbindir(&ctx.arena);
+ assert(ctx.dir);
+ printf("[INFO]\tBinary dir\t\"%s\"\n", ctx.dir);
+ return ctx;
+}
+
+texture_t prge_load_texture(prge_context_t *ctx, const char *filename, i32 gamma)
+{
+ char full_path[MAX_PATH];
+ snprintf(full_path, sizeof(full_path), "%s/%s", ctx->dir, filename);
+ texture_t texture = load_texture(&ctx->arena, full_path, gamma);
+ return texture;
+}
+
+model_t prge_load_model(prge_context_t *ctx, transform_t transform, const char *filename)
+{
+ char full_path[MAX_PATH];
+ snprintf(full_path, sizeof(full_path), "%s/%s", ctx->dir, filename);
+ model_t model = load_model_obj(&ctx->arena, transform, full_path);
+ return model;
+}
+
+i32 prge_load_sound_vorbis(prge_context_t *ctx, const char *filename)
+{
+ char full_path[MAX_PATH];
+ snprintf(full_path, sizeof(full_path), "%s/%s", ctx->dir, filename);
+ return load_vorbis(&ctx->arena, ctx->sounds, full_path);
+}
+
+void prge_play_sound(prge_context_t *ctx, i32 id)
+{
+ play_sound(ctx->sounds, &ctx->sound_queue, ctx->sound_queue_nodes, id);
+}
diff --git a/draw.h b/draw.h
new file mode 100644
index 0000000..bb67639
--- /dev/null
+++ b/draw.h
@@ -0,0 +1,92 @@
+void clear_window(v3 color)
+{
+ glClearColor(color.x, color.y, color.z, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+}
+
+void begin3d(prge_window_t window, shader_t shader, camera_t camera)
+{
+ f32 aspect_ratio = (f32)window.width/(f32)window.height;
+ mat4 projection = perspective(camera, aspect_ratio);
+ mat4 view = camera_get_view_mat(camera);
+
+ glUseProgram(shader.id);
+ shader_set_mat4(shader, SHADER_PROJECTION_MATRIX, projection);
+ shader_set_mat4(shader, SHADER_VIEW_MATRIX, view);
+}
+
+void end3d(void)
+{
+ glUseProgram(0);
+}
+
+void begin3d_alpha(prge_window_t window, shader_t shader, camera_t camera)
+{
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ begin3d(window, shader, camera);
+}
+
+void end3d_alpha(void)
+{
+ end3d();
+ glDisable(GL_BLEND);
+}
+
+void draw_mesh(mesh_t mesh)
+{
+ if (!mesh.vao) {
+ printf("warning: trying to draw mesh that doesn't have vao\n");
+ return;
+ }
+
+ glBindVertexArray(mesh.vao);
+
+ for (i32 i = 0; i < mesh.ntextures; i++) {
+ glActiveTexture(GL_TEXTURE0+i);
+ glBindTexture(GL_TEXTURE_2D, mesh.textures[i].id);
+ }
+
+ if (mesh.ebo)
+ glDrawElements(GL_TRIANGLES, mesh.nindices, GL_UNSIGNED_INT, 0);
+ else
+ glDrawArrays(GL_TRIANGLES, 0, mesh.nvertices);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glBindVertexArray(0);
+}
+
+void draw_model(shader_t shader, model_t model)
+{
+ mat4 modelmat = apply_transform(model.transform);
+ for (i32 i = 0; i < model.nmeshes; ++i) {
+ mat4 meshmat = apply_transform(model.meshes[i].transform);
+ mat4 resultmat = mat4_mul(modelmat, meshmat);
+
+ shader_set_mat4(shader, SHADER_MODEL_MATRIX, resultmat);
+ draw_mesh(model.meshes[i]);
+ }
+}
+
+void draw_entity(shader_t shader, entity_t entity)
+{
+ v3 position = entity.model.transform.position;
+ position = v3_add(position, entity.position);
+ entity.model.transform.position = position;
+ draw_model(shader, entity.model);
+}
+
+void draw_entities(elist_t entities, shader_t shader)
+{
+ for (enode_t *node = entities.first; node; node = node->next)
+ if (!(node->entity.flags & ENTITY_ALPHA))
+ draw_entity(shader, node->entity);
+}
+
+void draw_entities_alpha(elist_t entities, shader_t shader)
+{
+ for (enode_t *node = entities.first; node; node = node->next)
+ if (node->entity.flags & ENTITY_ALPHA)
+ draw_entity(shader, node->entity);
+}
diff --git a/gui.h b/gui.h
new file mode 100644
index 0000000..e94267a
--- /dev/null
+++ b/gui.h
@@ -0,0 +1,67 @@
+ui_t beginui(prge_window_t window, input_t input, shader_t shader, rect_t rect, arena_t *arena, f32 padding)
+{
+ assert(arena);
+ assert(shader.id);
+ assert(window.width && window.height);
+
+ v2 start = {rect.start.x, rect.end.y};
+ ui_t ui = {window, input, shader, rect, ui_list, start, arena, padding};
+ glUseProgram(ui.shader.id);
+ mat4 projection = ortho(0.0f, ui.window.width, 0.0f, ui.window.height, -1.0f, 1.0f);
+ shader_set_mat4(ui.shader, SHADER_PROJECTION_MATRIX, projection);
+ glDisable(GL_DEPTH_TEST);
+
+ f32 width = rect.end.x - rect.start.x;
+ f32 height = rect.end.y - rect.start.y;
+ mesh_t background = gen_quad_mesh(ui.arena, DEFAULT_TRANSFORM, width, height);
+ v2 half_width_height = {width/2.0f, height/2.0f};
+ start = v2_add(rect.start, half_width_height);
+ mat4 world = mat4_make_transl(v3_from_v2(start));
+ shader_set_mat4(ui.shader, SHADER_MODEL_MATRIX, world);
+ v4 color = {0.149f, 0.4f, 0.42f, 1.0f};
+ shader_set_v4(ui.shader, "color", color);
+ draw_mesh(background);
+ clear_mesh(&background);
+
+ return ui;
+}
+
+i32 button(ui_t *ui, const char *text, f32 width, f32 height)
+{
+ if (width <= 0.0f || height <= 0.0f)
+ return 0;
+
+ v4 color = {0.075f, 0.525f, 0.549f, 1.0f};
+ i32 pressed = 0;
+
+ v2 last = {ui->last.x + ui->padding, ui->last.y - height - ui->padding};
+ rect_t rect = {last, v2_add(last, (v2){width, height})};
+ if (in_rect(ui->input.mouse.pos, rect) && !ui->input.mouse.capture) {
+ color = (v4){0.3f, 0.61f, 0.63f, 1.0f};
+ if (is_key_pressed(ui->input.mouse.left)) {
+ pressed = 1;
+ printf("%s\n", text);
+ }
+ }
+
+ v2 center = {width/2.0f, height/2.0f};
+ v2 start = v2_add(last, center);
+ ui->last.x += width + 2.0f*ui->padding;
+ mat4 world = mat4_make_transl(v3_from_v2(start));
+
+ shader_set_mat4(ui->shader, SHADER_MODEL_MATRIX, world);
+ shader_set_v4(ui->shader, "color", color);
+
+ mesh_t quad = gen_quad_mesh(ui->arena, DEFAULT_TRANSFORM, width, height);
+
+ draw_mesh(quad);
+ clear_mesh(&quad);
+
+ return pressed;
+}
+
+void endui(void)
+{
+ glEnable(GL_DEPTH_TEST);
+ glUseProgram(0);
+}
diff --git a/input.h b/input.h
new file mode 100644
index 0000000..28090e9
--- /dev/null
+++ b/input.h
@@ -0,0 +1,46 @@
+input_t init_input()
+{
+ input_t input = {0};
+ input.mouse.first = 1;
+ return input;
+}
+
+void update_input(input_t *input)
+{
+ input->mouse.last = input->mouse.pos;
+ input->mouse.offset = V2_ZERO;
+ input->mouse.left.last = input->mouse.left.state;
+ input->mouse.right.last = input->mouse.right.state;
+
+ input->move_right.last = input->move_right.state;
+ input->move_forward.last = input->move_forward.state;
+ input->move_left.last = input->move_left.state;
+ input->move_backward.last = input->move_backward.state;
+ input->move_up.last = input->move_up.state;
+ input->move_down.last = input->move_down.state;
+
+ input->jump.last = input->jump.state;
+ input->action_right.last = input->action_right.state;
+ input->action_up.last = input->action_up.state;
+ input->action_left.last = input->action_left.state;
+ input->action_down.last = input->action_down.state;
+ input->exit.last = input->exit.state;
+}
+
+i32 is_key_down(prge_key_t key)
+{
+ i32 result = (key.state == key_state_press);
+ return result;
+}
+
+i32 is_key_pressed(prge_key_t key)
+{
+ i32 result = ((key.last == key_state_release) && (key.state == key_state_press));
+ return result;
+}
+
+i32 was_key_pressed(prge_key_t key)
+{
+ i32 result = ((key.last == key_state_press) && (key.state == key_state_release));
+ return result;
+}
diff --git a/model.h b/model.h
new file mode 100644
index 0000000..e7a2843
--- /dev/null
+++ b/model.h
@@ -0,0 +1,246 @@
+#define TINYOBJ_LOADER_C_IMPLEMENTATION
+#include "tinyobj_loader_c.h"
+
+mat4 apply_transform(transform_t transform)
+{
+ mat4 result = mat4_make_scale(transform.scale);
+ result = mat4_rotate(result, transform.rotation);
+ result = mat4_transl(result, transform.position);
+ return result;
+}
+
+void init_mesh_buffers(mesh_t *mesh)
+{
+ assert(mesh->vertices);
+ assert(mesh->nvertices > 0);
+
+ u32 vertices_size = mesh->nvertices*sizeof(vertex_t);
+ u32 indices_size = mesh->nindices*sizeof(u32);
+
+ glGenVertexArrays(1, &mesh->vao);
+ glBindVertexArray(mesh->vao);
+
+ glGenBuffers(1, &mesh->vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
+ glBufferData(GL_ARRAY_BUFFER, vertices_size, mesh->vertices, GL_STATIC_DRAW);
+
+ if (mesh->indices && (mesh->nindices > 0)) {
+ glGenBuffers(1, &mesh->ebo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices_size, mesh->indices, GL_STATIC_DRAW);
+ }
+
+ glEnableVertexAttribArray(SHADER_POSITION_LOCATION);
+ glVertexAttribPointer(SHADER_POSITION_LOCATION, 3, GL_FLOAT, GL_FALSE,
+ sizeof(vertex_t), (void *)offsetof(vertex_t, position));
+
+ glEnableVertexAttribArray(SHADER_NORMAL_LOCATION);
+ glVertexAttribPointer(SHADER_NORMAL_LOCATION, 3, GL_FLOAT, GL_FALSE,
+ sizeof(vertex_t), (void *)offsetof(vertex_t, normal));
+
+ glEnableVertexAttribArray(SHADER_TEXCOORDS_LOCATION);
+ glVertexAttribPointer(SHADER_TEXCOORDS_LOCATION, 2, GL_FLOAT, GL_FALSE,
+ sizeof(vertex_t), (void *)offsetof(vertex_t, texcoords));
+
+ glBindVertexArray(0);
+}
+
+mesh_t init_mesh(transform_t transform, i32 nvertices, vertex_t *vertices, i32 nindices, u32 *indices)
+{
+ mesh_t mesh = {0};
+ mesh.transform = transform;
+ mesh.nvertices = nvertices;
+ mesh.vertices = vertices;
+ mesh.nindices = nindices;
+ mesh.indices = indices;
+ init_mesh_buffers(&mesh);
+ return mesh;
+}
+
+void clear_mesh(mesh_t *mesh)
+{
+ glBindVertexArray(mesh->vao);
+ glDisableVertexAttribArray(SHADER_POSITION_LOCATION);
+ glDisableVertexAttribArray(SHADER_NORMAL_LOCATION);
+ glDisableVertexAttribArray(SHADER_TEXCOORDS_LOCATION);
+
+ glBindVertexArray(0);
+ glDeleteVertexArrays(1, &mesh->vao);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &mesh->vbo);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ glDeleteBuffers(1, &mesh->ebo);
+}
+
+void add_mesh_texture(mesh_t *mesh, texture_t texture)
+{
+ if (!mesh) {
+ printf("error: can't add texture to a null mesh :|\n");
+ return;
+ }
+
+ if (mesh->ntextures+1 >= MAX_TEXTURE_PER_MESH) {
+ printf("warning: \"%s\" texture limit reached: %d\n", texture.name, MAX_TEXTURE_PER_MESH);
+ return;
+ }
+
+ mesh->textures[mesh->ntextures++] = texture;
+}
+
+mesh_t gen_quad_mesh(arena_t *arena, transform_t transform, f32 width, f32 height)
+{
+ assert(width > 0);
+ assert(height > 0);
+
+ i32 nvertices = 4;
+ vertex_t *vertices = push_arena(arena, nvertices*sizeof(vertex_t));
+ vertices[0] = (vertex_t){{-width/2.0f, -height/2.0f, 0.0f}, V3_ZERO, {0.0f, 0.0f}};
+ vertices[1] = (vertex_t){{-width/2.0f, height/2.0f, 0.0f}, V3_ZERO, {0.0f, height}};
+ vertices[2] = (vertex_t){{ width/2.0f, -height/2.0f, 0.0f}, V3_ZERO, {width, 0.0f}};
+ vertices[3] = (vertex_t){{ width/2.0f, height/2.0f, 0.0f}, V3_ZERO, {width, height}};
+
+ i32 nindices = 6;
+ u32 *indices = push_arena(arena, nindices*sizeof(u32));
+ indices[0] = 0;
+ indices[1] = 1;
+ indices[2] = 3;
+ indices[3] = 0;
+ indices[4] = 2;
+ indices[5] = 3;
+
+ mesh_t mesh = init_mesh(transform, nvertices, vertices, nindices, indices);
+
+ return mesh;
+}
+
+mesh_t gen_circle_mesh(arena_t *arena, transform_t transform, f32 radius, i32 nvertices)
+{
+ if (nvertices < 3)
+ nvertices = 3;
+
+ vertex_t *vertices = push_arena(arena, nvertices*sizeof(vertex_t));
+
+ f32 angle = 0.0f;
+ f32 dangle = 2.0f*F_PI/nvertices;
+ for (i32 i = 0; i < nvertices; ++i, angle += dangle)
+ vertices[i] = (vertex_t){{fcos(angle)*radius, fsin(angle)*radius, 0.0f}, V3_ZERO, V2_ZERO};
+
+ i32 nindices = nvertices*3;
+ u32 *indices = push_arena(arena, nindices*sizeof(u32));
+ for (i32 i = 0, vi = 1; i < nindices; i += 3, vi++) {
+ indices[i] = 0;
+ indices[i+1] = vi;
+ indices[i+2] = ((vi+1 == nvertices) ? 1 : vi+1);
+ }
+
+ mesh_t mesh = init_mesh(transform, nvertices, vertices, nindices, indices);
+
+ return mesh;
+}
+
+model_t init_model(transform_t transform, i32 nmeshes, mesh_t *meshes)
+{
+ model_t model = {
+ transform,
+ nmeshes,
+ meshes,
+ };
+ return model;
+}
+
+void read_file_tinyobj(void* ctx, const char* filename, const i32 is_mtl, const char* obj_filename, char** data, u64* len)
+{
+ if (is_mtl)
+ printf("info: is_mtl is set (don't use it right now)\n");
+ if (obj_filename)
+ printf("info: obj_filename is \"%s\"\n", obj_filename);
+ if (!filename) {
+ printf("error: obj filename is zero\n");
+ *data = 0;
+ *len = 0;
+ return;
+ }
+
+ arena_t *arena = (arena_t *)ctx;
+ *len = sys_read_file(arena, data, filename);
+}
+
+model_t load_model_obj(arena_t *arena, transform_t transform, const char *filename)
+{
+ tinyobj_attrib_t attrib;
+ u64 nshapes;
+ tinyobj_shape_t *shapes;
+ u64 nmaterials;
+ tinyobj_material_t *materials;
+
+ u32 flags = TINYOBJ_FLAG_TRIANGULATE;
+ i32 status = tinyobj_parse_obj(&attrib, &shapes, &nshapes, &materials, &nmaterials,
+ filename, read_file_tinyobj, arena, flags);
+
+ model_t model = {0};
+ if (status != TINYOBJ_SUCCESS) {
+ printf("error: failed to parse \"%s\"\n", filename);
+ return model;
+ }
+
+ u64 ntriangles = attrib.num_face_num_verts;
+ u64 face_offset = 0;
+
+ u64 nvertices = ntriangles*3;
+ vertex_t *vertices = push_arena(arena, sizeof(vertex_t)*nvertices);
+
+ u64 nindices = ntriangles*3;
+ u32 *indices = push_arena(arena, sizeof(u32)*nindices);
+
+ i32 vertex_count = 0, index_count = 0, index_index = 0;
+ for (u32 i = 0; i < attrib.num_face_num_verts; ++i) {
+ assert(attrib.face_num_verts[i]%3 == 0);
+ assert(attrib.face_num_verts[i]/3 > 0);
+ assert(attrib.num_texcoords);
+
+ tinyobj_vertex_index_t idx;
+ for (i32 j = 0; j < 3; ++j) {
+ idx = attrib.faces[face_offset+j];
+ assert(idx.v_idx >= 0);
+ v3 position = {
+ attrib.vertices[3*idx.v_idx+0],
+ attrib.vertices[3*idx.v_idx+1],
+ attrib.vertices[3*idx.v_idx+2]
+ };
+
+ assert(idx.vn_idx < (i32)attrib.num_normals);
+ v3 normal = {
+ attrib.normals[3*idx.vn_idx+0],
+ attrib.normals[3*idx.vn_idx+1],
+ attrib.normals[3*idx.vn_idx+2]
+ };
+
+ assert(idx.vt_idx < (i32)attrib.num_texcoords);
+ v2 texcoords = {
+ attrib.texcoords[2*idx.vt_idx+0],
+ attrib.texcoords[2*idx.vt_idx+1]
+ };
+
+ vertices[vertex_count++] = (vertex_t){position, normal, texcoords};
+ indices[index_index++] = index_count++;
+ }
+
+ face_offset += 3;
+ }
+
+ i32 nmeshes = 1;
+ mesh_t *meshes = push_arena(arena, sizeof(mesh_t)*nmeshes);
+ *meshes = init_mesh(DEFAULT_TRANSFORM, nvertices, vertices, nindices, indices);
+
+ tinyobj_attrib_free(&attrib);
+ tinyobj_shapes_free(shapes, nshapes);
+ tinyobj_materials_free(materials, nmaterials);
+
+ model = init_model(transform, nmeshes, meshes);
+
+ printf("info: \"%s\" loaded successfully\n", filename);
+
+ return model;
+}
diff --git a/phys.h b/phys.h
new file mode 100644
index 0000000..d7b3a76
--- /dev/null
+++ b/phys.h
@@ -0,0 +1,95 @@
+i32 add_entity(entity_t entity, elist_t *list)
+{
+ assert(list);
+ i32 i;
+ for (i = 0; i < MAX_ENTITIES; ++i)
+ if (!list->nodes[i].id)
+ break;
+ if (i == MAX_ENTITIES) {
+ printf("error: failed to add entity\n");
+ return 0;
+ }
+ ++list->count;
+ enode_t *node = list->nodes+i;
+ node->id = list->count;
+ node->entity = entity;
+ dllpushback(list->first, list->last, node);
+ return node->id;
+}
+
+void delete_entity(i32 id, elist_t *list)
+{
+ assert(list);
+ for (enode_t *node = list->first; node; node = node->next) {
+ if (node->id == id) {
+ dllremove(list->first, list->last, node);
+ memzero_struct(node);
+ list->count--;
+ printf("info: entity %d deleted\n", id);
+ return;
+ }
+ }
+ printf("error: entity %d failed to delete\n", id);
+}
+
+entity_t *get_entity(elist_t list, i32 id)
+{
+ for (enode_t *node = list.first; node; node = node->next)
+ if (node->id == id)
+ return &node->entity;
+ return 0;
+}
+
+i32 aabb3d(bbox_t a, bbox_t b)
+{
+ i32 result = ((b.start.x <= a.end.x) && (b.end.x >= a.start.x)) &&
+ ((b.start.y <= a.end.y) && (b.end.y >= a.start.y)) &&
+ ((b.start.z <= a.end.z) && (b.end.z >= a.start.z));
+ return result;
+}
+
+i32 check_collision(entity_t *a, entity_t *b)
+{
+ if (!(a->flags & ENTITY_COLLIDE) || !(b->flags & ENTITY_COLLIDE))
+ return 0;
+
+ bbox_t bboxa = {
+ v3_add(a->bbox.start, a->position),
+ v3_add(a->bbox.end, a->position)
+ };
+
+ bbox_t bboxb = {
+ v3_add(b->bbox.start, b->position),
+ v3_add(b->bbox.end, b->position)
+ };
+
+ i32 result = aabb3d(bboxa, bboxb);
+
+ return result;
+}
+
+entity_t move_entity(entity_t old, v3 acceleration, float dt)
+{
+ entity_t new = old;
+ new.position = v3_add(old.position, v3_scalef(old.velocity, dt));
+ new.velocity = v3_add(old.velocity, v3_scalef(acceleration, dt*dt));
+ new.velocity = v3_sub(new.velocity, v3_scalef(V3_UP, dt));
+ return new;
+}
+
+/*
+void update_entities(elist_t list)
+{
+ for (enode_t *node = list.first; node; node = node->next) {
+ if (node->entity.flags & ENTITY_MOVE)
+ move_entity(node->entity, );
+ if (node->entity.flags & ENTITY_COLLIDE) {
+ for (enode_t *test = list.first; test; test = test->next) {
+ if (check_collision(node->entity, test->entity)) {
+
+ }
+ }
+ }
+ }
+}
+*/
diff --git a/prge.h b/prge.h
index 90271b3..d9c664b 100644
--- a/prge.h
+++ b/prge.h
@@ -3,45 +3,16 @@
#include "prb.h"
-#define STB_IMAGE_IMPLEMENTATION
-#include "stb_image.h"
-
-#include "prge_types.h"
-#include "prge_window.h"
-#include "prge_input.h"
-#include "prge_texture.h"
-#include "prge_shader.h"
-#include "prge_model.h"
-#include "prge_camera.h"
-#include "prge_draw.h"
-#include "prge_gui.h"
-#include "prge_audio.h"
-
-#include "prge_window.c"
-#include "prge_input.c"
-#include "prge_texture.c"
-#include "prge_shader.c"
-#include "prge_model.c"
-#include "prge_camera.c"
-#include "prge_draw.c"
-#include "prge_gui.c"
-#include "prge_audio.c"
-
-#define PRGE_PERSARENA_SIZE MB(64)
-#define PRGE_TMPARENA_SIZE MB(32)
-
-void init_prge(PRGEContext *ctx)
-{
- MEM0STRUCT(ctx);
-
- ctx->pa = alloc_arena(PRGE_PERSARENA_SIZE);
- ctx->tmpa = alloc_arena(PRGE_TMPARENA_SIZE);
-
- ctx->in = init_input();
-
- ctx->bindir = sys_getbindir(ctx->pa);
- if (ctx->bindir)
- sys_printf("[INFO] : PRGE : Binary path : \"%s\"\n", ctx->bindir);
-}
+#include "types.h"
+#include "input.h"
+#include "texture.h"
+#include "shader.h"
+#include "model.h"
+#include "phys.h"
+#include "camera.h"
+#include "audio.h"
+#include "ctx.h"
+#include "draw.h"
+#include "gui.h"
#endif /* PRGE_H */
diff --git a/prge_audio.c b/prge_audio.c
deleted file mode 100644
index 08fb67c..0000000
--- a/prge_audio.c
+++ /dev/null
@@ -1,75 +0,0 @@
-S32 find_sound(PRGEContext *ctx, const char *name)
-{
- S32 i;
- Sound *snd;
-
- for (i = 0; i < PRGE_MAX_SOUNDS_LOADED; i++) {
- snd = ctx->snds+i;
- if (snd->name && (strcmp(snd->name, name) == 0))
- return i;
- }
-
- return -1;
-}
-
-S32 load_sound(PRGEContext *ctx, Sound newsnd)
-{
- S32 i;
- Sound *snd;
-
- for (i = 0; i < PRGE_MAX_SOUNDS_LOADED; i++) {
- snd = ctx->snds+i;
- if (!snd->data)
- break;
- }
-
- if (i == PRGE_MAX_SOUNDS_LOADED) {
- sys_printf("[WARNING] : PRGE : Max sounds loaded\n");
- pop_arena(ctx->pa, newsnd.size);
- return -1;
- }
-
- *snd = newsnd;
-
- return i;
-}
-
-B32 enqueue_sound(PRGEContext *ctx, Sound *snd)
-{
- SoundQueueNode *node;
- SoundQueue *sndq;
- S32 i;
-
- ASSERT(snd);
-
- sndq = &ctx->sndq;
-
- if (sndq->cnt == PRGE_MAX_SOUNDS_PLAYING)
- return 0;
-
- for (i = 0; i < PRGE_MAX_SOUNDS_PLAYING; i++) {
- node = ctx->nodes+i;
- if (!node->snd)
- break;
- }
-
- node->snd = snd;
-
- DLLPUSHFRONT(sndq->first, sndq->last, node);
-
- sndq->cnt++;
-
- return 1;
-}
-
-Sound *dequeue_sound(SoundQueue *sndq)
-{
- Sound *snd;
- if (sndq->cnt == 0)
- return 0;
- snd = sndq->first->snd;
- sndq->first->snd = 0;
- DLLREMOVE(sndq->first, sndq->last, sndq->first);
- sndq->cnt--;
- return snd;
-}
diff --git a/prge_audio.h b/prge_audio.h
deleted file mode 100644
index 5f07a2c..0000000
--- a/prge_audio.h
+++ /dev/null
@@ -1,6 +0,0 @@
-S32 find_sound(PRGEContext *ctx, const char *name);
-S32 load_sound(PRGEContext *ctx, Sound snd);
-S32 load_vorbis(PRGEContext *ctx, const char *fname);
-S32 enqueue_sound(PRGEContext *ctx, Sound *snd);
-Sound *dequeue_sound(SoundQueue *sndq);
-void play_sound(PRGEContext *ctx, S32 id);
diff --git a/prge_camera.c b/prge_camera.c
deleted file mode 100644
index 0a79a74..0000000
--- a/prge_camera.c
+++ /dev/null
@@ -1,99 +0,0 @@
-Camera initcam(V3 pos, F32 fov, F32 near, F32 far, F32 yaw, F32 pitch, F32 roll)
-{
- Camera c = {
- .pos = pos,
- .fov = fov,
- .near = near,
- .far = far,
- .yaw = yaw,
- .pitch = pitch,
- .roll = roll,
- };
- return c;
-}
-
-MAT4 getfpviewmat(Camera *c)
-{
- MAT4 v;
- v = translmat4(MAT4_IDENTITY, invv3(c->pos));
- v = rotatemat4(v, v3(c->pitch, c->yaw, c->roll));
- return v;
-}
-
-void getfpvecs(Camera *c, V3 *l, V3 *u, V3 *f)
-{
- F32 angle, cp, sp, cy, sy, cr, sr;
-
- angle = DEG2RAD*c->pitch;
- cp = f32cos(angle);
- sp = f32sin(angle);
- angle = DEG2RAD*c->yaw;
- cy = f32cos(angle);
- sy = f32sin(angle);
- angle = DEG2RAD*c->roll;
- cr = f32cos(angle);
- sr = f32sin(angle);
-
- *l = v3(cy*cr, -cy*sr, sy);
- *u = v3(sp*sy*cr+cp*sr, -sp*sy*sr+cp*cr, -sp*cy);
- *f = v3(-cp*sy*cr+sp*sr, cp*sy*sr+sp*cr, cp*cy);
-}
-
-MAT4 lookat(Camera c, V3 t, V3 wup)
-{
- V3 f, r, u;
- MAT4 transl, rotate, res;
-
- f = normv3(subv3(c.pos, t));
- r = normv3(crossv3(wup, f));
- u = crossv3(f, r);
-
- transl = translmat4(MAT4_IDENTITY, invv3(c.pos));
- rotate = transpmat4(rotateaxismat4(r, u, f));
- res = mulmat4(rotate, transl);
-
- return res;
-}
-
-MAT4 ortho(F32 l, F32 r, F32 b, F32 t, F32 n, F32 f)
-{
- MAT4 res;
-
- res = MAT4_IDENTITY;
- res.m0.x = 2.0f/(r-l);
- res.m1.y = 2.0f/(t-b);
- res.m2.z = -2.0f/(f-n);
- res.m3.x = -(r+l)/(r-l);
- res.m3.y = -(t+b)/(t-b);
- res.m3.z = -(f+n)/(f-n);
-
- return res;
-}
-
-MAT4 persp(F32 fov, F32 ar, F32 n, F32 f)
-{
- F32 r, t;
- MAT4 res;
-
- r = n*f32tan(fov/2.0f*DEG2RAD);
- t = r/ar;
-
- res = MAT4_IDENTITY;
- res.m0.x = n/r;
- res.m1.y = n/t;
- res.m2.z = -(f+n)/(f-n);
- res.m2.w = -1.0f;
- res.m3.z = (-2.0f*f*n)/(f-n);
- res.m3.w = 0.0f;
-
- return res;
-}
-
-MAT4 camera_persp(Camera c, F32 ar)
-{
- MAT4 res;
-
- res = persp(c.fov, ar, c.near, c.far);
-
- return res;
-}
diff --git a/prge_camera.h b/prge_camera.h
deleted file mode 100644
index f938b8b..0000000
--- a/prge_camera.h
+++ /dev/null
@@ -1,7 +0,0 @@
-Camera initcam(V3 pos, F32 fov, F32 near, F32 far, F32 yaw, F32 pitch, F32 roll);
-MAT4 getfpviewmat(Camera *c);
-void getfpvecs(Camera *c, V3 *l, V3 *u, V3 *f);
-MAT4 lookat(Camera c, V3 t, V3 wup);
-MAT4 ortho(F32 l, F32 r, F32 b, F32 t, F32 n, F32 f);
-MAT4 persp(F32 fov, F32 ar, F32 n, F32 f);
-MAT4 camera_persp(Camera c, F32 ar);
diff --git a/prge_draw.c b/prge_draw.c
deleted file mode 100644
index 4228d68..0000000
--- a/prge_draw.c
+++ /dev/null
@@ -1,78 +0,0 @@
-void clear_window(PRGEWindow wnd, V3 clear_color)
-{
- glClearColor(clear_color.x, clear_color.y, clear_color.z, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-}
-
-void begin3d(PRGEWindow wnd, Shader shader, Camera camera)
-{
- F32 ar;
- MAT4 proj, view;
-
- ar = (F32)wnd.w/(F32)wnd.h;
- proj = camera_persp(camera, ar);
- view = getfpviewmat(&camera);
-
- glUseProgram(shader.id);
-
- setmat4fv(shader.id, PRGE_SHADER_PROJ_MAT, proj);
- setmat4fv(shader.id, PRGE_SHADER_VIEW_MAT, view);
-}
-
-void end3d(void)
-{
- glUseProgram(0);
-}
-
-void begin3d_alpha(PRGEWindow wnd, Shader shader, Camera camera)
-{
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- begin3d(wnd, shader, camera);
-}
-
-void end3d_alpha(void)
-{
- end3d();
- glDisable(GL_BLEND);
-}
-
-void draw_mesh(Mesh mesh)
-{
- S32 i;
-
- ASSERT(mesh.vao);
-
- glBindVertexArray(mesh.vao);
-
- for (i = 0; i < mesh.ntextures; i++) {
- glActiveTexture(GL_TEXTURE0+i);
- glBindTexture(GL_TEXTURE_2D, mesh.textures[i].id);
- }
-
- if (mesh.ebo)
- glDrawElements(GL_TRIANGLES, mesh.nindices, GL_UNSIGNED_INT, 0);
- else
- glDrawArrays(GL_TRIANGLES, 0, mesh.nverts);
-
- glBindVertexArray(0);
-}
-
-void draw_model(Shader shader, Model model)
-{
- MAT4 modelm,
- meshm,
- resm;
- S32 i;
-
- modelm = rotatemat4(MAT4_IDENTITY, model.rotate);
- modelm = translmat4(modelm, model.origin);
- for (i = 0; i < model.nmeshes; i++) {
- meshm = rotatemat4(MAT4_IDENTITY, model.meshes[i].rotate);
- meshm = translmat4(meshm, model.meshes[i].origin);
- resm = mulmat4(modelm, meshm);
-
- setmat4fv(shader.id, PRGE_SHADER_MODEL_MAT, resm);
- draw_mesh(model.meshes[i]);
- }
-}
diff --git a/prge_draw.h b/prge_draw.h
deleted file mode 100644
index 087b5ac..0000000
--- a/prge_draw.h
+++ /dev/null
@@ -1,8 +0,0 @@
-void clear_window(PRGEWindow wnd, V3 clear_color);
-void begin3d(PRGEWindow wnd, Shader shader, Camera camera);
-void end3d(void);
-void begin3d_alpha(PRGEWindow wnd, Shader shader, Camera camera);
-void end3d_alpha(void);
-
-void draw_mesh(Mesh mesh);
-void draw_model(Shader shader, Model model);
diff --git a/prge_gui.c b/prge_gui.c
deleted file mode 100644
index b4be331..0000000
--- a/prge_gui.c
+++ /dev/null
@@ -1,60 +0,0 @@
-B32 inrect(V2 pos, V2 start, V2 end)
-{
- B32 res;
- res = ((pos.x > start.x) && (pos.x < end.x) &&
- (pos.y > start.y) && (pos.y < end.y));
- return res;
-}
-
-void beginui(Shader shader, PRGEWindow wnd)
-{
- MAT4 proj;
-
- glUseProgram(shader.id);
- proj = ortho(0.0f, (F32)wnd.w, 0.0f, (F32)wnd.h, -1.0f, 1.0f);
- setmat4fv(shader.id, PRGE_SHADER_PROJ_MAT, proj);
- glDisable(GL_DEPTH_TEST);
-}
-
-void endui(void)
-{
- glEnable(GL_DEPTH_TEST);
- glUseProgram(0);
-}
-
-B32 button(PRGEContext *prgectx, Shader shader, const char *name, V2 center, F32 w, F32 h)
-{
- B32 pressed;
- Mesh quad;
- V2 start, end;
-
- MAT4 model;
- V4 color;
-
- pressed = 0;
-
- quad = gen_quad(prgectx->tmpa, v3fromv2(center), V3_ZERO, w, h);
-
- color = v4(1.0f, 0.0f, 0.0f, 1.0f);
- start = v2(center.x-w/2.0f, center.y-h/2.0f);
- end = v2(center.x+w/2.0f, center.y+h/2.0f);
-
- if (inrect(prgectx->in.mouse_pos, start, end) && !prgectx->in.capture_mouse) {
- color = v4(0.0f, 0.0f, 1.0f, 1.0f);
- if (is_key_pressed(prgectx->in.mouse_left)) {
- sys_printf("%s\n", name);
- pressed = 1;
- }
- }
-
- model = translmat4(MAT4_IDENTITY, v3(center.x, prgectx->wnd.h-center.y, 0.0f));
-
- setmat4fv(shader.id, "model", model);
- set4fv(shader.id, "color", color);
-
- draw_mesh(quad);
-
- clear_mesh(&quad);
-
- return pressed;
-}
diff --git a/prge_gui.h b/prge_gui.h
deleted file mode 100644
index c267466..0000000
--- a/prge_gui.h
+++ /dev/null
@@ -1,6 +0,0 @@
-B32 inrect(V2 pos, V2 start, V2 end);
-
-void beginui(Shader shader, PRGEWindow wnd);
-void endui(void);
-
-B32 button(PRGEContext *prgectx, Shader shader, const char *name, V2 center, F32 w, F32 h);
diff --git a/prge_input.c b/prge_input.c
deleted file mode 100644
index 74de9e5..0000000
--- a/prge_input.c
+++ /dev/null
@@ -1,51 +0,0 @@
-Input init_input()
-{
- Input in;
-
- MEM0STRUCT(&in);
-
- in.first_mouse = 1;
-
- return in;
-}
-
-/* NOTE(pryazha): Updates the last states of keys, mouse position and offset.
- * Should be called every frame */
-void update_input(Input *in)
-{
- in->last_mouse_pos = in->mouse_pos;
- in->mouse_offset = V2_ZERO;
- in->mouse_left.last = in->mouse_left.state;
- in->mouse_right.last = in->mouse_right.state;
-
- in->move_right.last = in->move_right.state;
- in->move_forward.last = in->move_forward.state;
- in->move_left.last = in->move_left.state;
- in->move_backward.last = in->move_backward.state;
- in->move_up.last = in->move_up.state;
- in->move_down.last = in->move_down.state;
- in->jump.last = in->jump.state;
- in->action_right.last = in->action_right.state;
- in->action_up.last = in->action_up.state;
- in->action_left.last = in->action_left.state;
- in->action_down.last = in->action_down.state;
- in->exit.last = in->exit.state;
-}
-
-B32 is_key_down(Key key)
-{
- B32 r = (key.state == KeyState_PRESS);
- return r;
-}
-
-B32 is_key_pressed(Key key)
-{
- B32 r = ((key.last == KeyState_RELEASE) && (key.state == KeyState_PRESS));
- return r;
-}
-
-B32 was_key_pressed(Key key)
-{
- B32 r = ((key.last == KeyState_PRESS) && (key.state == KeyState_RELEASE));
- return r;
-}
diff --git a/prge_input.h b/prge_input.h
deleted file mode 100644
index fe9c01f..0000000
--- a/prge_input.h
+++ /dev/null
@@ -1,5 +0,0 @@
-Input init_input();
-void update_input(Input *in);
-B32 is_key_down(Key key);
-B32 is_key_pressed(Key key);
-B32 was_key_pressed(Key key);
diff --git a/prge_model.c b/prge_model.c
deleted file mode 100644
index e2dc55f..0000000
--- a/prge_model.c
+++ /dev/null
@@ -1,187 +0,0 @@
-Vertex init_vert(V3 pos, V2 texc)
-{
- Vertex v = {
- .pos = pos,
- .texc = texc,
- };
- return v;
-}
-
-void init_mesh_buffers(Mesh *mesh)
-{
- ASSERT(mesh->verts);
- ASSERT(mesh->nverts > 0);
-
- U32 sverts,
- sindices;
-
- sverts = mesh->nverts*sizeof(Vertex);
- sindices = mesh->nindices*sizeof(U32);
-
- glGenVertexArrays(1, &mesh->vao);
- glBindVertexArray(mesh->vao);
-
- glGenBuffers(1, &mesh->vbo);
- glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo);
- glBufferData(GL_ARRAY_BUFFER, sverts,
- mesh->verts, GL_STATIC_DRAW);
-
- if (mesh->indices && (mesh->nindices > 0)) {
- glGenBuffers(1, &mesh->ebo);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo);
- glBufferData(GL_ELEMENT_ARRAY_BUFFER, sindices,
- mesh->indices, GL_STATIC_DRAW);
- }
-
- glEnableVertexAttribArray(PRGE_SHADER_POS_LOC);
- glVertexAttribPointer(PRGE_SHADER_POS_LOC, 3,
- GL_FLOAT, GL_FALSE, sizeof(Vertex),
- (void *)OFFSETOF(Vertex, pos));
-
- glEnableVertexAttribArray(PRGE_SHADER_TEXC_LOC);
- glVertexAttribPointer(PRGE_SHADER_TEXC_LOC, 2,
- GL_FLOAT, GL_FALSE, sizeof(Vertex),
- (void *)OFFSETOF(Vertex, texc));
-
- glBindVertexArray(0);
-}
-
-Mesh init_mesh(V3 origin, V3 rotate, S32 nverts, Vertex *verts, S32 nindices, U32 *indices)
-{
- Mesh mesh;
-
- MEM0STRUCT(&mesh);
-
- mesh.origin = origin;
- mesh.rotate = rotate;
-
- mesh.verts = verts;
- mesh.nverts = nverts;
-
- mesh.indices = indices;
- mesh.nindices = nindices;
-
- init_mesh_buffers(&mesh);
-
- return mesh;
-}
-
-void clear_mesh(Mesh *mesh)
-{
- glBindVertexArray(mesh->vao);
- glDisableVertexAttribArray(PRGE_SHADER_POS_LOC);
-
- glBindVertexArray(0);
- glDeleteVertexArrays(1, &mesh->vao);
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &mesh->vbo);
-
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &mesh->ebo);
-}
-
-void add_mesh_texture(Mesh *mesh, Texture texture)
-{
- if (mesh->ntextures+1 >= PRGE_MAX_TEXTURES) {
- sys_printf("[WARNING] : Texture : \"%s\" : limit\n", texture.name);
- return;
- }
- mesh->textures[mesh->ntextures++] = texture;
-}
-
-Mesh gen_quad(Arena *arena, V3 origin, V3 rotate, F32 w, F32 h)
-{
- Mesh mesh;
-
- S32 nverts;
- Vertex *verts;
-
- S32 nindices;
- U32 *indices;
-
- ASSERT(w > 0);
- ASSERT(h > 0);
-
- nverts = 4;
- verts = push_arena(arena, nverts*sizeof(Vertex));
- verts[0] = init_vert(v3(-w/2.0f, -h/2.0f, 0.0f), v2(0.0f, 0.0f));
- verts[1] = init_vert(v3(-w/2.0f, h/2.0f, 0.0f), v2(0.0f, h));
- verts[2] = init_vert(v3(w/2.0f, -h/2.0f, 0.0f), v2(w, 0.0f));
- verts[3] = init_vert(v3(w/2.0f, h/2.0f, 0.0f), v2(w, h));
-
- nindices = 6;
- indices = push_arena(arena, nindices*sizeof(U32));
- indices[0] = 0;
- indices[1] = 1;
- indices[2] = 3;
- indices[3] = 0;
- indices[4] = 2;
- indices[5] = 3;
-
- mesh = init_mesh(origin, rotate, nverts, verts, nindices, indices);
-
- return mesh;
-}
-
-Mesh gen_circle(Arena *arena, V3 origin, V3 rotate, F32 r, S32 nverts)
-{
- Mesh mesh;
-
- Vertex *verts;
-
- S32 nindices;
- U32 *indices;
-
- F32 angle, dangle;
-
- S32 i, vi;
-
- if (nverts < 3)
- nverts = 3;
-
- verts = push_arena(arena, nverts*sizeof(Vertex));
-
- dangle = 2*F32PI/(F32)nverts;
- for (i = 0, angle = 0.0f; i < nverts; i++, angle += dangle)
- verts[i] = init_vert(v3(f32cos(angle)*r, f32sin(angle)*r, 0.0f), V2_ZERO);
-
- nindices = nverts*3;
- indices = push_arena(arena, nindices*sizeof(U32));
- for (i = 0, vi = 1; i < nindices; i += 3, vi++) {
- indices[i] = 0;
- indices[i+1] = vi;
- indices[i+2] = (((vi+1) == (nverts)) ? 1 : (vi+1));
- }
-
- mesh = init_mesh(origin, rotate, nverts, verts, nindices, indices);
-
- return mesh;
-}
-
-Model init_model(V3 origin, V3 rotate, S32 nmeshes, Mesh *meshes)
-{
- Model model = {
- .origin = origin,
- .rotate = rotate,
- .nmeshes = nmeshes,
- .meshes = meshes,
- };
- return model;
-}
-
-Model load_model(V3 origin, V3 rotate, const char *fname)
-{
- Model model;
-
- MEM0STRUCT(&model);
-
- model.origin = origin;
- model.rotate = rotate;
-
- sys_printf("[INFO] : PRGE : Trying to load %s\n", fname);
-
- /* TODO(pryazha): Load models with assimp? */
-
- return model;
-}
diff --git a/prge_model.h b/prge_model.h
deleted file mode 100644
index b2e6f1e..0000000
--- a/prge_model.h
+++ /dev/null
@@ -1,11 +0,0 @@
-extern Vertex init_vert(V3 pos, V2 texc);
-
-extern Mesh init_mesh(V3 origin, V3 rotate, S32 nverts, Vertex *verts, S32 nindices, U32 *indices);
-extern void clear_mesh(Mesh *mesh);
-extern void add_mesh_texture(Mesh *mesh, Texture texture);
-
-extern Mesh gen_quad(Arena *arena, V3 origin, V3 rotate, F32 w, F32 h);
-extern Mesh gen_circle(Arena *arena, V3 origin, V3 rotate, F32 r, S32 nverts);
-
-extern Model init_model(V3 origin, V3 rotate, S32 nmeshes, Mesh *meshes);
-extern Model load_model(V3 origin, V3 rotate, const char *fname);
diff --git a/prge_shader.c b/prge_shader.c
deleted file mode 100644
index 3aee9b5..0000000
--- a/prge_shader.c
+++ /dev/null
@@ -1,93 +0,0 @@
-U32 compile_glsl_shader(U32 type, const char *fname)
-{
- Arena *tmpa;
- FLS src;
- const char *csrc;
- U32 id;
- S32 status;
-
- tmpa = alloc_arena(0);
- src = sys_read_entire_file_fls(tmpa, fname);
- if (!src.p) {
- sys_printf("[ERROR] : Failed to read \"%s\"\n", fname);
- return 0;
- }
- csrc = (const char *)src.p;
-
- id = glCreateShader(type);
- glShaderSource(id, 1, &csrc, 0);
- glCompileShader(id);
-
- glGetShaderiv(id, GL_COMPILE_STATUS, &status);
- if (status == GL_FALSE) {
- char log[512];
- glGetShaderInfoLog(id, 512, 0, log);
- sys_printf("[ERROR] : Failed to compile : \"%s\"\n%s", fname, log);
- } else {
- sys_printf("[INFO] : \"%s\" compiled successfully.\n", fname);
- }
-
- release_arena(tmpa);
-
- return id;
-}
-
-Shader load_shader(const char *vfname, const char *gfname, const char *ffname)
-{
- Shader shader;
- U32 vert, geom, frag;
- S32 success;
-
- shader.id = glCreateProgram();
-
- if (vfname) {
- vert = compile_glsl_shader(GL_VERTEX_SHADER, vfname);
- glAttachShader(shader.id, vert);
- }
- if (gfname) {
- geom = compile_glsl_shader(GL_GEOMETRY_SHADER, gfname);
- glAttachShader(shader.id, geom);
- }
- if (ffname) {
- frag = compile_glsl_shader(GL_FRAGMENT_SHADER, ffname);
- glAttachShader(shader.id, frag);
- }
-
- glLinkProgram(shader.id);
- glGetProgramiv(shader.id, GL_LINK_STATUS, &success);
-
- if (success == GL_FALSE) {
- char log[512];
- glGetProgramInfoLog(shader.id, 512, 0, log);
- sys_printf("[ERROR] : Failed to link shader program:\n%s", log);
- } else {
- sys_printf("[INFO] : Shader linked successfuly.\n\n");
- }
-
- if (vfname)
- glDeleteShader(vert);
- if (gfname)
- glDeleteShader(geom);
- if (ffname)
- glDeleteShader(frag);
-
- return shader;
-}
-
-void set3fv(U32 id, const char *name, V3 v)
-{
- S32 loc = glGetUniformLocation(id, name);
- glUniform3fv(loc, 1, (F32 *)&v);
-}
-
-void set4fv(U32 id, const char *name, V4 v)
-{
- S32 loc = glGetUniformLocation(id, name);
- glUniform4fv(loc, 1, (F32 *)&v);
-}
-
-void setmat4fv(U32 id, const char *name, MAT4 m)
-{
- S32 loc = glGetUniformLocation(id, name);
- glUniformMatrix4fv(loc, 1, 0, (F32 *)&m);
-}
diff --git a/prge_shader.h b/prge_shader.h
deleted file mode 100644
index 36e95ad..0000000
--- a/prge_shader.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#define PRGE_SHADER_POS_LOC 0
-#define PRGE_SHADER_TEXC_LOC 1
-
-#define PRGE_SHADER_PROJ_MAT "proj"
-#define PRGE_SHADER_VIEW_MAT "view"
-#define PRGE_SHADER_MODEL_MAT "model"
-
-U32 compile_glsl_shader(U32 type, const char *fname);
-Shader load_shader(const char *vfname, const char *gfname, const char *ffname);
-void set3fv(U32 id, const char *name, V3 v);
-void set4fv(U32 id, const char *name, V4 v);
-void setmat4fv(U32 id, const char *name, MAT4 m);
diff --git a/prge_texture.c b/prge_texture.c
deleted file mode 100644
index e6c0820..0000000
--- a/prge_texture.c
+++ /dev/null
@@ -1,59 +0,0 @@
-Texture load_texture(Arena *arena, const char *fname, B32 gamma)
-{
- Texture texture;
- U8 *data;
- S32 nchannels;
- GLenum internal_format;
- GLenum data_format;
- S32 size;
-
- MEM0STRUCT(&texture);
-
- stbi_set_flip_vertically_on_load(1);
- data = stbi_load(fname, &texture.w, &texture.h, &nchannels, 0);
-
- if (!data) {
- sys_printf("[ERROR] : Texture : %s : Failed to load\n", fname);
- goto end;
- }
-
- switch (nchannels) {
- case 1:
- texture.type = TextureType_R;
- internal_format = data_format = GL_RED;
- break;
- case 3:
- texture.type = TextureType_RGB;
- internal_format = (gamma) ? GL_SRGB : GL_RGB;
- data_format = GL_RGB;
- break;
- case 4:
- texture.type = TextureType_RGBA;
- internal_format = (gamma) ? GL_SRGB_ALPHA : GL_RGBA;
- data_format = GL_RGBA;
- break;
- default:
- sys_printf("[ERROR] : Texture : %s : Unsupported type\n", fname);
- goto end;
- }
-
- size = texture.type*texture.w*texture.h;
- texture.data = push_arena(arena, size);
- MEMCPY(texture.data, data, size);
-
- glGenTextures(1, &texture.id);
- glBindTexture(GL_TEXTURE_2D, texture.id);
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.w, texture.h,
- 0, data_format, GL_UNSIGNED_BYTE, texture.data);
- glGenerateMipmap(GL_TEXTURE_2D);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glBindTexture(GL_TEXTURE_2D, 0);
-
- sys_printf("[INFO] : Texture : %s : Loaded successfully\n", fname);
-end:
- stbi_image_free(data);
- return texture;
-}
diff --git a/prge_texture.h b/prge_texture.h
deleted file mode 100644
index d8fe72f..0000000
--- a/prge_texture.h
+++ /dev/null
@@ -1 +0,0 @@
-Texture load_texture(Arena *arena, const char *fname, B32 gamma);
diff --git a/prge_types.h b/prge_types.h
deleted file mode 100644
index a41d110..0000000
--- a/prge_types.h
+++ /dev/null
@@ -1,166 +0,0 @@
-typedef struct {
- S32 w;
- S32 h;
- const char *name;
- U32 flags;
-} PRGEWindow;
-
-typedef enum {
- KeyState_RELEASE = 0,
- KeyState_PRESS = 1
-} KeyStateEnum;
-
-typedef struct {
- KeyStateEnum last;
- KeyStateEnum state;
-} Key;
-
-typedef struct {
- V2 mouse_pos;
- V2 last_mouse_pos;
- V2 mouse_offset;
- B32 first_mouse;
- B32 capture_mouse;
- Key mouse_left;
- Key mouse_right;
-
- F32 dt;
-
- Key move_right;
- Key move_forward;
- Key move_left;
- Key move_backward;
-
- Key move_up;
- Key move_down;
-
- Key jump;
-
- Key action_right;
- Key action_up;
- Key action_left;
- Key action_down;
-
- Key exit;
-} Input;
-
-typedef enum {
- TextureType_R = 1,
- TextureType_RGB = 3,
- TextureType_RGBA = 4
-} TextureTypeEnum;
-
-typedef struct {
- U32 id;
- const char *name;
-
- TextureTypeEnum type;
-
- S32 w;
- S32 h;
-
- U8 *data;
-} Texture;
-
-typedef struct {
- V3 pos;
- V2 texc;
-} Vertex;
-
-#define PRGE_MAX_TEXTURES 2
-#define PRGE_MAX_MESHES 8
-#define PRGE_MAX_MODELS 8
-
-typedef struct {
- U32 id;
- const char *name;
-} Shader;
-
-typedef struct {
- V3 transl;
- V3 rotate;
- V3 scale;
-} Transform;
-
-typedef struct {
- V3 origin;
- V3 rotate;
-
- S32 nverts;
- Vertex *verts;
-
- S32 nindices;
- U32 *indices;
-
- S32 ntextures;
- Texture textures[PRGE_MAX_TEXTURES];
-
- U32 vao, vbo, ebo;
-} Mesh;
-
-typedef struct {
- U32 id;
-
- V3 origin;
- V3 rotate;
-
- S32 nmeshes;
- Mesh *meshes;
-} Model;
-
-typedef struct {
- V3 pos;
-
- F32 fov;
-
- F32 near;
- F32 far;
-
- F32 yaw;
- F32 pitch;
- F32 roll;
-} Camera;
-
-#define PRGE_MAX_SOUNDS_LOADED 4
-#define PRGE_MAX_SOUNDS_PLAYING 2
-
-typedef struct {
- S32 channels;
- S32 sample_rate;
- S32 bytes_per_sample;
-
- S32 size;
- U8 *data;
-
- const char *name;
-} Sound;
-
-typedef struct SoundQueueNode {
- Sound *snd;
- struct SoundQueueNode *next;
- struct SoundQueueNode *prev;
-} SoundQueueNode;
-
-typedef struct {
- S32 cnt;
- struct SoundQueueNode *first;
- struct SoundQueueNode *last;
-} SoundQueue;
-
-typedef struct {
- B32 should_close;
-
- Arena *pa;
- Arena *tmpa;
-
- Input in;
-
- /* TODO(pryazha): Probably a bad idea to have only one window 🙃*/
- PRGEWindow wnd;
-
- Sound snds[PRGE_MAX_SOUNDS_LOADED];
- SoundQueueNode nodes[PRGE_MAX_SOUNDS_PLAYING];
- SoundQueue sndq;
-
- const char *bindir;
-} PRGEContext;
diff --git a/prge_window.c b/prge_window.c
deleted file mode 100644
index f132102..0000000
--- a/prge_window.c
+++ /dev/null
@@ -1,10 +0,0 @@
-PRGEWindow init_window(S32 w, S32 h, const char *name, U32 flags)
-{
- PRGEWindow wnd = {
- .w = w,
- .h = h,
- .name = name,
- .flags = flags
- };
- return wnd;
-}
diff --git a/prge_window.h b/prge_window.h
deleted file mode 100644
index 5d9d086..0000000
--- a/prge_window.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#define PRGE_WINDOW_DEPTH_TEST 0x1
-#define PRGE_WINDOW_MULTISAMPLE 0x10
-
-PRGEWindow init_window(S32 w, S32 h, const char *name, U32 flags);
diff --git a/shader.h b/shader.h
new file mode 100644
index 0000000..189225a
--- /dev/null
+++ b/shader.h
@@ -0,0 +1,105 @@
+shader_t compile_gl_shader(u32 type, char **src)
+{
+ shader_t shader = {0};
+ shader.id = glCreateShader(type);
+ glShaderSource(shader.id, 1, (const char **)src, 0);
+ glCompileShader(shader.id);
+
+ i32 status;
+ glGetShaderiv(shader.id, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE)
+ glGetShaderInfoLog(shader.id, MAX_SHADER_LOG, 0, shader.log);
+ else
+ snprintf(shader.log, MAX_SHADER_LOG, "compiled successfully");
+
+ return shader;
+}
+
+shader_t compile_gl_shader_file(u32 type, const char *filename)
+{
+ char *src;
+ shader_t shader = {0};
+
+ arena_t tmp = alloc_arena(0);
+ if (!sys_read_file(&tmp, &src, filename)) {
+ printf("error: failed to read: \"%s\"\n", filename);
+ release_arena(&tmp);
+ return shader;
+ }
+ shader = compile_gl_shader(type, &src);
+ release_arena(&tmp);
+
+ if (!shader.id)
+ printf("error: \"%s\": ", filename);
+ else
+ printf("info: \"%s\": ", filename);
+ printf("%s", shader.log);
+ printf("\n");
+
+ return shader;
+}
+
+shader_t load_gl_shader(const char *dir, const char *vert_filename, const char *geom_filename, const char *frag_filename)
+{
+ shader_t shader = {0};
+ shader.id = glCreateProgram();
+
+ char full_path[MAX_PATH];
+ shader_t vert;
+ if (vert_filename) {
+ snprintf(full_path, sizeof(full_path), "%s/%s", dir, vert_filename);
+ vert = compile_gl_shader_file(GL_VERTEX_SHADER, full_path);
+ glAttachShader(shader.id, vert.id);
+ }
+
+ shader_t geom;
+ if (geom_filename) {
+ snprintf(full_path, sizeof(full_path), "%s/%s", dir, geom_filename);
+ geom = compile_gl_shader_file(GL_GEOMETRY_SHADER, full_path);
+ glAttachShader(shader.id, geom.id);
+ }
+
+ shader_t frag;
+ if (frag_filename) {
+ snprintf(full_path, sizeof(full_path), "%s/%s", dir, frag_filename);
+ frag = compile_gl_shader_file(GL_FRAGMENT_SHADER, full_path);
+ glAttachShader(shader.id, frag.id);
+ }
+
+ i32 status;
+ glLinkProgram(shader.id);
+ glGetProgramiv(shader.id, GL_LINK_STATUS, &status);
+ if (status == GL_FALSE) {
+ glGetProgramInfoLog(shader.id, MAX_SHADER_LOG, 0, shader.log);
+ printf("error: failed to link shader program:\n%s", shader.log);
+ } else {
+ printf("info: shader linked successfuly\n\n");
+ }
+
+ if (vert_filename)
+ glDeleteShader(vert.id);
+ if (geom_filename)
+ glDeleteShader(geom.id);
+ if (frag_filename)
+ glDeleteShader(frag.id);
+
+ return shader;
+}
+
+void shader_set_v3(shader_t shader, const char *name, v3 vec)
+{
+ i32 location = glGetUniformLocation(shader.id, name);
+ glUniform3fv(location, 1, (f32 *)&vec);
+}
+
+void shader_set_v4(shader_t shader, const char *name, v4 vec)
+{
+ i32 location = glGetUniformLocation(shader.id, name);
+ glUniform4fv(location, 1, (f32 *)&vec);
+}
+
+void shader_set_mat4(shader_t shader, const char *name, mat4 mat)
+{
+ i32 location = glGetUniformLocation(shader.id, name);
+ glUniformMatrix4fv(location, 1, 0, (f32 *)&mat);
+}
diff --git a/texture.h b/texture.h
new file mode 100644
index 0000000..c51e411
--- /dev/null
+++ b/texture.h
@@ -0,0 +1,55 @@
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+texture_t load_texture(arena_t *arena, const char *filename, i32 gamma)
+{
+ texture_t texture = {0};
+ i32 nchannels;
+ stbi_set_flip_vertically_on_load(1);
+ u8 *data = stbi_load(filename, &texture.width, &texture.height, &nchannels, 0);
+ if (!data) {
+ printf("error: \"%s\" failed to load\n", filename);
+ return texture;
+ }
+
+ u32 internal_format, data_format;
+ switch (nchannels) {
+ case 1:
+ texture.type = texture_type_r;
+ internal_format = data_format = GL_RED;
+ break;
+ case 3:
+ texture.type = texture_type_rgb;
+ internal_format = gamma ? GL_SRGB : GL_RGB;
+ data_format = GL_RGB;
+ break;
+ case 4:
+ texture.type = texture_type_rgba;
+ internal_format = gamma ? GL_SRGB_ALPHA : GL_RGBA;
+ data_format = GL_RGBA;
+ break;
+ default:
+ printf("error: \"%s\" unsupported type\n", filename);
+ goto end;
+ }
+
+ u64 size = texture.type * texture.width * texture.height;
+ texture.data = push_arena(arena, size);
+ prb_memmove(texture.data, data, size);
+
+ glGenTextures(1, &texture.id);
+ glBindTexture(GL_TEXTURE_2D, texture.id);
+ glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height,
+ 0, data_format, GL_UNSIGNED_BYTE, texture.data);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ printf("info: \"%s\" loaded successfully\n", filename);
+end:
+ stbi_image_free(data);
+ return texture;
+}
diff --git a/types.h b/types.h
new file mode 100644
index 0000000..6fd5799
--- /dev/null
+++ b/types.h
@@ -0,0 +1,231 @@
+#define WINDOW_DEPTH_TEST 0x1
+#define WINDOW_MULTISAMPLE 0x10
+
+typedef struct {
+ i32 width;
+ i32 height;
+ const char *name;
+ u32 flags;
+} prge_window_t;
+
+typedef enum {
+ key_state_release = 0,
+ key_state_press = 1
+} key_state_enum;
+
+typedef struct {
+ key_state_enum last;
+ key_state_enum state;
+} prge_key_t;
+
+typedef struct {
+ v2 pos;
+ v2 last;
+ v2 offset;
+ i32 first;
+ i32 capture;
+ prge_key_t left;
+ prge_key_t right;
+} mouse_t;
+
+typedef struct {
+ mouse_t mouse;
+
+ prge_key_t move_right;
+ prge_key_t move_forward;
+ prge_key_t move_left;
+ prge_key_t move_backward;
+ prge_key_t move_up;
+ prge_key_t move_down;
+
+ prge_key_t jump;
+ prge_key_t action_right;
+ prge_key_t action_up;
+ prge_key_t action_left;
+ prge_key_t action_down;
+ prge_key_t exit;
+
+ f32 dt;
+} input_t;
+
+typedef enum {
+ texture_type_r = 1,
+ texture_type_rgb = 3,
+ texture_type_rgba = 4
+} texture_type_enum;
+
+typedef struct {
+ u32 id;
+ const char *name;
+ texture_type_enum type;
+ i32 width;
+ i32 height;
+ u8 *data;
+} texture_t;
+
+#define SHADER_POSITION_LOCATION 0
+#define SHADER_NORMAL_LOCATION 1
+#define SHADER_TEXCOORDS_LOCATION 2
+
+#define SHADER_PROJECTION_MATRIX "projection"
+#define SHADER_VIEW_MATRIX "view"
+#define SHADER_MODEL_MATRIX "model"
+
+#define MAX_SHADER_LOG 512
+
+typedef struct {
+ u32 id;
+ char log[MAX_SHADER_LOG];
+} shader_t;
+
+typedef struct {
+ v3 position;
+ v3 normal;
+ v2 texcoords;
+} vertex_t;
+
+#define DEFAULT_TRANSFORM (transform_t){V3_ZERO, V3_ZERO, V3_ONE}
+
+typedef struct {
+ v3 position;
+ v3 rotation;
+ v3 scale;
+} transform_t;
+
+#define MAX_TEXTURE_PER_MESH 2
+
+typedef struct {
+ transform_t transform;
+
+ i32 nvertices;
+ vertex_t *vertices;
+
+ i32 nindices;
+ u32 *indices;
+
+ i32 ntextures;
+ texture_t textures[MAX_TEXTURE_PER_MESH];
+
+ u32 vao;
+ u32 vbo;
+ u32 ebo;
+} mesh_t;
+
+typedef struct {
+ transform_t transform;
+ i32 nmeshes;
+ mesh_t *meshes;
+} model_t;
+
+#define BBOX_UNIT (bbox_t){{-0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, 0.5f}}
+#define BBOX_ZERO (bbox_t){V3_ZERO, V3_ZERO}
+
+typedef struct {
+ v3 start;
+ v3 end;
+} bbox_t;
+
+#define ENTITY_COLLIDE (1)
+#define ENTITY_MOVE (1 << 1)
+#define ENTITY_ALPHA (1 << 2)
+
+typedef struct {
+ u32 flags;
+
+ model_t model;
+
+ v3 position;
+ v3 velocity;
+ bbox_t bbox;
+} entity_t;
+
+#define MAX_ENTITIES 4
+
+typedef struct enode_t {
+ i32 id;
+ entity_t entity;
+ struct enode_t *next;
+ struct enode_t *prev;
+} enode_t;
+
+typedef struct {
+ i32 count;
+ enode_t nodes[MAX_ENTITIES];
+ struct enode_t *first;
+ struct enode_t *last;
+} elist_t;
+
+#define DEFAULT_CAMERA (camera_t){v3_ZERO, 90.0f, 0.1f, 1000.0f, V3_ZERO}
+
+typedef struct {
+ v3 position;
+
+ f32 fov;
+
+ f32 near;
+ f32 far;
+
+ v3 angles;
+} camera_t;
+
+typedef struct {
+ i32 channels;
+ i32 freq;
+ i32 bps;
+
+ i32 size;
+ unsigned char *data;
+
+ const char *name;
+} sound_t;
+
+typedef struct sound_queue_node_t {
+ sound_t *sound;
+ struct sound_queue_node_t *next;
+ struct sound_queue_node_t *prev;
+} sound_queue_node_t;
+
+typedef struct {
+ i32 count;
+ struct sound_queue_node_t *first;
+ struct sound_queue_node_t *last;
+} sound_queue_t;
+
+#define ARENA_SIZE megabytes(64)
+#define FRAME_ARENA_SIZE megabytes(16)
+
+#define MAX_SOUNDS_LOADED 8
+#define MAX_SOUNDS_PLAYING 4
+
+typedef struct {
+ i32 should_close;
+
+ arena_t arena;
+ arena_t frame_arena;
+
+ input_t input;
+
+ /* TODO(pryazha): Probably a bad idea to have only one window 🙃*/
+ prge_window_t window;
+
+ sound_t sounds[MAX_SOUNDS_LOADED];
+ sound_queue_node_t sound_queue_nodes[MAX_SOUNDS_PLAYING];
+ sound_queue_t sound_queue;
+
+ elist_t entities;
+
+ const char *dir;
+} prge_context_t;
+
+typedef enum {ui_list, ui_stack} ui_layout_enum;
+
+typedef struct {
+ prge_window_t window;
+ input_t input;
+ shader_t shader;
+ rect_t rect;
+ ui_layout_enum layout;
+ v2 last;
+ arena_t *arena;
+ f32 padding;
+} ui_t;