#include "GL/glew.h" #include "GLFW/glfw3.h" #include "pwyazh.h" #include "pwyazh_GL.h" #include "common.h" #define LIGHT_COUNT 3 int main(void) { S32 width = 1600; S32 height = 900; /* NOTE(pryazha): GLFW init */ glfwSetErrorCallback(error_callback); if (glfwInit() == GLFW_FALSE) return 1; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); GLFWwindow *window = glfwCreateWindow(width, height, "Bloom", 0, 0); if (!window) return 1; glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwMakeContextCurrent(window); if (glewInit() != GLEW_OK) return 1; glEnable(GL_DEPTH_TEST); /* NOTE(pryazha): Program init */ State state = {0}; state.arena = arena_alloc(Kilobytes(256)); state.input.first_mouse = 1; state.camera = (Camera){ v3f(0.0f, 0.0f, 3.0f), 90.0f, 0.1f, 100.0f, 0.0f, 0.0f }; V3F light_positions[LIGHT_COUNT]; F32 da = 2.0f*pi_F32/LIGHT_COUNT; F32 a = 0.0f; F32 r = 2.0f; for (S32 i = 0; i < LIGHT_COUNT; i++, a += da) light_positions[i] = v3f(f32_sin(a)*r, 0.0f, f32_cos(a)*r); V3F light_colors[LIGHT_COUNT] = { {5.0f, 5.0f, 5.0f}, {10.0f, 0.0f, 0.0f}, {0.0f, 5.0f, 0.0f}, }; S32 bloom = 0; F32 exposure = 1.0f; /* NOTE(pryazha): Textures */ U32 woood_texture = load_texture_gamma("../../data/textures/wood.png", 1); /* NOTE(pryazha): Meshes */ Mesh *quad = mesh_gen_quad(state.arena); Mesh *cube = mesh_load_obj(state.arena, "../../data/models/cube.obj"); /* NOTE(pryazha): Shaders */ U32 shader = load_shader("shaders/bloom.vert", "shaders/bloom.frag"); U32 shader_light = load_shader("shaders/bloom.vert", "shaders/light.frag"); U32 shader_blur = load_shader("shaders/blur.vert", "shaders/blur.frag"); U32 shader_test_blur = load_shader("shaders/test_blur.vert", "shaders/test_blur.frag"); U32 shader_final = load_shader("shaders/final.vert", "shaders/final.frag"); glUseProgram(shader_final); shader_set_1i(shader_final, "scene", 0); shader_set_1i(shader_final, "blur", 1); /* NOTE(pryazha): Framebuffers */ U32 hdrfbo; glGenFramebuffers(1, &hdrfbo); glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo); U32 colorbuffers[2]; glGenTextures(2, colorbuffers); for (S32 i = 0; i < 2; ++i) { glBindTexture(GL_TEXTURE_2D, colorbuffers[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+i, GL_TEXTURE_2D, colorbuffers[i], 0); } U32 hdrrbo; glGenRenderbuffers(1, &hdrrbo); glBindRenderbuffer(GL_RENDERBUFFER, hdrrbo); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, hdrrbo); U32 attachments[2] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1}; glDrawBuffers(2, attachments); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fprintf(stderr, "error: framebuffer not complete\n"); glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); U32 pingpong_fbo[2]; U32 pingpong_colorbuffers[2]; glGenFramebuffers(2, pingpong_fbo); glGenTextures(2, pingpong_colorbuffers); for (S32 i = 0; i < 2; i++) { glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[i]); glBindTexture(GL_TEXTURE_2D, pingpong_colorbuffers[i]); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpong_colorbuffers[i], 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fprintf(stderr, "error: framebuffer not complete\n"); } glBindFramebuffer(GL_FRAMEBUFFER, 0); U32 blur_fbo; glGenFramebuffers(1, &blur_fbo); glBindFramebuffer(GL_FRAMEBUFFER, blur_fbo); U32 blur_colorbuffer; glGenTextures(1, &blur_colorbuffer); glBindTexture(GL_TEXTURE_2D, blur_colorbuffer); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, blur_colorbuffer, 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) fprintf(stderr, "error: blur framebuffer not complete\n"); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0); S32 myblur = 0; F64 last_time = glfwGetTime(); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); glfwGetFramebufferSize(window, &width, &height); process_glfw_keyboard(window, &state.input); process_glfw_mouse_pos(window, &state.input); if (key_first_press(state.input.exit)) glfwSetWindowShouldClose(window, GLFW_TRUE); F32 speed = 2.0f; V3F dv = get_dv_camera_first_person(&state.input, &state.camera, speed, state.dt); state.camera_dp = v3f_add(state.camera_dp, dv); state.camera_dp = v3f_scalef(state.camera_dp, 0.8f); state.camera.pos = v3f_add(state.camera.pos, state.camera_dp); F32 sensitivity = 0.1f; state.input.mouse_offset = v2f_scalef(state.input.mouse_offset, sensitivity); state.camera.yaw += state.input.mouse_offset.x; state.camera.pitch += state.input.mouse_offset.y; if (state.camera.pitch > 89.0f) state.camera.pitch = 89.0f; if (state.camera.pitch < -89.0f) state.camera.pitch = -89.0f; /* NOTE(pryazha): Update */ if (key_is_pressed(state.input.action_down)) exposure -= 0.01f; if (key_is_pressed(state.input.action_up)) exposure += 0.01f; if (key_first_press(state.input.jump)) bloom = !bloom; if (key_first_press(state.input.action_left)) myblur = !myblur; for (S32 i = 0; i < LIGHT_COUNT; i++) light_positions[i].y = f32_sin(glfwGetTime()+i); /* NOTE(pryazha): Render */ glClearColor(0.15f, 0.15f, 0.15f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Render to HDR framebuffer */ glBindFramebuffer(GL_FRAMEBUFFER, hdrfbo); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); F32 ar = (F32)width/(F32)height; MAT4 projection = camera_persp(state.camera, ar); MAT4 view = get_view_matrix(&state.camera); glUseProgram(shader); shader_set_mat4fv(shader, "projection", projection); shader_set_mat4fv(shader, "view", view); for (S32 i = 0; i < LIGHT_COUNT; i++) { char light_string[1024]; snprintf(light_string, 1024, "lights[%d].position", i); shader_set_3fv(shader, light_string, light_positions[i]); snprintf(light_string, 1024, "lights[%d].color", i); shader_set_3fv(shader, light_string, light_colors[i]); } shader_set_3fv(shader, "view_pos", state.camera.pos); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, woood_texture); MAT4 model = mat4_make_scale(v3f(10.0f, 0.25f, 10.0f)); model = mat4_translate(model, v3f(0.0f, -2.0f, 0.0f)); shader_set_mat4fv(shader, "model", model); mesh_draw(cube); model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); model = mat4_rotate_angles(model, v3f(30.0f, 45.0f, 0.0f)); model = mat4_translate(model, v3f(-0.5f, -1.0f, -2.0f)); shader_set_mat4fv(shader, "model", model); mesh_draw(cube); model = mat4_make_scale(v3f(0.5f, 0.5f, 0.5f)); model = mat4_rotate_angles(model, v3f(-30.0f, 45.0f, 90.0f)); model = mat4_translate(model, v3f(0.75f, -1.5f, 1.0f)); shader_set_mat4fv(shader, "model", model); mesh_draw(cube); glBindTexture(GL_TEXTURE_2D, 0); glUseProgram(0); glUseProgram(shader_light); shader_set_mat4fv(shader_light, "projection", projection); shader_set_mat4fv(shader_light, "view", view); for (S32 i = 0; i < LIGHT_COUNT; i++) { model = mat4_make_scale(v3f(0.2f, 0.2f, 0.2f)); model = mat4_translate(model, light_positions[i]); shader_set_mat4fv(shader_light, "model", model); shader_set_3fv(shader_light, "light_color", light_colors[i]); mesh_draw(cube); } glUseProgram(0); S32 horizontal = 1, first = 1, amount = 10; glUseProgram(shader_blur); for (S32 i = 0; i < amount; i++) { glBindFramebuffer(GL_FRAMEBUFFER, pingpong_fbo[horizontal]); shader_set_1i(shader_blur, "horizontal", horizontal); glBindTexture(GL_TEXTURE_2D, first ? colorbuffers[1] : pingpong_colorbuffers[!horizontal]); mesh_draw(quad); horizontal = !horizontal; if (first) first = 0; } glUseProgram(0); glBindFramebuffer(GL_FRAMEBUFFER, blur_fbo); glUseProgram(shader_test_blur); glActiveTexture(0); glBindTexture(GL_TEXTURE_2D, colorbuffers[1]); mesh_draw(quad); glUseProgram(0); glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(shader_final); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, colorbuffers[0]); glActiveTexture(GL_TEXTURE1); if (myblur) { glBindTexture(GL_TEXTURE_2D, blur_colorbuffer); } else { glBindTexture(GL_TEXTURE_2D, pingpong_colorbuffers[!horizontal]); } shader_set_1i(shader_final, "bloom", bloom); shader_set_1f(shader_final, "exposure", exposure); mesh_draw(quad); glfwSwapBuffers(window); F64 time = glfwGetTime(); state.dt = time - last_time; last_time = time; input_update_last_state(&state.input); } return 0; }