summaryrefslogtreecommitdiff
path: root/libs/common.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/common.h')
-rw-r--r--libs/common.h666
1 files changed, 666 insertions, 0 deletions
diff --git a/libs/common.h b/libs/common.h
new file mode 100644
index 0000000..098bc9a
--- /dev/null
+++ b/libs/common.h
@@ -0,0 +1,666 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+#define TINYOBJ_LOADER_C_IMPLEMENTATION
+#include "tinyobj_loader_c.h"
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+U8 *
+read_entire_file(const char *filename) {
+ U8 *result;
+ FILE *f;
+ long file_size;
+
+ result = 0;
+
+ if (!filename) {
+ return(result);
+ }
+
+ f = fopen(filename, "rb");
+ if (!f) {
+ return(result);
+ }
+
+ fseek(f, 0, SEEK_END);
+ file_size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ result = malloc(file_size + 1);
+ fread(result, file_size, 1, f);
+ fclose(f);
+
+ result[file_size] = 0;
+
+ return(result);
+}
+
+void *
+mmap_file(size_t *len, const char *filename)
+{
+ struct stat sb;
+ char* p;
+ int fd;
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ perror("open");
+ return NULL;
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ perror("fstat");
+ return NULL;
+ }
+
+ if (!S_ISREG(sb.st_mode)) {
+ fprintf(stderr, "%s is not a file\n", filename);
+ return NULL;
+ }
+
+ p = (char*)mmap(0, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
+
+ if (p == MAP_FAILED) {
+ perror("mmap");
+ return NULL;
+ }
+
+ if (close(fd) == -1) {
+ perror("close");
+ return NULL;
+ }
+
+ (*len) = sb.st_size;
+
+ return p;
+}
+
+void
+read_entire_file_mmap(void* ctx, const char* filename, const int is_mtl,
+ const char* obj_filename, char** data, size_t* len)
+{
+ if (!filename)
+ {
+ fprintf(stderr, "[ERROR]: Filename not provided (null)\n");
+ *data = 0;
+ *len = 0;
+ return;
+ }
+
+ size_t data_len = 0;
+
+ *data = mmap_file(&data_len, filename);
+ *len = data_len;
+}
+
+Mesh *
+mesh_load_obj(Arena *arena, const char *filename)
+{
+ tinyobj_attrib_t attrib;
+ tinyobj_shape_t *shapes = 0;
+ tinyobj_material_t *materials = 0;
+ size_t num_shapes, num_materials, num_triangles;
+ size_t i, j, face_offset;
+ U32 flags;
+ Mesh *mesh = 0;
+
+ flags = TINYOBJ_FLAG_TRIANGULATE;
+
+ S32 status = tinyobj_parse_obj(&attrib, &shapes, &num_shapes,
+ &materials, &num_materials, filename,
+ read_entire_file_mmap, 0, flags);
+ if (status != TINYOBJ_SUCCESS)
+ {
+ fprintf(stderr, "[ERROR]: Failed to parse \"%s\"\n", filename);
+ if (status == TINYOBJ_ERROR_INVALID_PARAMETER)
+ fprintf(stderr, "[ERROR]: TINYOBJ_ERROR_INVALID_PARAMETER\n");
+ return(mesh);
+ }
+
+ num_triangles = attrib.num_face_num_verts;
+ face_offset = 0;
+
+ Vertex *vertices = arena_push_size(arena, sizeof(Vertex)*num_triangles*3);
+ U32 *indices = arena_push_size(arena, num_triangles*3*sizeof(U32));
+ U32 vertex_count = 0;
+ U32 index_count = 0, index_index = 0;
+ for (i = 0; i < attrib.num_face_num_verts; ++i)
+ {
+ tinyobj_vertex_index_t idx;
+ V3F pos, normal;
+ V2F tex_coords;
+
+ Assert(attrib.face_num_verts[i]%3 == 0);
+
+ Assert(attrib.face_num_verts[i]/3 > 3);
+
+ Assert(attrib.num_texcoords);
+
+ for (j = 0; j < 3; ++j)
+ {
+ idx = attrib.faces[face_offset+j];
+ Assert(idx.v_idx >= 0);
+ pos = v3f(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 < (S32)attrib.num_normals);
+ normal = v3f(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 < (S32)attrib.num_texcoords);
+ tex_coords = v2f(attrib.texcoords[2*idx.vt_idx+0],
+ attrib.texcoords[2*idx.vt_idx+1]);
+
+ vertices[vertex_count++] = vertex(pos, normal, tex_coords);
+ Assert(index_count < attrib.num_faclibe_num_verts);
+ indices[index_index++] = index_count++;
+ }
+
+ face_offset += 3;
+ }
+
+ mesh = mesh_init(arena, vertices, vertex_count,
+ indices, num_triangles*3);
+
+ tinyobj_attrib_free(&attrib);
+ tinyobj_shapes_free(shapes, num_shapes);
+ tinyobj_materials_free(materials, num_materials);
+
+ return(mesh);
+}
+
+U32
+compile_shader(GLenum type, const char *filename)
+{
+ U32 shader;
+ S32 status;
+ char logs[512];
+
+ const char *source = (const char *)read_entire_file(filename);
+ if (!source) {
+ fprintf(stderr, "[ERROR]: Failed to read the file \"%s\"\n", filename);
+ return(0);
+ }
+
+ shader = glCreateShader(type);
+ glShaderSource(shader, 1, &source, 0);
+ free((void *)source);
+ glCompileShader(shader);
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status == GL_FALSE) {
+ glGetShaderInfoLog(shader, 512, 0, logs);
+ fprintf(stderr, "[ERROR]: Failed to compile: \"%s\"\n%s", filename, logs);
+ } else {
+ fprintf(stdout, "[INFO]: \"%s\" compiled successfuly.\n", filename);
+ }
+ return(shader);
+}
+
+U32
+create_shader_program(char *vertex_shader_filename,
+ char *fragment_shader_filename)
+{
+ S32 success;
+ char logs[512];
+
+ U32 vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_filename);
+ U32 fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_filename);
+
+ U32 shader_program;
+ shader_program = glCreateProgram();
+ glAttachShader(shader_program, vertex_shader);
+ glAttachShader(shader_program, fragment_shader);
+ glLinkProgram(shader_program);
+ glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
+ if (success == GL_FALSE) {
+ glGetProgramInfoLog(shader_program, 512, 0, logs);
+ fprintf(stderr, "[ERROR]: Failed to link shader program:\n%s",
+ logs);
+ } else {
+ fprintf(stdout, "[INFO]: Shader program linked successfuly.\n\n");
+ }
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+
+ return(shader_program);
+}
+
+U32
+create_shader_program_geom(char *vertex_shader_filename,
+ char *fragment_shader_filename,
+ char *geometry_shader_filename)
+{
+ S32 success;
+ char logs[512];
+
+ U32 vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_filename);
+ U32 fragment_shader = compile_shader(GL_FRAGMENT_SHADER, fragment_shader_filename);
+ U32 geometry_shader = compile_shader(GL_GEOMETRY_SHADER, geometry_shader_filename);
+
+ U32 shader_program;
+ shader_program = glCreateProgram();
+ glAttachShader(shader_program, vertex_shader);
+ glAttachShader(shader_program, fragment_shader);
+ glAttachShader(shader_program, geometry_shader);
+ glLinkProgram(shader_program);
+ glGetProgramiv(shader_program, GL_LINK_STATUS, &success);
+ if (success == GL_FALSE) {
+ glGetProgramInfoLog(shader_program, 512, 0, logs);
+ fprintf(stderr, "[ERROR]: Failed to link shader program:\n%s",
+ logs);
+ } else {
+ fprintf(stdout, "[INFO]: Shader program linked successfuly.\n\n");
+ }
+ glDeleteShader(vertex_shader);
+ glDeleteShader(fragment_shader);
+ glDeleteShader(geometry_shader);
+
+ return(shader_program);
+}
+
+void
+shader_set_3f(U32 shader_program, char *uniform_name, F32 x, F32 y, F32 z)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniform3f(uniform_location, x, y, z);
+}
+
+void
+shader_set_1f(U32 shader_program, char *uniform_name, F32 value)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniform1f(uniform_location, value);
+}
+
+void
+shader_set_3fv(U32 shader_program, char *uniform_name, V3F value)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniform3fv(uniform_location, 1, (const GLfloat *)&value);
+}
+
+void
+shader_set_2fv(U32 shader_program, char *uniform_name, V2F value)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniform2fv(uniform_location, 1, (const GLfloat *)&value);
+}
+
+void
+shader_set_mat4fv(U32 shader_program, char *uniform_name, MAT4 value)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniformMatrix4fv(uniform_location, 1, GL_FALSE, (F32 *)&value);
+}
+
+void
+shader_set_1i(U32 shader_program, char *uniform_name, S32 value)
+{
+ U32 uniform_location = glGetUniformLocation(shader_program, uniform_name);
+ glUniform1i(uniform_location, value);
+}
+
+U32
+load_texture(char *texture_filename)
+{
+ S32 width, height, number_channels;
+ U32 texture_id;
+
+ glGenTextures(1, &texture_id);
+
+ stbi_set_flip_vertically_on_load(1);
+ U8 *data = stbi_load(texture_filename, &width, &height, &number_channels, 0);
+ if (data) {
+ GLenum format = 0;
+ if (number_channels == 1)
+ format = GL_RED;
+ else if (number_channels == 3)
+ format = GL_RGB;
+ else if (number_channels == 4)
+ format = GL_RGBA;
+
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format,
+ GL_UNSIGNED_BYTE, 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);
+
+ fprintf(stdout, "[INFO]: Texture (\"%s\") is loaded successfully\n",
+ texture_filename);
+ } else {
+ fprintf(stderr, "[ERROR]: Failed to load texture: \"%s\"\n",
+ texture_filename);
+ }
+ stbi_image_free(data);
+
+ return(texture_id);
+}
+
+U32
+load_cubemap(const char *texture_filenames[6])
+{
+ U32 texture_id;
+ glGenTextures(1, &texture_id);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, texture_id);
+ S32 width, height, number_channels;
+ U8 *data = 0;
+ stbi_set_flip_vertically_on_load(0);
+ for (U32 texture_index = 0;
+ texture_index < 6;
+ ++texture_index)
+ {
+ data = stbi_load(texture_filenames[texture_index], &width, &height,
+ &number_channels, 0);
+ if (data) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+texture_index, 0, GL_RGB,
+ width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
+ fprintf(stdout, "[INFO]: Texture (\"%s\") is loaded successfully\n",
+ texture_filenames[texture_index]);
+ } else {
+ fprintf(stderr, "[ERROR]: Failed to load texture: \"%s\"\n",
+ texture_filenames[texture_index]);
+ }
+ stbi_image_free(data);
+ }
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ return(texture_id);
+}
+
+typedef struct {
+ V3F translate;
+ V3F scale;
+ V3F rotate;
+} Transform;
+
+enum KeyState_Enum {
+ KeyState_RELEASE = 0,
+ KeyState_PRESS = 1
+};
+
+typedef struct {
+ enum KeyState_Enum last;
+ enum KeyState_Enum state;
+} Key;
+
+typedef struct {
+ 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;
+ V2F last_mouse_pos;
+ V2F mouse_offset;
+} Input;
+
+void
+input_update_last_state(Input *input)
+{
+ 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;
+}
+
+B32
+key_is_pressed(Key key)
+{
+ B32 result = (key.state == KeyState_PRESS);
+ return(result);
+}
+
+B32
+key_first_press(Key key)
+{
+ B32 result = ((key.last == KeyState_RELEASE) &&
+ (key.state == KeyState_PRESS));
+ return(result);
+}
+
+B32
+key_was_pressed(Key key)
+{
+ B32 result = ((key.last == KeyState_PRESS) &&
+ (key.state == KeyState_RELEASE));
+ return(result);
+}
+
+MAT4
+mat4_change_basis(V3F x, V3F y, V3F z)
+{
+ MAT4 result = mat4_identity();
+ result.m0 = v4f(x.x, x.y, x.z, 0.0f);
+ result.m1 = v4f(y.x, y.y, y.z, 0.0f);
+ result.m2 = v4f(z.x, z.y, z.z, 0.0f);
+ return(result);
+}
+
+/*
+ * NOTE(pryazha): angles in degrees
+ * | 1 0 0 | | cy 0 sy | | cz -sz 0 | | cy*cz -cy*sz sy |
+ * | 0 cx -sx |*| 0 1 0 |*| sz cz 0 |=| sx*sy*cz+cx*sz -sx*sy*sz+cx*cz -sx*cy |
+ * | 0 sx cx | | -sy 0 cy | | 0 0 1 | | -cx*sy*cz+sx*sz cx*sy*sz+sx*cz cx*cy |
+ */
+MAT4
+mat4_make_rotate(V3F angles)
+{
+ F32 angle, cx, sx, cy, sy, cz, sz;
+ MAT4 result;
+ V3F newx, newy, newz;
+
+ angle = DEG2RAD*angles.x;
+ cx = f32_cos(angle);
+ sx = f32_sin(angle);
+ angle = DEG2RAD*angles.y;
+ cy = f32_cos(angle);
+ sy = f32_sin(angle);
+ angle = DEG2RAD*angles.z;
+ cz = f32_cos(angle);
+ sz = f32_sin(angle);
+
+ newx = v3f(cy*cz, sx*sy*cz+cx*sz, -cx*sy*cz+sx*sz);
+ newy = v3f(-cy*sz, -sx*sy*sz+cx*cz, cx*sy*sz+sx*cz);
+ newz = v3f(sy, -sx*cy, cx*cy);
+ result = mat4_change_basis(newx, newy, newz);
+
+ return(result);
+}
+
+MAT4
+mat4_rotate_angles(MAT4 source, V3F angles)
+{
+ MAT4 rotate = mat4_make_rotate(angles);
+ MAT4 result = mat4_mul(rotate, source);
+ return(result);
+}
+
+Transform
+transform_make(V3F translate, V3F scale, V3F rotate)
+{
+ Transform result;
+ result.translate = translate;
+ result.scale = scale;
+ result.rotate = rotate;
+ return(result);
+}
+
+Transform
+transform_default()
+{
+ Transform result = transform_make(v3f_zero(), v3f_one(), v3f_zero());
+ return(result);
+}
+
+Transform
+transform_make_translate(V3F translate)
+{
+ Transform result = transform_default();
+ result.translate = translate;
+ return(result);
+}
+
+Transform
+transform_make_scale(V3F scale)
+{
+ Transform result = transform_default();
+ result.scale = scale;
+ return(result);
+}
+
+Transform
+transform_make_rotate(V3F angles)
+{
+ Transform result = transform_default();
+ result.rotate = angles;
+ return(result);
+}
+
+Transform
+transform_translate(Transform source, V3F translate)
+{
+ Transform result = source;
+ result.translate = v3f_add(source.translate, translate);
+ return(result);
+}
+
+Transform
+transform_scale(Transform source, V3F scale)
+{
+ Transform result = source;
+ result.scale = v3f_dot(source.scale, scale);
+ return(result);
+}
+
+Transform
+transform_rotate(Transform source, V3F angles)
+{
+ Transform result;
+ result.translate = source.translate;
+ result.scale = source.scale;
+ result.rotate = v3f_add(source.rotate, angles);
+ return(result);
+}
+
+Transform
+transform_make_scale_translate(V3F scale, V3F translate)
+{
+ Transform result = transform_default();
+ result.translate = translate;
+ result.scale = scale;
+ return(result);
+}
+
+MAT4
+transform_apply(Transform transform)
+{
+ MAT4 result = mat4_identity();
+ MAT4 translate = mat4_make_translate(transform.translate);
+ MAT4 scale = mat4_make_scale(transform.scale);
+ MAT4 rotate = mat4_make_rotate(transform.rotate);
+ result = mat4_mul(mat4_mul(translate, scale), rotate);
+ return(result);
+}
+
+MAT4
+ortho(F32 l, F32 r, F32 b, F32 t, F32 n, F32 f)
+{
+ MAT4 result = mat4_identity();
+ result.m0.x = 2.0f/(r-l);
+ result.m1.y = 2.0f/(t-b);
+ result.m2.z = -2.0f/(f-n);
+ result.m3.x = -(r+l)/(r-l);
+ result.m3.y = -(t+b)/(t-b);
+ result.m3.z = -(f+n)/(f-n);
+ return(result);
+}
+
+MAT4
+perspective(F32 fovx, F32 ar, F32 n, F32 f)
+{
+ F32 r = n*f32_tan(fovx/2.0f*DEG2RAD);
+ F32 t = r/ar;
+ MAT4 result = mat4_identity();
+ result.m0.x = n/r;
+ result.m1.y = n/t;
+ result.m2.z = -(f+n)/(f-n);
+ result.m2.w = -1.0f;
+ result.m3.z = (-2.0f*f*n)/(f-n);
+ result.m3.w = 0.0f;
+ return(result);
+}
+
+MAT4
+look_at(V3F eye, V3F target, V3F up)
+{
+ V3F f = v3f_norm(v3f_sub(eye, target));
+ V3F l = v3f_norm(v3f_cross(up, f));
+ V3F u = v3f_cross(f, l);
+ MAT4 translate = mat4_make_translate(v3f_negate(eye));
+ MAT4 rotate = mat4_change_basis(l, u, f);
+ MAT4 result = mat4_mul(mat4_transpose(rotate), translate);
+ return(result);
+}
+
+V3F
+update_camera_pos_orbital(Input input, V3F pos, V3F target,
+ F32 dt, F32 speed)
+{
+ V3F up, f, l, u, dp, new_pos;
+
+ up = v3f(0.0f, 1.0f, 0.0f);
+ f = v3f_norm(v3f_sub(target, pos));
+ l = v3f_norm(v3f_cross(up, f));
+ u = v3f_cross(f, l);
+
+ dp = v3f_zero();
+
+ if (key_is_pressed(input.move_right))
+ dp = v3f_sub(dp, l);
+ if (key_is_pressed(input.move_forward))
+ dp = v3f_add(dp, f);
+ if (key_is_pressed(input.move_left))
+ dp = v3f_add(dp, l);
+ if (key_is_pressed(input.move_backward))
+ dp = v3f_sub(dp, f);
+ if (key_is_pressed(input.move_up))
+ dp = v3f_add(dp, u);
+ if (key_is_pressed(input.move_down))
+ dp = v3f_sub(dp, u);
+
+ new_pos = v3f_add(pos, v3f_scalef(dp, speed*dt));
+
+ return(new_pos);
+}
+
+#endif /* COMMON_H */