diff options
author | pryazha <pryadeiniv@mail.ru> | 2025-01-19 17:33:44 +0500 |
---|---|---|
committer | pryazha <pryadeiniv@mail.ru> | 2025-01-19 17:33:44 +0500 |
commit | bd49bd525f4c6c6c15c4142bf42d1dd38be6fc16 (patch) | |
tree | 9e69f473c34b53e9e57d8af1873c39698bf5c80e /libs/common.h |
initial commit
Diffstat (limited to 'libs/common.h')
-rw-r--r-- | libs/common.h | 666 |
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 */ |