diff options
-rw-r--r-- | audio.h | 68 | ||||
-rw-r--r-- | camera.h | 69 | ||||
-rw-r--r-- | ctx.h | 39 | ||||
-rw-r--r-- | draw.h | 92 | ||||
-rw-r--r-- | gui.h | 67 | ||||
-rw-r--r-- | input.h | 46 | ||||
-rw-r--r-- | model.h | 246 | ||||
-rw-r--r-- | phys.h | 95 | ||||
-rw-r--r-- | prge.h | 51 | ||||
-rw-r--r-- | prge_audio.c | 75 | ||||
-rw-r--r-- | prge_audio.h | 6 | ||||
-rw-r--r-- | prge_camera.c | 99 | ||||
-rw-r--r-- | prge_camera.h | 7 | ||||
-rw-r--r-- | prge_draw.c | 78 | ||||
-rw-r--r-- | prge_draw.h | 8 | ||||
-rw-r--r-- | prge_gui.c | 60 | ||||
-rw-r--r-- | prge_gui.h | 6 | ||||
-rw-r--r-- | prge_input.c | 51 | ||||
-rw-r--r-- | prge_input.h | 5 | ||||
-rw-r--r-- | prge_model.c | 187 | ||||
-rw-r--r-- | prge_model.h | 11 | ||||
-rw-r--r-- | prge_shader.c | 93 | ||||
-rw-r--r-- | prge_shader.h | 12 | ||||
-rw-r--r-- | prge_texture.c | 59 | ||||
-rw-r--r-- | prge_texture.h | 1 | ||||
-rw-r--r-- | prge_types.h | 166 | ||||
-rw-r--r-- | prge_window.c | 10 | ||||
-rw-r--r-- | prge_window.h | 4 | ||||
-rw-r--r-- | shader.h | 105 | ||||
-rw-r--r-- | texture.h | 55 | ||||
-rw-r--r-- | types.h | 231 |
31 files changed, 1124 insertions, 978 deletions
@@ -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; +} @@ -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); +} @@ -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); +} @@ -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); +} @@ -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; +} @@ -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; +} @@ -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)) { + + } + } + } + } +} +*/ @@ -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; +} @@ -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; |