#include "GL/glew.h" #include "GLFW/glfw3.h" #include "pwyazh.h" #include "pwyazh_GL.h" #include "common.h" U32 gen_quad_with_tan() { /* Positions */ V3F p1 = v3f(-1.0f, 1.0f, 0.0f); V3F p2 = v3f(-1.0f, -1.0f, 0.0f); V3F p3 = v3f(1.0f, -1.0f, 0.0f); V3F p4 = v3f(1.0f, 1.0f, 0.0f); /* Texture ccoordinates */ V2F uv1 = v2f(0.0f, 1.0f); V2F uv2 = v2f(0.0f, 0.0f); V2F uv3 = v2f(1.0f, 0.0f); V2F uv4 = v2f(1.0f, 1.0f); /* Normal vector */ V3F nm = v3f(0.0f, 0.0f, 1.0f); V3F edge1, edge2; V2F duv1, duv2; F32 f; V3F t1, bit1, t2, bit2; edge1 = v3f_sub(p2, p1); edge2 = v3f_sub(p3, p1); duv1 = v2f_sub(uv2, uv1); duv2 = v2f_sub(uv3, uv1); f = 1.0f/(duv1.x*duv2.y-duv2.x*duv1.y); t1.x = f*(duv2.y*edge1.x-duv1.y*edge2.x); t1.y = f*(duv2.y*edge1.y-duv1.y*edge2.y); t1.z = f*(duv2.y*edge1.z-duv1.y*edge2.z); bit1.x = f*(-duv2.x*edge1.x+duv1.x*edge2.x); bit1.y = f*(-duv2.x*edge1.y+duv1.x*edge2.y); bit1.z = f*(-duv2.x*edge1.z+duv1.x*edge2.z); edge1 = v3f_sub(p3, p1); edge2 = v3f_sub(p4, p1); duv1 = v2f_sub(uv3, uv1); duv2 = v2f_sub(uv4, uv1); f = 1.0f/(duv1.x*duv2.y-duv2.x*duv1.y); t2.x = f*(duv2.y*edge1.x-duv1.y*edge2.x); t2.y = f*(duv2.y*edge1.y-duv1.y*edge2.y); t2.z = f*(duv2.y*edge1.z-duv1.y*edge2.z); bit2.x = f*(-duv2.x*edge1.x+duv1.x*edge2.x); bit2.y = f*(-duv2.x*edge1.y+duv1.x*edge2.y); bit2.z = f*(-duv2.x*edge1.z+duv1.x*edge2.z); F32 quad_vertices[] = { p1.x, p1.y, p1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, t1.x, t1.y, t1.z, bit1.x, bit1.y, bit1.z, p2.x, p2.y, p2.z, nm.x, nm.y, nm.z, uv2.x, uv2.y, t1.x, t1.y, t1.z, bit1.x, bit1.y, bit1.z, p3.x, p3.y, p3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, t1.x, t1.y, t1.z, bit1.x, bit1.y, bit1.z, p1.x, p1.y, p1.z, nm.x, nm.y, nm.z, uv1.x, uv1.y, t2.x, t2.y, t2.z, bit2.x, bit2.y, bit2.z, p3.x, p3.y, p3.z, nm.x, nm.y, nm.z, uv3.x, uv3.y, t2.x, t2.y, t2.z, bit2.x, bit2.y, bit2.z, p4.x, p4.y, p4.z, nm.x, nm.y, nm.z, uv4.x, uv4.y, t2.x, t2.y, t2.z, bit2.x, bit2.y, bit2.z }; U32 quad_vao, vbo; glGenVertexArrays(1, &quad_vao); glBindVertexArray(quad_vao); glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14*sizeof(F32), (void *)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14*sizeof(F32), (void *)(3*sizeof(F32))); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14*sizeof(F32), (void *)(6*sizeof(F32))); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14*sizeof(F32), (void *)(8*sizeof(F32))); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14*sizeof(F32), (void *)(11*sizeof(F32))); glBindVertexArray(0); return quad_vao; } int main(void) { GLFWwindow *window; State state; Input input = {0}; F64 time, last_time; V3F camera_dp; Arena *arena = 0; S32 width, height; U32 vao, parallax_shader, normals_debug_shader; U32 diffuse_texture, normal_texture, depth_texture; V3F light_pos; width = 800; height = 600; /* 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); window = glfwCreateWindow(width, height, "Point shadows", 0, 0); if (!window) goto error; glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwMakeContextCurrent(window); if (glewInit() != GLEW_OK) goto error; /* NOTE(pryazha): Program init */ arena = arena_alloc(Kilobytes(4)); input.first_mouse = 1; state.camera = (Camera){ v3f(0.0f, 0.0f, 3.0f), 90.0f, 0.1f, 100.0f, 0.0f, 0.0f }; camera_dp = v3f_zero(); light_pos = v3f(1.0f, 2.0f, 1.0f); /* NOTE(pryazha): Meshes */ vao = gen_quad_with_tan(); diffuse_texture = load_texture("../../data/textures/bricks2.jpg"); normal_texture = load_texture("../../data/textures/bricks2_normal.jpg"); depth_texture = load_texture("../../data/textures/bricks2_disp.jpg"); /* NOTE(pryazha): Shaders */ parallax_shader = create_shader_program("shaders/parallax.vert", "shaders/parallax.frag"); normals_debug_shader = create_shader_program_geom("shaders/normals_debug.vert", "shaders/normals_debug.frag", "shaders/normals_debug.geom"); glUseProgram(parallax_shader); shader_set_1i(parallax_shader, "diffuse_texture", 0); shader_set_1i(parallax_shader, "normal_map", 1); shader_set_1i(parallax_shader, "depth_map", 2); glUseProgram(0); last_time = glfwGetTime(); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); /* NOTE(pryazha): Update */ F32 speed, sensitivity; V3F dv; glfwGetFramebufferSize(window, &width, &height); process_glfw_keyboard(window, &input); process_glfw_mouse_pos(window, &input); if (key_first_press(input.exit)) glfwSetWindowShouldClose(window, GLFW_TRUE); speed = 2.0f; dv = get_dv_camera_first_person(&input, &state.camera, speed, state.dt); if (key_is_pressed(input.action_up)) dv = v3f_scalef(dv, 3.0f); camera_dp = v3f_add(camera_dp, dv); camera_dp = v3f_scalef(camera_dp, 0.8f); state.camera.pos = v3f_add(state.camera.pos, camera_dp); sensitivity = 0.1f; input.mouse_offset = v2f_scalef(input.mouse_offset, sensitivity); state.camera.yaw += input.mouse_offset.x; state.camera.pitch += 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; input_update_last_state(&input); /* NOTE(pryazha): Render */ F32 ar; MAT4 proj, view, model; ar = (F32)width/(F32)height; proj = camera_persp(state.camera, ar); view = get_view_matrix(&state.camera); model = mat4_identity(); glViewport(0, 0, width, height); glClearColor(0.15f, 0.15f, 0.15f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* NOTE(pryazha): Draw the quad */ glUseProgram(parallax_shader); shader_set_mat4fv(parallax_shader, "proj", proj); shader_set_mat4fv(parallax_shader, "view", view); shader_set_mat4fv(parallax_shader, "model", model); shader_set_3fv(parallax_shader, "light_pos", light_pos); shader_set_3fv(parallax_shader, "view_pos", state.camera.pos); shader_set_1f(parallax_shader, "hscale", 0.1f); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, diffuse_texture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal_texture); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, depth_texture); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glUseProgram(0); /* NOTE(pryazha): Draw normals */ glUseProgram(normals_debug_shader); shader_set_mat4fv(normals_debug_shader, "proj", proj); shader_set_mat4fv(normals_debug_shader, "model", model); shader_set_mat4fv(normals_debug_shader, "view", view); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, diffuse_texture); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal_texture); glBindVertexArray(vao); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glUseProgram(0); glfwSwapBuffers(window); time = glfwGetTime(); state.dt = time-last_time; last_time = time; } glDeleteVertexArrays(1, &vao); arena_release(arena); glfwTerminate(); return(0); error: arena_release(arena); glfwTerminate(); return(1); }