#include #include #include #include #include #include #include #include "include/rendlib.h" #include "include/math.h" #include "include/object.h" // global variables 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]; // tmp input 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"; void update_screen_viewport(int x, int y, int width, int height) { GLFWwindow *w = glfwGetCurrentContext(); glfwSetCursorPos(w, (width/2), (height/2)); glViewport(x, y, width, height); glGetIntegerv(GL_VIEWPORT, screen_viewport); } int load_shader(const char *path, unsigned int shader) { FILE *fp = fopen(path, "r"); if (fp == NULL) { fprintf(stderr, "error: cannot open file '%s'\n", path); return -1; } fseek(fp, 0L, SEEK_END); int len = ftell(fp); if (len == -1) { fprintf(stderr, "error: cannot fetch length of file '%s'\n", path); return -1; } fseek(fp, 0L, SEEK_SET); char *fc = (char *) malloc(len); if (fc == NULL) { fprintf(stderr, "error: not enough dynamic memory\n"); return -1; } memset(fc, 0, len); int rb = 0; do { rb += fread(fc+rb, sizeof(char), len-rb, fp); if (rb == 0) { break; } } while (rb < len); fclose(fp); glShaderSource(shader, 1, (const char **) &fc, &rb); glCompileShader(shader); int success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (success != GL_TRUE) { int log_length; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); char log[log_length]; glGetShaderInfoLog(shader, log_length, NULL, log); fprintf(stderr, "Shader Compilation Error: %s\n", log); return -1; } free(fc); return 0; } 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); if (load_shader(object_vertex_shader_location, vertex_shader) == -1) { return -1; } if (load_shader(object_fragment_shader_location, fragment_shader) == -1) { return -1; } // compile object shader program glAttachShader(shader_program, vertex_shader); glAttachShader(shader_program, fragment_shader); glLinkProgram(shader_program); int success; glGetProgramiv(shader_program, GL_LINK_STATUS, &success); if (success != GL_TRUE) { int log_length; glGetProgramiv(shader_program, GL_INFO_LOG_LENGTH, &log_length); char log[log_length]; glGetProgramInfoLog(shader_program, log_length, NULL, log); fprintf(stderr, "[object program] Shader Compilation Error: %s\n", log); return -1; } glDeleteShader(vertex_shader); glDeleteShader(fragment_shader); return 0; } void handle_input(void) { int ret = 0; if (input & RENDLIB_INPUT_ESC) { exit(EXIT_SUCCESS); input &= ~RENDLIB_INPUT_ESC; } if (input & RENDLIB_INPUT_REL) { ret = load_shaders(); if (ret < 0) { fprintf(stderr, "--error: reloading shaders\n"); exit(EXIT_FAILURE); } input &= ~RENDLIB_INPUT_REL; } 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_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); glm_vec3_sub(camera_pos, camera_side, camera_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_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); glm_vec3_add(camera_pos, camera_side, camera_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); } 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); } } void window_size(GLFWwindow *w, int width, int height) { update_screen_viewport(0, 0, width, height); } void display(void) { handle_input(); GLFWwindow *w = glfwGetCurrentContext(); mat4 view; mat4 projection; GLint translation_uniform; GLint view_uniform; GLint projection_uniform; GLint color_uniform; GLint scale_uniform; glClearColor(0.13f, 0.13f, 0.13f, 0.0f); 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); view_uniform = glGetUniformLocation(shader_program, "view"); projection_uniform = glGetUniformLocation(shader_program, "projection"); translation_uniform = glGetUniformLocation(shader_program, "translation"); 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); 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); glUniform3fv(color_uniform, 1, (float *) obj->color); glUniform1f(scale_uniform, obj->scale); 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); glBindBuffer(GL_ARRAY_BUFFER,obj->vbo); glBufferData(GL_ARRAY_BUFFER,obj_model->vertices_num*3*sizeof(float),obj_model->vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *) 0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, obj->nbo); glBufferData(GL_ARRAY_BUFFER, obj_model->normals_num*3*sizeof(float), obj_model->normals, GL_STATIC_DRAW); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void *) 0); glEnableVertexAttribArray(1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,obj->ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, obj_model->indices_num*sizeof(unsigned int), obj_model->indices, GL_STATIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } glEnable(GL_DEPTH_TEST); } void keyboard(GLFWwindow *w, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_Q: case GLFW_KEY_ESCAPE: input |= RENDLIB_INPUT_ESC; break; case GLFW_KEY_R: input |= RENDLIB_INPUT_REL; break; case GLFW_KEY_A: case GLFW_KEY_LEFT: input |= RENDLIB_INPUT_LEFT; break; case GLFW_KEY_D: case GLFW_KEY_RIGHT: input |= RENDLIB_INPUT_RIGHT; break; case GLFW_KEY_S: case GLFW_KEY_DOWN: input |= RENDLIB_INPUT_BACKW; break; case GLFW_KEY_W: case GLFW_KEY_UP: input |= RENDLIB_INPUT_FORW; break; case GLFW_KEY_F11: { GLFWmonitor *m = glfwGetPrimaryMonitor(); const GLFWvidmode *vm = glfwGetVideoMode(m); GLFWwindow *w = glfwGetCurrentContext(); glfwSetWindowMonitor(w, m, 0, 0, vm->width, vm->height, vm->refreshRate); update_screen_viewport(0, 0, vm->width, vm->height); break; } } } else if (action == GLFW_RELEASE) { switch (key) { case GLFW_KEY_A: case GLFW_KEY_LEFT: input &= ~RENDLIB_INPUT_LEFT; break; case GLFW_KEY_D: case GLFW_KEY_RIGHT: input &= ~RENDLIB_INPUT_RIGHT; break; case GLFW_KEY_S: case GLFW_KEY_DOWN: input &= ~RENDLIB_INPUT_BACKW; break; case GLFW_KEY_W: case GLFW_KEY_UP: input &= ~RENDLIB_INPUT_FORW; break; } } } int warped_pointer = 0; int first_pointer = 1; void mouse_motion(GLFWwindow *window, double x, double y) { if (warped_pointer == 1) { warped_pointer = 0; return; } warped_pointer = 1; glGetIntegerv(GL_VIEWPORT, screen_viewport); GLFWwindow *w = glfwGetCurrentContext(); glfwSetCursorPos(w, (screen_viewport[2]/2), (screen_viewport[3]/2)); if (first_pointer == 1) { first_pointer = 0; return; } float offset_x = (float) (x - (screen_viewport[2]/2)) * camera_sensitivity; float offset_y = (float) (y - (screen_viewport[3]/2)) * camera_sensitivity; camera_yaw += offset_x; camera_pitch -= offset_y; // limit view rotation if (camera_pitch < -89.9f) { camera_pitch = -89.9f; } if (camera_pitch > 89.9f) { camera_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)) }; glm_normalize_to(view_direction, camera_front); } int rendlib_start_window(int argc, char *argv[]) { int ret = glfwInit(); if (!ret) { return err_glfw_init; } GLFWwindow *w = glfwCreateWindow(window_width, window_height, window_title, NULL, NULL); if (w == NULL) { return err_glfw_win; } glfwMakeContextCurrent(w); glfwSetWindowSizeCallback(w, window_size); glfwSetCursorPosCallback(w, mouse_motion); glfwSetKeyCallback(w, keyboard); glfwSetInputMode(w, GLFW_CURSOR, GLFW_CURSOR_DISABLED); ret = glewInit(); if (ret != GLEW_OK) { return err_glew_init; } ret = load_shaders(); if (ret < 0) { return err_shaders_init; } return 0; } int rendlib_render(void) { rendlib_bake_graphics(); for (;;) { display(); } return 0; }