A 3D game engine from scratch.
at main 170 lines 6.0 kB view raw
1// (c) 2020 Vlad-Stefan Harbuz <vlad@vladh.net> 2 3#include "geom.hpp" 4 5 6void 7geom::setup_mesh_vertex_buffers( 8 Mesh *mesh, 9 Vertex *vertex_data, u32 n_vertices, 10 u32 *index_data, u32 n_indices 11) { 12 assert(vertex_data && n_vertices > 0); 13 14 u32 vertex_size = sizeof(Vertex); 15 u32 index_size = sizeof(u32); 16 17 glGenVertexArrays(1, &mesh->vao); 18 glGenBuffers(1, &mesh->vbo); 19 glGenBuffers(1, &mesh->ebo); 20 21 glBindVertexArray(mesh->vao); 22 23 glBindBuffer(GL_ARRAY_BUFFER, mesh->vbo); 24 glBufferData(GL_ARRAY_BUFFER, vertex_size * n_vertices, vertex_data, GL_STATIC_DRAW); 25 26 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->ebo); 27 glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size * n_indices, index_data, GL_STATIC_DRAW); 28 29 u32 location; 30 31 location = 0; 32 glEnableVertexAttribArray(location); 33 glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)offsetof(Vertex, position)); 34 35 location = 1; 36 glEnableVertexAttribArray(location); 37 glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)offsetof(Vertex, normal)); 38 39 location = 2; 40 glEnableVertexAttribArray(location); 41 glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, vertex_size, (void*)offsetof(Vertex, tex_coords)); 42 43 location = 3; 44 glEnableVertexAttribArray(location); 45 glVertexAttribIPointer(location, MAX_N_BONES_PER_VERTEX, GL_INT, vertex_size, (void*)offsetof(Vertex, bone_idxs)); 46 47 location = 4; 48 glEnableVertexAttribArray(location); 49 glVertexAttribPointer(location, MAX_N_BONES_PER_VERTEX, GL_FLOAT, GL_FALSE, vertex_size, 50 (void*)offsetof(Vertex, bone_weights)); 51} 52 53 54bool 55geom::is_mesh_valid(geom::Mesh *mesh) 56{ 57 return mesh->vao > 0; 58} 59 60 61void 62geom::destroy_mesh(geom::Mesh *mesh) 63{ 64 glDeleteVertexArrays(1, &mesh->vao); 65 glDeleteBuffers(1, &mesh->vbo); 66 glDeleteBuffers(1, &mesh->ebo); 67} 68 69 70void 71geom::make_plane( 72 memory::Pool *memory_pool, 73 u32 x_size, u32 z_size, 74 u32 n_x_segments, u32 n_z_segments, 75 u32 *n_vertices, u32 *n_indices, 76 geom::Vertex **vertex_data, u32 **index_data 77) { 78 *n_vertices = 0; 79 *n_indices = 0; 80 81 u32 n_total_vertices = (n_x_segments + 1) * (n_z_segments + 1); 82 u32 index_data_length = (n_x_segments) * (n_z_segments) * 6; 83 84 *vertex_data = (geom::Vertex*)memory::push(memory_pool, sizeof(geom::Vertex) * n_total_vertices, "plane_vertex_data"); 85 *index_data = (u32*)memory::push(memory_pool, sizeof(u32) * index_data_length, "plane_index_data"); 86 87 for (u32 idx_x = 0; idx_x <= n_x_segments; idx_x++) { 88 for (u32 idx_z = 0; idx_z <= n_z_segments; idx_z++) { 89 f32 x_segment = (f32)idx_x / (f32)n_x_segments; 90 f32 z_segment = (f32)idx_z / (f32)n_z_segments; 91 f32 x_pos = x_segment * x_size - (x_size / 2); 92 f32 y_pos = 0; 93 f32 z_pos = z_segment * z_size - (z_size / 2); 94 95 (*vertex_data)[(*n_vertices)++] = { 96 .position = { x_pos, y_pos, z_pos }, 97 .normal = { 0.0f, 1.0f, 0.0f }, 98 .tex_coords = { x_segment, z_segment }, 99 }; 100 } 101 } 102 103 // NOTE: Counterclockwise winding order. I could swear this code is CW 104 // order though. Not sure where the confusion happens. 105 for (u32 idx_x = 0; idx_x < n_x_segments; idx_x++) { 106 for (u32 idx_z = 0; idx_z < n_z_segments; idx_z++) { 107 // This current vertex. 108 (*index_data)[(*n_indices)++] = (idx_x * (n_z_segments + 1)) + idx_z; 109 // Next row, right of this one. 110 (*index_data)[(*n_indices)++] = ((idx_x + 1) * (n_z_segments + 1)) + idx_z + 1; 111 // Next row, under this one. 112 (*index_data)[(*n_indices)++] = ((idx_x + 1) * (n_z_segments + 1)) + idx_z; 113 114 // This current vertex. 115 (*index_data)[(*n_indices)++] = (idx_x * (n_z_segments + 1)) + idx_z; 116 // This row, right of this one. 117 (*index_data)[(*n_indices)++] = (idx_x * (n_z_segments + 1)) + idx_z + 1; 118 // Next row, right of this one. 119 (*index_data)[(*n_indices)++] = ((idx_x + 1) * (n_z_segments + 1)) + idx_z + 1; 120 } 121 } 122} 123 124 125void 126geom::make_sphere( 127 memory::Pool *memory_pool, 128 u32 n_x_segments, u32 n_y_segments, 129 u32 *n_vertices, u32 *n_indices, 130 geom::Vertex **vertex_data, u32 **index_data 131) { 132 *n_vertices = 0; 133 *n_indices = 0; 134 135 u32 total_n_vertices = (n_x_segments + 1) * (n_y_segments + 1); 136 u32 index_data_length = (n_x_segments + 1) * (n_y_segments) * 2; 137 138 *vertex_data = (geom::Vertex*)memory::push(memory_pool, sizeof(geom::Vertex) * total_n_vertices, "sphere_vertex_data"); 139 *index_data = (u32*)memory::push(memory_pool, sizeof(u32) * index_data_length, "sphere_index_data"); 140 141 for (u32 y = 0; y <= n_y_segments; y++) { 142 for (u32 x = 0; x <= n_x_segments; x++) { 143 f32 x_segment = (f32)x / (f32)n_x_segments; 144 f32 y_segment = (f32)y / (f32)n_y_segments; 145 f32 x_pos = cos(x_segment * 2.0f * PI32) * sin(y_segment * PI32); 146 f32 y_pos = cos(y_segment * PI32); 147 f32 z_pos = sin(x_segment * 2.0f * PI32) * sin(y_segment * PI32); 148 149 (*vertex_data)[(*n_vertices)++] = { 150 .position = {x_pos, y_pos, z_pos}, 151 .normal = {x_pos, y_pos, z_pos}, 152 .tex_coords = {x_segment, y_segment}, 153 }; 154 } 155 } 156 157 for (u32 y = 0; y < n_y_segments; y++) { 158 if (y % 2 == 0) { 159 for (u32 x = 0; x <= n_x_segments; x++) { 160 (*index_data)[(*n_indices)++] = (y + 1) * (n_x_segments + 1) + x; 161 (*index_data)[(*n_indices)++] = y * (n_x_segments + 1) + x; 162 } 163 } else { 164 for (i32 x = n_x_segments; x >= 0; x--) { 165 (*index_data)[(*n_indices)++] = y * (n_x_segments + 1) + x; 166 (*index_data)[(*n_indices)++] = (y + 1) * (n_x_segments + 1) + x; 167 } 168 } 169 } 170}