From 950fb4d353f4046b618eaae47c3ef75d68c01917 Mon Sep 17 00:00:00 2001 From: Kevin Jerebica Date: Tue, 8 Oct 2024 19:43:14 +0200 Subject: [PATCH] feat: introduce camera interface --- Makefile | 3 +- camera.c | 72 ++++++++++++++++++++++ dev.c | 7 +++ include/camera.h | 32 ++++++++++ include/math.h | 1 - include/object.h | 15 ++--- include/rendlib.h | 1 + math.c | 29 --------- object.c | 148 ++++++++++++++++++++++----------------------- rendlib.c | 149 ++++++++++++++-------------------------------- 10 files changed, 235 insertions(+), 222 deletions(-) create mode 100644 camera.c create mode 100644 include/camera.h diff --git a/Makefile b/Makefile index f7ca625..e9201c1 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,8 @@ all: $(CC) $(CFLAGS) -c rendlib.c -o $(OUT)/rendlib.o $(LFLAGS) $(CC) $(CFLAGS) -c math.c -o $(OUT)/math.o $(LFLAGS) $(CC) $(CFLAGS) -c object.c -o $(OUT)/object.o $(LFLAGS) - $(LD) -relocatable $(OUT)/rendlib.o $(OUT)/math.o $(OUT)/object.o -o $(OUT)/rendlib + $(CC) $(CFLAGS) -c camera.c -o $(OUT)/camera.o $(LFLAGS) + $(LD) -relocatable $(OUT)/rendlib.o $(OUT)/math.o $(OUT)/object.o $(OUT)/camera.o -o $(OUT)/rendlib dev: all $(CC) $(CFLAGS) dev.c $(OUT)/rendlib -o $(OUT)/dev $(LFLAGS) diff --git a/camera.c b/camera.c new file mode 100644 index 0000000..204a46d --- /dev/null +++ b/camera.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "include/camera.h" + +struct camera *create_camera(int type) { + if (type != CAMERA_PERSPECTIVE && + type != CAMERA_ORTHOGONAL) { + return NULL; + } + + struct camera *c = malloc(sizeof(struct camera)); + if (c == NULL) { + return NULL; + } + + memset(c, 0, sizeof(struct camera)); + + c->type = type; + c->fov = 80.0f; + c->near_z = 0.01f; + c->far_z = 1000.0f; + c->yaw = -90.0f; + c->pitch = 0.0f; + c->sensitivity = 0.02f; + + if (c->type == CAMERA_ORTHOGONAL) { + c->viewport_modifier = 0.5f; + } + + c->pos[0] = 0.0f; + c->pos[1] = 0.0f; + c->pos[2] = 10.0f; + + c->front[0] = 0.0f; + c->front[1] = 0.0f; + c->front[2] = -1.0f; + + c->up[0] = 0.0f; + c->up[1] = 1.0f; + c->up[2] = 0.0f; + + return c; +} + +int bake_camera(struct camera *c) { + glm_mat4_identity(c->view); + glm_vec3_add(c->pos, c->front, c->center); + glm_lookat(c->pos, c->center, c->up, c->view); + + glm_mat4_identity(c->projection); + + int screen_viewport[4]; + glGetIntegerv(GL_VIEWPORT, screen_viewport); + if (c->type == CAMERA_PERSPECTIVE) { + glm_perspective(glm_rad(c->fov), + (float) ((float)screen_viewport[2]/(float)screen_viewport[3]), + c->near_z, c->far_z, + c->projection); + } else if (c->type == CAMERA_ORTHOGONAL) { + float left = -screen_viewport[2]/2 * c->viewport_modifier; + float right = screen_viewport[2]/2 * c->viewport_modifier; + float top = screen_viewport[3]/2 * c->viewport_modifier; + float bottom = -screen_viewport[3]/2 * c->viewport_modifier; + glm_ortho(left, right, bottom, top, c->near_z, c->far_z, c->projection); + } else { + return -1; + } + + return 0; +} + diff --git a/dev.c b/dev.c index 6985c8f..aeba1cd 100644 --- a/dev.c +++ b/dev.c @@ -1,6 +1,7 @@ #include #include #include "include/rendlib.h" +#include "include/camera.h" #include "include/object.h" int main(int argc, char *argv[]) { @@ -22,6 +23,12 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } + struct camera *c = create_camera(CAMERA_PERSPECTIVE); + if (c == NULL) { + fprintf(stderr, "--error: creating camera\n"); + return EXIT_FAILURE; + } + ret = rendlib_render(); if (ret < 0) { fprintf(stderr, "--error: %d\n", ret); diff --git a/include/camera.h b/include/camera.h new file mode 100644 index 0000000..ce37dc2 --- /dev/null +++ b/include/camera.h @@ -0,0 +1,32 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include +#include + +#define CAMERA_PERSPECTIVE 0x1 +#define CAMERA_ORTHOGONAL 0x2 + +struct camera { + int type; + float fov; + float near_z; + float far_z; + float yaw; + float pitch; + float sensitivity; + float viewport_modifier; + + vec3 pos; + vec3 front; + vec3 center; + vec3 up; + + mat4 view; + mat4 projection; +}; + +struct camera *create_camera(int type); +int bake_camera(struct camera *c); + +#endif diff --git a/include/math.h b/include/math.h index edac44a..693c379 100644 --- a/include/math.h +++ b/include/math.h @@ -5,6 +5,5 @@ #include float frand48(void); -void calculate_gravity(struct object *src, struct object *target, vec3 force); #endif diff --git a/include/object.h b/include/object.h index 242e913..b091869 100644 --- a/include/object.h +++ b/include/object.h @@ -22,20 +22,13 @@ struct object { float mass; void *next; - float *paths; - int paths_num; - int paths_max; - struct model *model; float scale; - unsigned int vao; // array object for the actual object - unsigned int vbo; // buffer for vertices - unsigned int ebo; // buffer for indices - unsigned int nbo; // buffer for normals - - unsigned int pvao; // array object for paths - unsigned int pbo; // buffer for paths + unsigned int vao; + unsigned int vbo; // vertices + unsigned int ebo; // indices + unsigned int nbo; // normals }; struct model *load_model(const char *path); diff --git a/include/rendlib.h b/include/rendlib.h index 2721941..aee7fa8 100644 --- a/include/rendlib.h +++ b/include/rendlib.h @@ -15,6 +15,7 @@ enum errs { err_shaders_init = -4, }; +extern struct camera *active_camera; extern struct object *objects; int rendlib_start_window(int argc, char *argv[]); int rendlib_render(void); diff --git a/math.c b/math.c index c5f418c..88424cf 100644 --- a/math.c +++ b/math.c @@ -11,32 +11,3 @@ float frand48(void) { return number; } - -void calculate_gravity(struct object *src, struct object *target, vec3 force) { - vec4 v4distance; - glm_vec4_sub(target->position, src->position, v4distance); - - vec3 v3distance; - glm_vec3(v4distance, v3distance); - - float distance_xy = sqrt((v3distance[0] * v3distance[0]) + (v3distance[1] * v3distance[1])); - float distance_xyz = sqrt((distance_xy * distance_xy) + (v3distance[2] * v3distance[2])); - float force_scale = 4.0f; - - float g = 6.67f * 1e-11f; - float top = g * src->mass * target->mass; - - for (int i = 0; i < 3; i++) { - v3distance[i] = (v3distance[i] * v3distance[i] * v3distance[i]); - } - - for (int i = 0; i < 3; i++) { - if (v3distance[i] == 0) { - force[i] = 0.0f; - continue; - } - - force[i] = (top / (distance_xyz / (target->position[i] - src->position[i]))) * force_scale; - } -} - diff --git a/object.c b/object.c index 3114f3c..72a665e 100644 --- a/object.c +++ b/object.c @@ -6,96 +6,91 @@ #include #include -struct model *load_model(const char *path) { - struct model *new_model = (struct model *) calloc(1, sizeof(struct model)); - const struct aiScene *scene = aiImportFile(path, aiProcess_Triangulate); +static int load_vertices(struct model *m, struct aiMesh *ms) { + m->vertices_num = ms->mNumVertices; + int len = m->vertices_num * sizeof(struct aiVector3D); + m->vertices = malloc(len); + if (m->vertices == NULL) { + return -1; + } + memset(m->vertices, 0, len); + memcpy(m->vertices, ms->mVertices, len); + return 0; +} + +static int load_indices(struct model *m, struct aiMesh *ms) { + for (int face_index = 0; face_index < ms->mNumFaces; face_index++) { + struct aiFace *face = &(ms->mFaces[face_index]); + long start = m->indices_num; + + m->indices_num += face->mNumIndices; + m->indices = (unsigned int *) realloc(m->indices, sizeof(unsigned int)*m->indices_num); + if (m->indices == NULL) { + return -1; + } + + memcpy(&m->indices[start], face->mIndices, sizeof(unsigned int)*face->mNumIndices); + } + return 0; +} + +static int load_normals(struct model *m, struct aiMesh *ms) { + m->normals_num = ms->mNumVertices; + int len = m->vertices_num * sizeof(struct aiVector3D); + m->normals = malloc(len); + if (m->vertices == NULL) { + return -1; + } + memset(m->normals, 0, len); + memcpy(m->normals, ms->mNormals, len); + return 0; +} + +struct model *load_model(const char *path) { + int ret = 0; + struct model *nm = malloc(sizeof(struct model)); + if (nm == NULL) { + return NULL; + } + + memset(nm, 0, sizeof(struct model)); + + const struct aiScene *scene = aiImportFile(path, aiProcess_Triangulate); if (scene == NULL) { - fprintf(stderr, "Error: failed importing file from path '%s'", path); + free(nm); + return NULL; } for (int mesh_index = 0; mesh_index < scene->mNumMeshes; mesh_index++) { struct aiMesh *mesh = scene->mMeshes[mesh_index]; - // fetch vertices - for (int vertex_index = 0; vertex_index < mesh->mNumVertices; vertex_index++) { - struct aiVector3D *vertex = &(mesh->mVertices[vertex_index]); - long start = new_model->vertices_num*3; - - new_model->vertices_num++; - new_model->vertices = (float *) realloc(new_model->vertices, new_model->vertices_num*3*sizeof(float)); - if (new_model->vertices == NULL) { - fprintf(stderr, "Error: failed allocating memory for vertices\n"); - goto error; - } - - memcpy(&new_model->vertices[start], vertex, sizeof(float)*3); + ret = load_vertices(nm, mesh); + if (ret < 0) { + free(nm); + aiReleaseImport(scene); + return NULL; } - // fetch indices - for (int face_index = 0; face_index < mesh->mNumFaces; face_index++) { - struct aiFace *face = &(mesh->mFaces[face_index]); - long start = new_model->indices_num; - - new_model->indices_num += face->mNumIndices; - new_model->indices = (unsigned int *) realloc(new_model->indices, sizeof(unsigned int)*new_model->indices_num); - if (new_model->indices == NULL) { - fprintf(stderr, "Error: failed allocating memory for indices\n"); - goto error; - } - - memcpy(&new_model->indices[start], face->mIndices, sizeof(unsigned int)*face->mNumIndices); + ret = load_indices(nm, mesh); + if (ret < 0) { + free(nm->vertices); + free(nm); + aiReleaseImport(scene); + return NULL; } - // fetch normals - for (int normal_index = 0; normal_index < mesh->mNumVertices; normal_index++) { - struct aiVector3D *normal = &(mesh->mNormals[normal_index]); - long start = new_model->normals_num*3; - - new_model->normals_num++; - new_model->normals = (float *) realloc(new_model->normals, new_model->normals_num*3*sizeof(float)); - if (new_model->normals == NULL) { - fprintf(stderr, "Error: failed allocating memory for normals\n"); - goto error; - } - - memcpy(&new_model->normals[start], normal, sizeof(float)*3); + ret = load_normals(nm, mesh); + if (ret < 0) { + free(nm->vertices); + free(nm->indices); + free(nm); + aiReleaseImport(scene); + return NULL; } } - return new_model; - -error: - aiReleaseImport(scene); - free(new_model->vertices); - free(new_model->indices); - free(new_model->normals); - free(new_model); - return NULL; -} - -int record_path(struct object *obj) { - if (obj->paths_num <= obj->paths_max) { - obj->paths = (float *) reallocarray(obj->paths, (obj->paths_num+1)*3, sizeof(float)); - } - - if (obj->paths == NULL) { - fprintf(stderr, "Error: failed allocating memory for paths of object\n"); - return -1; - } - - memcpy(obj->paths+(obj->paths_num*3), obj->position, 3*sizeof(float)); - - if (obj->paths_num < obj->paths_max) { - obj->paths_num++; - goto end; - } - - // pop first element - memmove(obj->paths, &obj->paths[3], (obj->paths_num)*3*sizeof(float)); - -end: - return 0; + return nm; } struct object *create_object(struct object **o, float mass, struct model *model) { @@ -107,7 +102,6 @@ struct object *create_object(struct object **o, float mass, struct model *model) no->mass = mass; no->scale = 1.0f; - no->paths_max = MAX_PATHS; no->model = model; glm_vec4_one(no->position); glm_vec3_one(no->color); diff --git a/rendlib.c b/rendlib.c index d32c859..5b1fc51 100644 --- a/rendlib.c +++ b/rendlib.c @@ -6,7 +6,7 @@ #include #include #include "include/rendlib.h" -#include "include/math.h" +#include "include/camera.h" #include "include/object.h" // global variables @@ -14,31 +14,19 @@ int window_width = 960; int window_height = 540; char *window_title = "rendlib window"; -float fov = 90.0f; -float camera_yaw = -90.0f; -float camera_pitch = 0.0f; -float camera_sensitivity = 0.02f; -float top_movement_speed = 0.2f; -vec3 camera_pos = { 0.0f, 0.0f, 50.0f }; -vec3 camera_front = { 0.0f, 0.0f, -1.0f }; -vec3 camera_up = { 0.0f, 1.0f, 0.0f }; -vec3 speed = { 0.0f, 0.0f, 0.0f }; -struct object *camera_lock = NULL; -GLint screen_viewport[4]; +struct camera *ac; -// tmp input +float top_movement_speed = 0.4f; +vec3 speed = { 0.0f, 0.0f, 0.0f }; +GLint screen_viewport[4]; char input = 0; -// tmp -struct model *sphere_model; struct object *objects; -// opengl unsigned int shader_program; unsigned int vertex_shader; unsigned int fragment_shader; -// shaders const char *object_vertex_shader_location = "assets/shaders/shader.vert"; const char *object_fragment_shader_location = "assets/shaders/shader.frag"; @@ -103,7 +91,6 @@ int load_shaders(void) { glDeleteProgram(shader_program); shader_program = glCreateProgram(); - // create and load new shaders vertex_shader = glCreateShader(GL_VERTEX_SHADER); fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); @@ -115,7 +102,6 @@ int load_shaders(void) { return -1; } - // compile object shader program glAttachShader(shader_program, vertex_shader); glAttachShader(shader_program, fragment_shader); glLinkProgram(shader_program); @@ -159,31 +145,31 @@ void handle_input(void) { if (input & RENDLIB_INPUT_LEFT) { vec3 side_scalar = {top_movement_speed, top_movement_speed, top_movement_speed }; vec3 camera_side; - glm_cross(camera_front, camera_up, camera_side); + glm_cross(ac->front, ac->up, camera_side); glm_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); - glm_vec3_sub(camera_pos, camera_side, camera_pos); + glm_vec3_sub(ac->pos, camera_side, ac->pos); } if (input & RENDLIB_INPUT_RIGHT) { vec3 side_scalar = {top_movement_speed, top_movement_speed, top_movement_speed }; vec3 camera_side; - glm_cross(camera_front, camera_up, camera_side); + glm_cross(ac->front, ac->up, camera_side); glm_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); - glm_vec3_add(camera_pos, camera_side, camera_pos); + glm_vec3_add(ac->pos, camera_side, ac->pos); } if (input & RENDLIB_INPUT_BACKW) { vec3 front_scalar = {top_movement_speed, top_movement_speed, top_movement_speed }; - glm_vec3_mul(front_scalar, camera_front, front_scalar); - glm_vec3_sub(camera_pos, front_scalar, camera_pos); + glm_vec3_mul(front_scalar, ac->front, front_scalar); + glm_vec3_sub(ac->pos, front_scalar, ac->pos); } if (input & RENDLIB_INPUT_FORW) { vec3 front_scalar = {top_movement_speed, top_movement_speed, top_movement_speed }; - glm_vec3_mul(front_scalar, camera_front, front_scalar); - glm_vec3_add(camera_pos, front_scalar, camera_pos); + glm_vec3_mul(front_scalar, ac->front, front_scalar); + glm_vec3_add(ac->pos, front_scalar, ac->pos); } } @@ -195,9 +181,6 @@ void display(void) { handle_input(); GLFWwindow *w = glfwGetCurrentContext(); - mat4 view; - mat4 projection; - GLint translation_uniform; GLint view_uniform; GLint projection_uniform; @@ -208,13 +191,11 @@ void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(shader_program); - glm_mat4_identity(view); - vec3 camera_center; - glm_vec3_add(camera_pos, camera_front, camera_center); - glm_lookat(camera_pos, camera_center, camera_up, view); - - glm_mat4_identity(projection); - glm_perspective(glm_rad(fov), (float) screen_viewport[2]/(float) screen_viewport[3], 0.01f, 100000.0f, projection); + int ret = bake_camera(ac); + if (ret < 0) { + fprintf(stderr, "--error: failed baking camera\n"); + return; + } view_uniform = glGetUniformLocation(shader_program, "view"); projection_uniform = glGetUniformLocation(shader_program, "projection"); @@ -222,44 +203,14 @@ void display(void) { color_uniform = glGetUniformLocation(shader_program, "color"); scale_uniform = glGetUniformLocation(shader_program, "scale"); - glUniformMatrix4fv(view_uniform, 1, GL_FALSE, (float *) view); - glUniformMatrix4fv(projection_uniform, 1, GL_FALSE, (float *) projection); + glUniformMatrix4fv(view_uniform, 1, GL_FALSE, (float *) ac->view); + glUniformMatrix4fv(projection_uniform, 1, GL_FALSE, (float *) ac->projection); for (struct object *obj = objects; obj != NULL; obj = obj->next) { mat4 translation_matrix; glm_mat4_identity(translation_matrix); + struct model *obj_model = obj->model; - - // calculate gravity - for (struct object *target = objects; target != NULL; target = target->next) { - if (target == obj) { - continue; - } - - vec3 force; - glm_vec3_zero(force); - calculate_gravity(obj, target, force); - - vec4 force_new; - for (int i = 0; i < 3; i++) { - force_new[i] = force[i]; - } - force_new[3] = 0.0f; - - float n = obj->mass; - vec4 scaler = {n,n,n,1.0f}; - glm_vec4_div(force_new, scaler, force_new); - - glm_vec4_add(force_new, obj->translation_force, obj->translation_force); - } - - glm_vec4_add(obj->position, obj->translation_force, obj->position); - - // follow object if camera locked - if (camera_lock == obj) { - glm_vec3_add(camera_pos, obj->translation_force, camera_pos); - } - glm_translate(translation_matrix, obj->position); glUniformMatrix4fv(translation_uniform, 1, GL_FALSE, (float *) translation_matrix); @@ -269,41 +220,21 @@ void display(void) { glBindVertexArray(obj->vao); glDrawElements(GL_TRIANGLES, obj_model->indices_num, GL_UNSIGNED_INT, (void *) 0); - - glBindVertexArray(obj->pvao); - - glBindBuffer(GL_ARRAY_BUFFER, obj->pbo); - glBufferData(GL_ARRAY_BUFFER, obj->paths_num*3*sizeof(float),obj->paths, GL_STATIC_DRAW); - - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *) 0); - glEnableVertexAttribArray(0); - - glm_mat4_identity(translation_matrix); - glUniformMatrix4fv(translation_uniform, 1, GL_FALSE, (float *) translation_matrix); - glUniform1f(scale_uniform, 1.0f); - - glDrawArrays(GL_LINE_STRIP, 0, obj->paths_num); } - /*glutPostRedisplay(); - glutSwapBuffers();*/ glfwSwapBuffers(w); glfwPollEvents(); } void rendlib_bake_graphics(void) { - // setup default mouse position glGetIntegerv(GL_VIEWPORT, screen_viewport); - for (struct object *obj = objects; obj != NULL; obj = obj->next) { struct model *obj_model = obj->model; glGenVertexArrays(1, &obj->vao); - glGenVertexArrays(1, &obj->pvao); glGenBuffers(1, &obj->vbo); glGenBuffers(1, &obj->ebo); glGenBuffers(1, &obj->nbo); - glGenBuffers(1, &obj->pbo); glBindVertexArray(obj->vao); @@ -406,25 +337,24 @@ void mouse_motion(GLFWwindow *window, double x, double y) { return; } - float offset_x = (float) (x - (screen_viewport[2]/2)) * camera_sensitivity; - float offset_y = (float) (y - (screen_viewport[3]/2)) * camera_sensitivity; + float offset_x = (float) (x - (screen_viewport[2]/2)) * ac->sensitivity; + float offset_y = (float) (y - (screen_viewport[3]/2)) * ac->sensitivity; - camera_yaw += offset_x; - camera_pitch -= offset_y; + ac->yaw += offset_x; + ac->pitch -= offset_y; - // limit view rotation - if (camera_pitch < -89.9f) { - camera_pitch = -89.9f; + if (ac->pitch < -89.9f) { + ac->pitch = -89.9f; } - if (camera_pitch > 89.9f) { - camera_pitch = 89.9f; + if (ac->pitch > 89.9f) { + ac->pitch = 89.9f; } - vec3 view_direction = { cos(glm_rad(camera_yaw)) * cos(glm_rad(camera_pitch)), - sin(glm_rad(camera_pitch)), - sin(glm_rad(camera_yaw)) * cos(glm_rad(camera_pitch)) + vec3 view_direction = { cos(glm_rad(ac->yaw)) * cos(glm_rad(ac->pitch)), + sin(glm_rad(ac->pitch)), + sin(glm_rad(ac->yaw)) * cos(glm_rad(ac->pitch)) }; - glm_normalize_to(view_direction, camera_front); + glm_normalize_to(view_direction, ac->front); } int rendlib_start_window(int argc, char *argv[]) { @@ -457,7 +387,20 @@ int rendlib_start_window(int argc, char *argv[]) { return 0; } +int setup_default_camera(void) { + ac = create_camera(CAMERA_PERSPECTIVE); + if (ac == NULL) { + return -1; + } + return 0; +} + int rendlib_render(void) { + if (ac == NULL) { + if (setup_default_camera() < 0) { + return -1; + } + } rendlib_bake_graphics(); for (;;) { display();