diff options
Diffstat (limited to 'libs/common.h')
-rw-r--r-- | libs/common.h | 527 |
1 files changed, 389 insertions, 138 deletions
diff --git a/libs/common.h b/libs/common.h index 2fbed3d..72b44e7 100644 --- a/libs/common.h +++ b/libs/common.h @@ -14,6 +14,27 @@ #include "pwyazh.h" +void die(const char *fmt, ...) +{ + fprintf(stderr, "error: "); + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + fprintf(stderr, "\n"); + exit(1); +} + +void info(const char *fmt, ...) +{ + printf("info: "); + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + char *read_entire_file(const char *filename) { char *result = 0; @@ -74,6 +95,120 @@ void *mmap_file(size_t *len, const char *filename) return p; } +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); +} + +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); +} + +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; + B32 first_mouse; +} Input; + +typedef struct { + V3F pos; + F32 fovx; + F32 near; + F32 far; + + /* NOTE(pryazha): In degrees */ + F32 yaw; + F32 pitch; +} Camera; + +typedef struct { + Arena *arena; + Input input; + Camera camera; + GLFWwindow *window; + S32 width; + S32 height; +} state_t; + +Input input_init() +{ + Input input = {0}; + input.first_mouse = 1; + return(input); +} + +state_t init_state(S32 width, S32 height) +{ + state_t state = { + .arena = arena_alloc(Megabytes(64)), + .input = input_init(), + .camera = { + .pos = v3f(0.0f, 1.0f, 5.0f), + .fovx = 90.0f, + .near = 0.1f, + .far = 100.0f, + .yaw = 0.0f, + .pitch = 0.0f + }, + .width = width, + .height = height + }; + return state; +} + void read_entire_file_mmap(void* ctx, const char* filename, const int is_mtl, const char* obj_filename, char** data, size_t* len) { @@ -243,14 +378,18 @@ U32 load_shader(const char *vert_filename, const char *frag_filename) U32 load_shader_geom(const char *vert_filename, const char *frag_filename, const char *geom_filename) { - U32 vert = compile_shader(GL_VERTEX_SHADER, vert_filename); - U32 frag = compile_shader(GL_FRAGMENT_SHADER, frag_filename); - U32 geom = compile_shader(GL_GEOMETRY_SHADER, geom_filename); + U32 vert, frag, geom; + + vert = compile_shader(GL_VERTEX_SHADER, vert_filename); + frag = compile_shader(GL_FRAGMENT_SHADER, frag_filename); + if (geom_filename) + geom = compile_shader(GL_GEOMETRY_SHADER, geom_filename); U32 program = glCreateProgram(); glAttachShader(program, vert); glAttachShader(program, frag); - glAttachShader(program, geom); + if (geom_filename) + glAttachShader(program, geom); glLinkProgram(program); S32 success; @@ -259,12 +398,11 @@ U32 load_shader_geom(const char *vert_filename, const char *frag_filename, const char log[512]; glGetProgramInfoLog(program, 512, 0, log); fprintf(stderr, "error: failed to link shader program:\n%s\n", log); - } else { - fprintf(stdout, "info: shader program linked successfuly.\n\n"); } glDeleteShader(vert); glDeleteShader(frag); - glDeleteShader(geom); + if (geom_filename) + glDeleteShader(geom); return(program); } @@ -305,6 +443,78 @@ void shader_set_1i(U32 shader_program, char *uniform_name, S32 value) glUniform1i(uniform_location, value); } +typedef struct { + S32 loaded; + U32 id; + char *name; +} shader_t; + +#define MAX_SHADERS 8 +shader_t shaders[MAX_SHADERS] = {0}; + +void add_shader(const char *vert_filename, const char *frag_filename, const char *geom_filename) +{ + if (!vert_filename) { + info("vertex shader filename not specified"); + return; + } + const char *dot = strrchr(vert_filename, '.'); + if (!dot) { + info("shader \"%s\" was not loaded .vert or .vs expected for vertex shader", vert_filename); + return; + } + U64 len = dot - vert_filename; + char *name = malloc(len + 1); + memmove(name, vert_filename, len); + name[len] = '\0'; + for (S32 i = 0; i < MAX_SHADERS; i++) { + if (!shaders[i].loaded) { + shaders[i].loaded = 1; + shaders[i].id = load_shader_geom(vert_filename, frag_filename, geom_filename); + if (!shaders[i].id) die("failed to load shader \"%s\"", name); + shaders[i].name = name; + info("shader \"%s\" loaded successfully", name); + return; + } + } + info("max shaders reached, can't load \"%s\"", name); +} + +void remove_shader(const char *name) +{ + S32 i; + for (i = 0; i < MAX_SHADERS; i++) { + shader_t *shader = shaders + i; + if (shader->name && !strcmp(name, shader->name)) { + free(shader->name); + glDeleteProgram(shader->id); + memset(shader, 0, sizeof(shader_t)); + return; + } + } + info("failed to find shader \"%s\"", name); +} + +U32 find_shader(const char *name) +{ + for (S32 i = 0; i < MAX_SHADERS; i++) { + shader_t *shader = shaders + i; + if (shader->name && !strcmp(name, shader->name)) { + return shader->id; + } + } + return 0; +} + +void list_shaders(void) +{ + info("-----------------------"); + for (S32 i = 0; i < MAX_SHADERS; i++) + info("loaded = %d, id = %d, name = \"%s\"", + shaders[i].loaded, shaders[i].id, shaders[i].name); + info("-----------------------"); +} + U32 load_texture(char *texture_filename) { U32 texture_id; @@ -410,45 +620,116 @@ U32 load_cubemap(const char *texture_filenames[6]) return(texture_id); } -typedef struct { - V3F translate; - V3F scale; - V3F rotate; -} Transform; +U32 load_hdr_texture(const char *filename) +{ + U32 id = 0; -enum KeyState_Enum { - KeyState_RELEASE = 0, - KeyState_PRESS = 1 -}; + stbi_set_flip_vertically_on_load(1); + S32 width, height, number_channels; + F32 *data = stbi_loadf(filename, &width, &height, &number_channels, 0); + if (data) { + glGenTextures(1, &id); -typedef struct { - enum KeyState_Enum last; - enum KeyState_Enum state; -} Key; + glBindTexture(GL_TEXTURE_2D, id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); -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; - B32 first_mouse; -} Input; + info("texture (\"%s\") is loaded successfully", filename); + } else { + info("failed to load texture: \"%s\"", filename); + } + stbi_image_free(data); -Input input_init() + return id; +} + +void init_glfw(state_t *state) { + if (glfwInit() == GLFW_FALSE) + die("failed to initialize glfw"); + + GLFWmonitor* monitor = glfwGetPrimaryMonitor(); + if (!monitor) + die("failed to get primary monitor"); + + S32 xpos = 0; + S32 ypos = 0; + S32 monitor_width = 0; + S32 monitor_height = 0; + glfwGetMonitorWorkarea(monitor, &xpos, &ypos, &monitor_width, &monitor_height); + + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); + glfwWindowHint(GLFW_POSITION_X, xpos + monitor_width / 2.0f - state->width / 2.0f); + glfwWindowHint(GLFW_POSITION_Y, ypos + monitor_height / 2.0f - state->height / 2.0f); + + state->window = glfwCreateWindow(state->width, state->height, "prb lighting", 0, 0); + if (!state->window) + die("failed to create window"); + + glfwSetInputMode(state->window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + + glfwMakeContextCurrent(state->window); + + glfwSwapInterval(0); +} + +void init_gl(void) { - Input input = {0}; - input.first_mouse = 1; - return(input); + if (glewInit() != GLEW_OK) + die("failed to initialize glew"); + glEnable(GL_DEPTH_TEST); +} + +F32 lock_framerate(F32 fps) +{ + static F32 last = 0; + if (!last) + last = glfwGetTime(); + F32 elapsed = (glfwGetTime() - last) * 1000.0f; + F32 target = 1000.0f / fps; + if (elapsed < target) { + U32 to_sleep = (U32)(target - elapsed - 1) * 1000; + if (to_sleep > 0) + usleep(to_sleep); + while (((glfwGetTime() - last) * 1000.0f) < target) + ; + } + F32 current = glfwGetTime(); + F32 dt = current - last; + last = current; + return dt; +} + +void fps_info(F32 dt, S32 again) +{ + static F32 time = 0; + static S32 lastsec = 0; + static F32 sumdt = 0; + static S32 sumfps = 0; + static F32 frame_count = 0; + time += dt; + sumdt += dt; + sumfps += (S32)(1.0f / dt); + frame_count++; + S32 sec = (S32)time; + if (sec != 0 && sec % again == 0) { + if (lastsec != sec) { + F32 mean_dt = sumdt / frame_count; + F32 mean_fps = sumfps / frame_count; + info("time: %d dt: %f fps: %f", sec, mean_dt, mean_fps); + lastsec = sec; + sumdt = 0; + sumfps = 0; + frame_count = 0; + } + } } void input_update_last_state(Input *input) @@ -504,12 +785,6 @@ void process_glfw_mouse_pos(GLFWwindow *window, Input *input) input->last_mouse_pos = v2f((F32)xpos, (F32)ypos); } - -void error_callback(int error, const char *desc) -{ - fprintf(stderr, "[ERROR]: %d %s\n", error, desc); -} - B32 key_is_pressed(Key key) { B32 result = (key.state == KeyState_PRESS); @@ -530,52 +805,84 @@ B32 key_was_pressed(Key key) return(result); } -MAT4 mat4_change_basis(V3F x, V3F y, V3F z) +void handle_glfw_events(GLFWwindow *window, Input *input) { - 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); + input_update_last_state(input); + glfwPollEvents(); + process_glfw_keyboard(window, input); + process_glfw_mouse_pos(window, input); + if (key_first_press(input->exit)) + glfwSetWindowShouldClose(window, GLFW_TRUE); } -/* - * 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) +MAT4 get_view_matrix(Camera *camera) { - F32 angle, cx, sx, cy, sy, cz, sz; - MAT4 result; - V3F newx, newy, newz; + MAT4 view; + view = mat4_make_translate(v3f_negate(camera->pos)); + view = mat4_rotate_angles(view, v3f(camera->pitch, camera->yaw, 0.0f)); + return(view); +} - 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); +void get_camera_vectors(Camera *camera, V3F *l, V3F *u, V3F *f) +{ + MAT4 view; + view = get_view_matrix(camera); + *l = v3f(-view.m0.x, -view.m1.x, -view.m2.x); + *u = v3f(view.m0.y, view.m1.y, view.m2.y); + *f = v3f(-view.m0.z, -view.m1.z, -view.m2.z); +} - 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); +V3F get_dv_camera_first_person(Input *input, Camera *camera, F32 acceleration, F32 dt) +{ + V3F f, l, u, dv; + get_camera_vectors(camera, &l, &u, &f); - return(result); + dv = v3f_zero(); + + if (key_is_pressed(input->move_right)) + dv = v3f_sub(dv, l); + if (key_is_pressed(input->move_forward)) + dv = v3f_add(dv, f); + if (key_is_pressed(input->move_left)) + dv = v3f_add(dv, l); + if (key_is_pressed(input->move_backward)) + dv = v3f_sub(dv, f); + if (key_is_pressed(input->move_up)) + dv = v3f_add(dv, u); + if (key_is_pressed(input->move_down)) + dv = v3f_sub(dv, u); + + dv = v3f_norm(dv); + + dv = v3f_scalef(dv, acceleration*dt); + + return(dv); } -MAT4 mat4_rotate_angles(MAT4 source, V3F angles) +void update_camera_first_person(Camera *camera, Input *input, F32 dt, F32 speed) { - MAT4 rotate = mat4_make_rotate(angles); - MAT4 result = mat4_mul(rotate, source); - return(result); + V3F a = get_dv_camera_first_person(input, camera, speed, dt); + static V3F v = {0.0f, 0.0f, 0.0f}; + v = v3f_add(v, a); + v = v3f_scalef(v, 0.8f); + camera->pos = v3f_add(camera->pos, v); + + F32 sensitivity = 0.1f; + input->mouse_offset = v2f_scalef(input->mouse_offset, sensitivity); + camera->yaw += input->mouse_offset.x; + camera->pitch += input->mouse_offset.y; + if (camera->pitch > 89.0f) + camera->pitch = 89.0f; + if (camera->pitch < -89.0f) + camera->pitch = -89.0f; } +typedef struct { + V3F translate; + V3F scale; + V3F rotate; +} Transform; + Transform transform_make(V3F translate, V3F scale, V3F rotate) { Transform result; @@ -690,27 +997,7 @@ MAT4 look_at(V3F eye, V3F target, V3F up) return(result); } -typedef struct { - V3F pos; - F32 fovx; - F32 near; - F32 far; - - /* NOTE(pryazha): In degrees */ - F32 yaw; - F32 pitch; -} Camera; - -MAT4 get_view_matrix(Camera *camera) -{ - MAT4 view; - view = mat4_make_translate(v3f_negate(camera->pos)); - view = mat4_rotate_angles(view, v3f(camera->pitch, camera->yaw, 0.0f)); - return(view); -} - -V3F get_dv_camera_orbital(Input *input, V3F pos, V3F target, - F32 dt, F32 acceleration) +V3F get_dv_camera_orbital(Input *input, V3F pos, V3F target, F32 dt, F32 acceleration) { V3F up, f, l, u, dv; @@ -741,42 +1028,6 @@ V3F get_dv_camera_orbital(Input *input, V3F pos, V3F target, return(dv); } -void get_camera_vectors(Camera *camera, V3F *l, V3F *u, V3F *f) -{ - MAT4 view; - view = get_view_matrix(camera); - *l = v3f(-view.m0.x, -view.m1.x, -view.m2.x); - *u = v3f(view.m0.y, view.m1.y, view.m2.y); - *f = v3f(-view.m0.z, -view.m1.z, -view.m2.z); -} - -V3F get_dv_camera_first_person(Input *input, Camera *camera, F32 acceleration, F32 dt) -{ - V3F f, l, u, dv; - get_camera_vectors(camera, &l, &u, &f); - - dv = v3f_zero(); - - if (key_is_pressed(input->move_right)) - dv = v3f_sub(dv, l); - if (key_is_pressed(input->move_forward)) - dv = v3f_add(dv, f); - if (key_is_pressed(input->move_left)) - dv = v3f_add(dv, l); - if (key_is_pressed(input->move_backward)) - dv = v3f_sub(dv, f); - if (key_is_pressed(input->move_up)) - dv = v3f_add(dv, u); - if (key_is_pressed(input->move_down)) - dv = v3f_sub(dv, u); - - dv = v3f_norm(dv); - - dv = v3f_scalef(dv, acceleration*dt); - - return(dv); -} - MAT4 camera_persp(Camera camera, F32 ar) { MAT4 result; |