#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; void (*keyboard_probe)(int key, int scancode, int action, int mods); void (*mouse_probe)(double x, double y); void (*update_probe)(void); float top_movement_speed = 0.4f; vec3 speed = { 0.0f, 0.0f, 0.0f }; GLint screen_viewport[4]; 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) { } 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 (keyboard_probe == NULL) { return; } (keyboard_probe)(key, scancode, action, mods); } void mouse_motion(GLFWwindow *window, double x, double y) { if (mouse_probe == NULL) { return; } (mouse_probe)(x, y); } 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 (;;) { if (update_probe != NULL) { (update_probe)(); } display(); } return 0; }