diff options
Diffstat (limited to 'advanced_lighting/7.bloom/bloom.c')
-rw-r--r-- | advanced_lighting/7.bloom/bloom.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/advanced_lighting/7.bloom/bloom.c b/advanced_lighting/7.bloom/bloom.c new file mode 100644 index 0000000..70adcfe --- /dev/null +++ b/advanced_lighting/7.bloom/bloom.c @@ -0,0 +1,287 @@ +#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; +} |