diff options
author | pryazha <pryadeiniv@mail.ru> | 2025-01-23 19:39:54 +0500 |
---|---|---|
committer | pryazha <pryadeiniv@mail.ru> | 2025-01-23 19:39:54 +0500 |
commit | bf1c59565096ac9774493846cfb15e259d3b0e66 (patch) | |
tree | 82e8182af128580b6f38437feccba8c0f48abdc1 /advanced_opengl/9.instancing/instancing.c | |
parent | 1ee094199af9c169e1ccaa53c7b0c186c4a3639e (diff) |
restructure
Diffstat (limited to 'advanced_opengl/9.instancing/instancing.c')
-rw-r--r-- | advanced_opengl/9.instancing/instancing.c | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/advanced_opengl/9.instancing/instancing.c b/advanced_opengl/9.instancing/instancing.c new file mode 100644 index 0000000..90647fb --- /dev/null +++ b/advanced_opengl/9.instancing/instancing.c @@ -0,0 +1,402 @@ +#include "GL/glew.h" +#include "GLFW/glfw3.h" + +#include "pwyazh.h" + +#include "pwyazh_GL.h" + +#include "common.h" + +#include <unistd.h> + +static S32 global_width = 1024, global_height = 768; +static Input global_input; + +void +key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) +{ + switch (action) + { + case GLFW_PRESS: { + switch (key) + { + case GLFW_KEY_D: { + global_input.move_right.state = KeyState_PRESS; + } break; + case GLFW_KEY_W: { + global_input.move_forward.state = KeyState_PRESS; + } break; + case GLFW_KEY_A: { + global_input.move_left.state = KeyState_PRESS; + } break; + case GLFW_KEY_S: { + global_input.move_backward.state = KeyState_PRESS; + } break; + case GLFW_KEY_E: { + global_input.move_up.state = KeyState_PRESS; + } break; + case GLFW_KEY_Q: { + global_input.move_down.state = KeyState_PRESS; + } break; + case GLFW_KEY_SPACE: { + global_input.jump.state = KeyState_PRESS; + } break; + case GLFW_KEY_RIGHT: { + global_input.action_right.state = KeyState_PRESS; + } break; + case GLFW_KEY_LEFT: { + global_input.action_left.state = KeyState_PRESS; + } break; + case GLFW_KEY_ESCAPE: { + global_input.exit.state = KeyState_PRESS; + } break; + } + } break; + + case GLFW_RELEASE: { + switch (key) + { + case GLFW_KEY_D: { + global_input.move_right.state = KeyState_RELEASE; + } break; + case GLFW_KEY_W: { + global_input.move_forward.state = KeyState_RELEASE; + } break; + case GLFW_KEY_A: { + global_input.move_left.state = KeyState_RELEASE; + } break; + case GLFW_KEY_S: { + global_input.move_backward.state = KeyState_RELEASE; + } break; + case GLFW_KEY_E: { + global_input.move_up.state = KeyState_RELEASE; + } break; + case GLFW_KEY_Q: { + global_input.move_down.state = KeyState_RELEASE; + } break; + case GLFW_KEY_SPACE: { + global_input.jump.state = KeyState_RELEASE; + } break; + case GLFW_KEY_RIGHT: { + global_input.action_right.state = KeyState_RELEASE; + } break; + case GLFW_KEY_LEFT: { + global_input.action_left.state = KeyState_RELEASE; + } break; + case GLFW_KEY_ESCAPE: { + global_input.exit.state = KeyState_RELEASE; + } break; + } + } break; + } +} + +void +window_resize_callback(GLFWwindow* window, int width, int height) +{ + global_width = width; + global_height = height; + glViewport(0, 0, global_width, global_height); +} + +int +main(void) +{ + GLFWwindow *window; + Arena *arena = 0; + + if (glfwInit() == GLFW_FALSE) + { + fprintf(stderr, "[ERROR] Failed to initialize glfw.\n"); + return(1); + } + + /* glfwWindowHint(GLFW_RESIZABLE, 0); */ + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + window = glfwCreateWindow(global_width, global_height, "Instancing", 0, 0); + if (!window) + { + fprintf(stderr, "[ERROR] Failed to create window.\n"); + glfwTerminate(); + return(1); + } + + glfwMakeContextCurrent(window); + + glfwSetKeyCallback(window, key_callback); + glfwSetWindowSizeCallback(window, window_resize_callback); + + 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.vs", + "shaders/instancing_uniform_array.fs"); + U32 instanced_arrays_shader = + create_shader_program("shaders/instanced_arrays.vs", + "shaders/instanced_arrays.fs"); + + 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)); + + U32 default_shader = create_shader_program("shaders/default.vs", "shaders/default.fs"); + U32 instanced_shader = create_shader_program("shaders/instanced_mat4.vs", + "shaders/instanced_mat4.fs"); + Mesh *planet_mesh = mesh_load_obj(arena, "../../data/models/planet/planet.obj"); + U32 planet_texture = load_texture("../../data/models/planet/mars.png"); + Mesh *rock_mesh = mesh_load_obj(arena, "../../data/models/rock/rock.obj"); + 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); + + F32 target_fps = 60.0f; + F32 target_spf = 1.0f/target_fps; + + F32 last_time = glfwGetTime(); + F32 time = last_time; + F32 dt; + + S32 scene = 0; + S32 number_scene = 4; + + MAT4 projection, view, model; + + V3F camera_pos = v3f(0.0f, 50.0f, 220.0f); + F32 camera_speed = 10.0f; + F32 fovx = 90.0f; + F32 near = 0.1f; + F32 far = 1000.0f; + + while (!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + + /* NOTE(pryazha): Update */ + if (key_is_pressed(global_input.exit)) + { + glfwSetWindowShouldClose(window, GLFW_TRUE); + } + if (key_first_press(global_input.jump) || + key_first_press(global_input.action_right)) + { + scene++; + } + else if (key_first_press(global_input.action_left)) + { + scene--; + if (scene < 0) + scene = number_scene-1; + } + scene %= number_scene; + + /* NOTE(pryazha): Render */ + 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 translation_index = 0; + translation_index < 100; + ++translation_index) + { + char temp[256]; + snprintf(temp, 256, "offsets[%d]", translation_index); + shader_set_2fv(instancing_uniform_array_shader, + temp, translations[translation_index]); + } + 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: { + camera_pos = update_camera_orbital(global_input, + camera_pos, v3f_zero(), + dt, camera_speed); + + projection = perspective(fovx, (F32)global_width/(F32)global_height, near, far); + V3F world_up = v3f(0.0f, 1.0f, 0.0f); + view = look_at(camera_pos, v3f_zero(), world_up); + + glUseProgram(default_shader); + shader_set_mat4fv(default_shader, "projection", projection); + shader_set_mat4fv(default_shader, "view", view); + + F32 scale = 5.0f; + 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: { + camera_pos = update_camera_orbital(global_input, + camera_pos, v3f_zero(), + dt, camera_speed); + + projection = perspective(fovx, (F32)global_width/(F32)global_height, near, far); + V3F world_up = v3f(0.0f, 1.0f, 0.0f); + view = look_at(camera_pos, v3f_zero(), world_up); + + glUseProgram(default_shader); + shader_set_mat4fv(default_shader, "projection", projection); + shader_set_mat4fv(default_shader, "view", view); + F32 scale = 5.0f; + 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, "projection", projection); + 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; + } + + input_update_last_state(&global_input); + + 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(); + dt = current_time-last_time; + time += dt; + last_time = current_time; + } + + glfwTerminate(); + return(0); +} |