A 3D game engine from scratch.
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}