libs/render/src/eu/render/world.cc
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "eu/render/world.h" | ||
| 2 | |||
| 3 | #include "eu/assert/assert.h" | ||
| 4 | |||
| 5 | |||
| 6 | #include "eu/core/geom.extract.h" | ||
| 7 | #include "eu/render/opengl_utils.h" | ||
| 8 | #include "eu/render/shader.h" | ||
| 9 | #include "eu/core/vertex_layout.h" | ||
| 10 | |||
| 11 | #include <utility> | ||
| 12 | |||
| 13 | namespace eu::render | ||
| 14 | { | ||
| 15 | |||
| 16 | ✗ | CompiledGeom::CompiledGeom(u32 b, u32 a, u32 e, const core::CompiledGeomVertexAttributes& att, i32 tc) | |
| 17 | ✗ | : vbo(b) | |
| 18 | ✗ | , vao(a) | |
| 19 | ✗ | , ebo(e) | |
| 20 | ✗ | , number_of_triangles(tc) | |
| 21 | ✗ | , debug_types(att.debug_types.begin(), att.debug_types.end()) | |
| 22 | |||
| 23 | { | ||
| 24 | ✗ | } | |
| 25 | |||
| 26 | ✗ | CompiledGeom_TransformInstance::CompiledGeom_TransformInstance( | |
| 27 | u32 iv, std::size_t mi, u32 b, u32 a, u32 e, const core::CompiledGeomVertexAttributes& att, i32 tc | ||
| 28 | ✗ | ) | |
| 29 | ✗ | : instance_vbo(iv) | |
| 30 | ✗ | , max_instances(mi) | |
| 31 | ✗ | , vbo(b) | |
| 32 | ✗ | , vao(a) | |
| 33 | ✗ | , ebo(e) | |
| 34 | ✗ | , number_of_triangles(tc) | |
| 35 | ✗ | , debug_types(att.debug_types.begin(), att.debug_types.end()) | |
| 36 | |||
| 37 | { | ||
| 38 | ✗ | } | |
| 39 | |||
| 40 | ✗ | std::shared_ptr<MeshInstance> make_mesh_instance(std::shared_ptr<CompiledGeom> geom, std::shared_ptr<Material> mat) | |
| 41 | { | ||
| 42 | ✗ | auto instance = std::make_shared<MeshInstance>(); | |
| 43 | ✗ | instance->geom = std::move(geom); | |
| 44 | ✗ | instance->material = std::move(mat); | |
| 45 | ✗ | return instance; | |
| 46 | } | ||
| 47 | |||
| 48 | ✗ | std::shared_ptr<MeshInstance_TransformInstanced> make_mesh_instance( | |
| 49 | std::shared_ptr<CompiledGeom_TransformInstance> geom, std::shared_ptr<Material> mat | ||
| 50 | ) | ||
| 51 | { | ||
| 52 | ✗ | auto instance = std::make_shared<MeshInstance_TransformInstanced>(); | |
| 53 | ✗ | instance->geom = std::move(geom); | |
| 54 | ✗ | instance->material = std::move(mat); | |
| 55 | ✗ | return instance; | |
| 56 | } | ||
| 57 | |||
| 58 | ✗ | std::shared_ptr<CompiledGeom> compile_geom(DEBUG_LABEL_ARG_MANY const core::Geom& geom, const core::CompiledGeomVertexAttributes& geom_layout) | |
| 59 | { | ||
| 60 | ✗ | const auto ex = extract_geom(geom, geom_layout); | |
| 61 | |||
| 62 | ✗ | const auto vao = create_vertex_array(); | |
| 63 | ✗ | glBindVertexArray(vao); | |
| 64 | ✗ | SET_DEBUG_LABEL_NAMED(vao, DebugLabelFor::VertexArray, fmt::format("VERT {}", debug_label)); | |
| 65 | |||
| 66 | ✗ | const auto vbo = create_buffer(); | |
| 67 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
| 68 | ✗ | SET_DEBUG_LABEL_NAMED(vbo, DebugLabelFor::Buffer, fmt::format("ARR BUF {}", debug_label)); | |
| 69 | ✗ | glBufferData(GL_ARRAY_BUFFER, glsizeiptr_from_sizet(ex.data.size()), ex.data.data(), GL_STATIC_DRAW); | |
| 70 | |||
| 71 | ✗ | const auto get_type = [](const core::ExtractedAttribute& extracted) -> GLenum | |
| 72 | { | ||
| 73 | ✗ | switch (extracted.type) | |
| 74 | { | ||
| 75 | ✗ | case core::ExtractedAttributeType::Float: return GL_FLOAT; | |
| 76 | ✗ | default: DIE("invalid extracted attribute"); return GL_FLOAT; | |
| 77 | } | ||
| 78 | }; | ||
| 79 | |||
| 80 | ✗ | const auto stride = ex.stride; | |
| 81 | ✗ | int attrib_location = 0; | |
| 82 | ✗ | std::size_t offset = 0; | |
| 83 | ✗ | for (const auto& att: ex.attributes) | |
| 84 | { | ||
| 85 | ✗ | constexpr auto normalize = false; | |
| 86 | ✗ | glVertexAttribPointer( | |
| 87 | gluint_from_int(attrib_location), | ||
| 88 | ✗ | att.count, | |
| 89 | get_type(att), | ||
| 90 | normalize ? GL_TRUE : GL_FALSE, | ||
| 91 | glsizei_from_sizet(stride), | ||
| 92 | reinterpret_cast<void*>(offset) | ||
| 93 | ); | ||
| 94 | ✗ | glEnableVertexAttribArray(gluint_from_int(attrib_location)); | |
| 95 | |||
| 96 | ✗ | attrib_location += 1; | |
| 97 | ✗ | offset += att.size; | |
| 98 | } | ||
| 99 | |||
| 100 | |||
| 101 | ✗ | const auto ebo = create_buffer(); | |
| 102 | ✗ | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); | |
| 103 | ✗ | SET_DEBUG_LABEL_NAMED(ebo, DebugLabelFor::Buffer, fmt::format("IND BUF {}", debug_label)); | |
| 104 | |||
| 105 | ✗ | glBufferData( | |
| 106 | GL_ELEMENT_ARRAY_BUFFER, | ||
| 107 | ✗ | glsizeiptr_from_sizet(sizeof(u32) * ex.indices.size()), | |
| 108 | ✗ | ex.indices.data(), | |
| 109 | GL_STATIC_DRAW | ||
| 110 | ); | ||
| 111 | |||
| 112 | ✗ | return std::make_shared<CompiledGeom>(vbo, vao, ebo, geom_layout, ex.face_size); | |
| 113 | ✗ | } | |
| 114 | |||
| 115 | ✗ | CompiledGeom::~CompiledGeom() | |
| 116 | { | ||
| 117 | ✗ | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 118 | ✗ | destroy_buffer(ebo); | |
| 119 | |||
| 120 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 121 | ✗ | destroy_buffer(vbo); | |
| 122 | |||
| 123 | ✗ | glBindVertexArray(0); | |
| 124 | ✗ | destroy_vertex_array(vao); | |
| 125 | ✗ | } | |
| 126 | |||
| 127 | ✗ | std::shared_ptr<CompiledGeom_TransformInstance> compile_geom_with_transform_instance( | |
| 128 | DEBUG_LABEL_ARG_MANY | ||
| 129 | const core::Geom& geom, const core::CompiledGeomVertexAttributes& geom_layout, std::size_t max_instances | ||
| 130 | ) | ||
| 131 | { | ||
| 132 | ✗ | const auto ex = extract_geom(geom, geom_layout); | |
| 133 | |||
| 134 | ✗ | const auto vao = create_vertex_array(); | |
| 135 | ✗ | glBindVertexArray(vao); | |
| 136 | ✗ | SET_DEBUG_LABEL_NAMED(vao, DebugLabelFor::VertexArray, fmt::format("VERT (in) {}", debug_label)); | |
| 137 | |||
| 138 | ✗ | const auto vbo = create_buffer(); | |
| 139 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, vbo); | |
| 140 | ✗ | SET_DEBUG_LABEL_NAMED(vbo, DebugLabelFor::Buffer, fmt::format("ARR BUF (in) {}", debug_label)); | |
| 141 | ✗ | glBufferData(GL_ARRAY_BUFFER, glsizeiptr_from_sizet(ex.data.size()), ex.data.data(), GL_STATIC_DRAW); | |
| 142 | |||
| 143 | ✗ | const auto get_type = [](const core::ExtractedAttribute& extracted) -> GLenum | |
| 144 | { | ||
| 145 | ✗ | switch (extracted.type) | |
| 146 | { | ||
| 147 | ✗ | case core::ExtractedAttributeType::Float: return GL_FLOAT; | |
| 148 | ✗ | default: DIE("invalid extracted attribute"); return GL_FLOAT; | |
| 149 | } | ||
| 150 | }; | ||
| 151 | |||
| 152 | ✗ | const auto stride = ex.stride; | |
| 153 | ✗ | int attrib_location = 0; | |
| 154 | ✗ | std::size_t offset = 0; | |
| 155 | ✗ | for (const auto& att: ex.attributes) | |
| 156 | { | ||
| 157 | ✗ | constexpr auto normalize = false; | |
| 158 | ✗ | glVertexAttribPointer( | |
| 159 | gluint_from_int(attrib_location), | ||
| 160 | ✗ | att.count, | |
| 161 | get_type(att), | ||
| 162 | normalize ? GL_TRUE : GL_FALSE, | ||
| 163 | glsizei_from_sizet(stride), | ||
| 164 | reinterpret_cast<void*>(offset) | ||
| 165 | ); | ||
| 166 | ✗ | glEnableVertexAttribArray(gluint_from_int(attrib_location)); | |
| 167 | |||
| 168 | ✗ | attrib_location += 1; | |
| 169 | ✗ | offset += att.size; | |
| 170 | } | ||
| 171 | |||
| 172 | // finally bind instance_vbo data, use a dummy data since the data will be uploaded before rendering | ||
| 173 | // todo(Gustav): is dynamic draw correct? | ||
| 174 | ✗ | const auto instance_vbo = create_buffer(); | |
| 175 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, instance_vbo); | |
| 176 | ✗ | SET_DEBUG_LABEL_NAMED(instance_vbo, DebugLabelFor::Buffer, fmt::format("ARRAY BUF (trans in) {}", debug_label)); | |
| 177 | ✗ | constexpr auto instance_size = sizeof(float) * 16; | |
| 178 | ✗ | glBufferData(GL_ARRAY_BUFFER, glsizeiptr_from_sizet(instance_size * max_instances), nullptr, GL_DYNAMIC_DRAW); | |
| 179 | |||
| 180 | ✗ | for (int matrix = 0; matrix < 4; matrix += 1) | |
| 181 | { | ||
| 182 | ✗ | const auto attribute = gluint_from_int(attrib_location + matrix); | |
| 183 | ✗ | glVertexAttribPointer( | |
| 184 | attribute, | ||
| 185 | 4, | ||
| 186 | GL_FLOAT, | ||
| 187 | GL_FALSE, | ||
| 188 | instance_size, | ||
| 189 | ✗ | reinterpret_cast<void*>(sizeof(v4) * static_cast<std::size_t>(matrix)) | |
| 190 | ); | ||
| 191 | ✗ | glEnableVertexAttribArray(attribute); | |
| 192 | ✗ | glVertexAttribDivisor(attribute, 1); | |
| 193 | } | ||
| 194 | |||
| 195 | ✗ | const auto ebo = create_buffer(); | |
| 196 | ✗ | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); | |
| 197 | ✗ | SET_DEBUG_LABEL_NAMED(ebo, DebugLabelFor::Buffer, fmt::format("IND BUF (in) {}", debug_label)); | |
| 198 | ✗ | glBufferData( | |
| 199 | GL_ELEMENT_ARRAY_BUFFER, | ||
| 200 | ✗ | glsizeiptr_from_sizet(sizeof(u32) * ex.indices.size()), | |
| 201 | ✗ | ex.indices.data(), | |
| 202 | GL_STATIC_DRAW | ||
| 203 | ); | ||
| 204 | |||
| 205 | return std::make_shared<CompiledGeom_TransformInstance>( | ||
| 206 | instance_vbo, max_instances, vbo, vao, ebo, geom_layout, ex.face_size | ||
| 207 | ✗ | ); | |
| 208 | ✗ | } | |
| 209 | |||
| 210 | ✗ | LocalAxis MeshInstance::get_local_axis() const | |
| 211 | { | ||
| 212 | // todo(Gustav): this this work with the matrix now including both rotation ADN translation? is it used anymore? | ||
| 213 | return { | ||
| 214 | ✗ | .x = transform.get_transformed_vec(v3{1, 0, 0}), | |
| 215 | ✗ | .y = transform.get_transformed_vec(v3{0, 1, 0}), | |
| 216 | ✗ | .z = transform.get_transformed_vec(v3{0, 0, 1}) | |
| 217 | ✗ | }; | |
| 218 | } | ||
| 219 | |||
| 220 | ✗ | void render_geom(const CompiledGeom& geom) | |
| 221 | { | ||
| 222 | ✗ | ASSERT(is_bound_for_shader(geom.debug_types)); | |
| 223 | ✗ | glBindVertexArray(geom.vao); | |
| 224 | ✗ | glDrawElements(GL_TRIANGLES, geom.number_of_triangles * 3, GL_UNSIGNED_INT, nullptr); | |
| 225 | ✗ | } | |
| 226 | |||
| 227 | ✗ | void render_geom_instanced(const MeshInstance_TransformInstanced& instanced) | |
| 228 | { | ||
| 229 | ✗ | auto* geom = instanced.geom.get(); | |
| 230 | ✗ | ASSERT(is_bound_for_shader(geom->debug_types)); | |
| 231 | ✗ | ASSERT(! instanced.world_from_locals.empty()); | |
| 232 | |||
| 233 | ✗ | for (std::size_t start_index = 0; start_index < instanced.world_from_locals.size(); | |
| 234 | ✗ | start_index += instanced.geom->max_instances) | |
| 235 | { | ||
| 236 | const std::size_t step_size | ||
| 237 | ✗ | = std::min(instanced.world_from_locals.size() - start_index, instanced.geom->max_instances); | |
| 238 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, instanced.geom->instance_vbo); | |
| 239 | ✗ | glBufferSubData( | |
| 240 | ✗ | GL_ARRAY_BUFFER, 0, glsizeiptr_from_sizet(sizeof(m4) * step_size), &instanced.world_from_locals[start_index] | |
| 241 | ); | ||
| 242 | |||
| 243 | ✗ | glBindVertexArray(geom->vao); | |
| 244 | ✗ | glDrawElementsInstanced( | |
| 245 | GL_TRIANGLES, | ||
| 246 | ✗ | geom->number_of_triangles * 3, | |
| 247 | GL_UNSIGNED_INT, | ||
| 248 | nullptr, | ||
| 249 | glsizei_from_sizet(instanced.world_from_locals.size()) | ||
| 250 | ); | ||
| 251 | } | ||
| 252 | ✗ | } | |
| 253 | |||
| 254 | ✗ | CompiledGeom_TransformInstance::~CompiledGeom_TransformInstance() | |
| 255 | { | ||
| 256 | ✗ | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); | |
| 257 | ✗ | destroy_buffer(ebo); | |
| 258 | |||
| 259 | ✗ | glBindBuffer(GL_ARRAY_BUFFER, 0); | |
| 260 | ✗ | destroy_buffer(vbo); | |
| 261 | ✗ | destroy_buffer(instance_vbo); | |
| 262 | |||
| 263 | ✗ | glBindVertexArray(0); | |
| 264 | ✗ | destroy_vertex_array(vao); | |
| 265 | ✗ | } | |
| 266 | |||
| 267 | ✗ | CameraVectors create_vectors(const DirectionalLight& p) | |
| 268 | { | ||
| 269 | ✗ | return create_vectors(p.rotation); | |
| 270 | } | ||
| 271 | |||
| 272 | } // namespace eu::render | ||
| 273 |