summaryrefslogtreecommitdiff
path: root/libs/common.h
diff options
context:
space:
mode:
Diffstat (limited to 'libs/common.h')
-rw-r--r--libs/common.h527
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;