#include #include #include #include #include #include #include #include "include/rendlib.h" #include "include/camera.h" #include "include/object.h" // global variables int window_width = 960; int window_height = 540; char *window_title = "rendlib window"; struct camera *ac; float top_movement_speed = 0.4f; vec3 speed = { 0.0f, 0.0f, 0.0f }; GLint screen_viewport[4]; char input = 0; struct object *objects; unsigned int shader_program; unsigned int vertex_shader; unsigned int fragment_shader; 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(); 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; } 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(ac->front, ac->up, camera_side); glm_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); 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(ac->front, ac->up, camera_side); glm_normalize(camera_side); glm_vec3_mul(camera_side, side_scalar, camera_side); 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, 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, ac->front, front_scalar); glm_vec3_add(ac->pos, front_scalar, ac->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(); 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); 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"); 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 *) 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; 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); } glfwSwapBuffers(w); glfwPollEvents(); } void rendlib_bake_graphics(void) { 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); glGenBuffers(1, &obj->vbo); glGenBuffers(1, &obj->ebo); glGenBuffers(1, &obj->nbo); 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)) * ac->sensitivity; float offset_y = (float) (y - (screen_viewport[3]/2)) * ac->sensitivity; ac->yaw += offset_x; ac->pitch -= offset_y; if (ac->pitch < -89.9f) { ac->pitch = -89.9f; } if (ac->pitch > 89.9f) { ac->pitch = 89.9f; } 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, ac->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 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(); } return 0; }