#include "GL/glew.h" #include "GLFW/glfw3.h" #include "pwyazh.h" #include "pwyazh_GL.h" #include "common.h" int main(void) { GLFWwindow *window; State state; S32 width, height; Input input; Arena *arena = 0; B32 move_camera; if (glfwInit() == GLFW_FALSE) { fprintf(stderr, "[ERROR] Failed to initialize glfw.\n"); return(1); } width = 1024; height = 768; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); window = glfwCreateWindow(width, height, "Instancing", 0, 0); if (!window) { fprintf(stderr, "[ERROR] Failed to create window.\n"); glfwTerminate(); return(1); } glfwMakeContextCurrent(window); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); if (glewInit() != GLEW_OK) { fprintf(stderr, "[ERROR] Failed to initialize glew.\n"); glfwTerminate(); return(1); } glEnable(GL_DEPTH_TEST); U32 instancing_uniform_array_shader = create_shader_program("shaders/instancing_uniform_array.vert", "shaders/instancing_uniform_array.frag"); U32 instanced_arrays_shader = create_shader_program("shaders/instanced_arrays.vert", "shaders/instanced_arrays.frag"); U32 default_shader = create_shader_program("shaders/default.vert", "shaders/default.frag"); U32 instanced_shader = create_shader_program("shaders/instanced_mat4.vert", "shaders/instanced_mat4.frag"); F32 quad_vertices[] = { -0.05f, 0.05f, 1.0f, 0.0f, 0.0f, 0.05f, -0.05f, 0.0f, 1.0f, 0.0f, -0.05f, -0.05f, 0.0f, 0.0f, 1.0f, -0.05f, 0.05f, 1.0f, 0.0f, 0.0f, 0.05f, -0.05f, 0.0f, 1.0f, 0.0f, 0.05f, 0.05f, 0.0f, 1.0f, 1.0f, }; GLuint 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, 2, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)0); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5*sizeof(F32), (void *)(2*sizeof(F32))); glBindVertexArray(0); V2F translations[100]; S32 index = 0; F32 offset = 0.1f; for (S32 y = -10; y < 10; y += 2) { for (S32 x = -10; x < 10; x += 2) { V2F translation = v2f((F32)x, (F32)y); translation = v2f_scalef(translation, 1.0f/10.0f); translation = v2f_add(translation, v2f(offset, offset)); translations[index++] = translation; } } U32 instance_vbo; glBindVertexArray(quad_vao); glGenBuffers(1, &instance_vbo); glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(translations), translations, GL_STATIC_DRAW); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(V2F), (void *)0); glBindBuffer(GL_ARRAY_BUFFER, 0); glVertexAttribDivisor(2, 1); glBindVertexArray(0); arena = arena_alloc(Megabytes(64)); Mesh *planet_mesh = mesh_load_obj(arena, "../../data/models/planet/planet.obj"); Mesh *rock_mesh = mesh_load_obj(arena, "../../data/models/rock/rock.obj"); U32 planet_texture = load_texture("../../data/models/planet/mars.png"); U32 rock_texture = load_texture("../../data/models/rock/rock.png"); S32 amount = 80000; F32 radius = 150.0f; offset = 25.0f; MAT4 trns[amount]; for (S32 i = 0; i < amount; ++i) { F32 angle, displacement, x, y, z, scale; MAT4 model = mat4_identity(); angle = rand()%360; model = mat4_rotate_angles(model, v3f(angle, angle, angle)); scale = (rand()%20)/100.0f+0.05f; model = mat4_scale(model, v3f(scale, scale, scale)); angle = ((F32)i/(F32)amount)*360.0f; displacement = (rand()%(S32)(2.0f*offset))-offset; x = f32_sin(DEG2RAD*angle)*radius+displacement; displacement = (rand()%(S32)(2.0f*offset))-offset; y = 0.4f*displacement; displacement = (rand()%(S32)(2.0f*offset))-offset; z = f32_cos(DEG2RAD*angle)*radius; model = mat4_translate(model, v3f(x, y, z)); trns[i] = model; } U32 buffer; glGenBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, amount*sizeof(MAT4), &trns[0], GL_STATIC_DRAW); glBindVertexArray(rock_mesh->vao); glEnableVertexAttribArray(3); glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 4*sizeof(V4F), (void *)0); glEnableVertexAttribArray(4); glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4*sizeof(V4F), (void *)(1*sizeof(V4F))); glEnableVertexAttribArray(5); glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, 4*sizeof(V4F), (void *)(2*sizeof(V4F))); glEnableVertexAttribArray(6); glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, 4*sizeof(V4F), (void *)(3*sizeof(V4F))); glVertexAttribDivisor(3, 1); glVertexAttribDivisor(4, 1); glVertexAttribDivisor(5, 1); glVertexAttribDivisor(6, 1); glBindVertexArray(0); state.camera = (Camera) { v3f(0.0f, 50.0f, 220.0f), 90.0f, 0.1f, 1000.0f, 0.0f, 0.0f }; F32 camera_speed = 10.0f; F32 target_fps = 60.0f; F32 target_spf = 1.0f/target_fps; F32 last_time = glfwGetTime(); F32 time = last_time; S32 scene = 0; S32 number_scene = 4; while (!glfwWindowShouldClose(window)) { glfwPollEvents(); /* NOTE(pryazha): Update */ glfwGetFramebufferSize(window, &width, &height); process_glfw_keyboard(window, &input); process_glfw_mouse_pos(window, &input); if (key_is_pressed(input.exit)) glfwSetWindowShouldClose(window, GLFW_TRUE); if (key_first_press(input.jump) || key_first_press(input.action_right)) { scene++; } else if (key_first_press(input.action_left)) { scene--; if (scene < 0) scene = number_scene-1; } scene %= number_scene; move_camera = (scene > 1) ? 1 : 0; if (move_camera) { V3F dv = get_dv_camera_first_person(&input, &state.camera, 4.0f, state.dt); state.camera.pos = v3f_add(state.camera.pos, dv); F32 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 */ MAT4 proj, view, model; F32 scale = 5.0f; view = get_view_matrix(&state.camera); proj = perspective(state.camera.fovx, (F32)width/(F32)height, state.camera.near, state.camera.far); glClearColor(0.15f, 0.15f, 0.15f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); switch (scene) { case 0: glUseProgram(instancing_uniform_array_shader); for (S32 i = 0; i < 100; ++i) { char temp[256]; snprintf(temp, 256, "offsets[%d]", i); shader_set_2fv(instancing_uniform_array_shader, temp, translations[i]); } glBindVertexArray(quad_vao); glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100); glBindVertexArray(0); break; case 1: glUseProgram(instanced_arrays_shader); glBindVertexArray(quad_vao); glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 100); glBindVertexArray(0); break; case 2: glUseProgram(default_shader); shader_set_mat4fv(default_shader, "proj", proj); shader_set_mat4fv(default_shader, "view", view); model = mat4_make_scale(v3f(scale, scale, scale)); shader_set_mat4fv(default_shader, "model", model); glBindTexture(GL_TEXTURE_2D, planet_texture); mesh_draw(planet_mesh); glBindTexture(GL_TEXTURE_2D, rock_texture); for (S32 i = 0; i < amount; ++i) { model = trns[i]; shader_set_mat4fv(default_shader, "model", model); mesh_draw(rock_mesh); } break; case 3: glUseProgram(default_shader); shader_set_mat4fv(default_shader, "proj", proj); shader_set_mat4fv(default_shader, "view", view); model = mat4_make_scale(v3f(scale, scale, scale)); shader_set_mat4fv(default_shader, "model", model); glBindTexture(GL_TEXTURE_2D, planet_texture); mesh_draw(planet_mesh); glBindTexture(GL_TEXTURE_2D, 0); glUseProgram(instanced_shader); shader_set_mat4fv(default_shader, "proj", proj); shader_set_mat4fv(default_shader, "view", view); glBindTexture(GL_TEXTURE_2D, rock_texture); glBindVertexArray(rock_mesh->vao); glDrawElementsInstanced(GL_TRIANGLES, rock_mesh->index_count, GL_UNSIGNED_INT, 0, amount); glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); break; } glfwSwapBuffers(window); F32 elapsed = glfwGetTime()-last_time; if (elapsed < target_spf) { U32 sleep_time = (U32)(target_spf-elapsed); if (sleep_time > 0) sleep(sleep_time); } F32 current_time = glfwGetTime(); state.dt = current_time-last_time; time += state.dt; last_time = current_time; } glfwTerminate(); return(0); }