Working prototype for entt based rendering

This commit is contained in:
2022-10-19 23:10:34 +02:00
parent 5b017d4725
commit 2cb49c1b9c
8 changed files with 264 additions and 150 deletions

View File

@@ -69,6 +69,7 @@ void main()
fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPosition, viewDir); fragmentColor += pointLightContribution(u_pointLight[i], normal, v_fragmentPosition, viewDir);
} }
fragmentColor = vec3(1.,1.,1.);
f_color = vec4(fragmentColor, 1.0f); f_color = vec4(fragmentColor, 1.0f);
} }

View File

@@ -31,123 +31,124 @@ Controller::Controller()
m_gameWindow->dimensions().second, m_gameWindow->dimensions().second,
postProcessingProgram) postProcessingProgram)
{ {
fx::gltf::ReadQuotas read_quotas{.MaxFileSize = 512 * 1024 * 1024, // fx::gltf::ReadQuotas read_quotas{.MaxFileSize = 512 * 1024 * 1024,
.MaxBufferByteLength = 512 * 1024 * 1024}; // .MaxBufferByteLength = 512 * 1024 * 1024};
// auto gltf_path = std::filesystem::path("Lantern/glTF/Lantern.gltf"); // // auto gltf_path = std::filesystem::path("Lantern/glTF/Lantern.gltf");
// auto gltf_path = std::filesystem::path("WaterBottle/glTF/WaterBottle.gltf"); // // auto gltf_path = std::filesystem::path("WaterBottle/glTF/WaterBottle.gltf");
auto gltf_path = std::filesystem::path("ABeautifulGame.glb"); // auto gltf_path = std::filesystem::path("ABeautifulGame.glb");
auto gltf = [&]() { // auto gltf = [&]() {
if (gltf_path.extension() == ".gltf") { // if (gltf_path.extension() == ".gltf") {
return fx::gltf::LoadFromText(gltf_path, read_quotas); // return fx::gltf::LoadFromText(gltf_path, read_quotas);
} // }
return fx::gltf::LoadFromBinary(gltf_path, read_quotas); // return fx::gltf::LoadFromBinary(gltf_path, read_quotas);
}(); // }();
defaultProgram.bind(); // defaultProgram.bind();
AttributeLocations locations{}; // AttributeLocations locations{};
locations.position = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_position"); // locations.position = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_position");
locations.normal = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_normal"); // locations.normal = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_normal");
locations.uv = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_texCoord"); // locations.uv = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_texCoord");
locations.tangent = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_tangent"); // locations.tangent = glGetAttribLocation(defaultProgram.getShaderProgramId(), "a_tangent");
ShaderProgram::unbind(); // ShaderProgram::unbind();
if (!gltf.cameras.empty()) { // if (!gltf.cameras.empty()) {
auto const &gltf_camera = gltf.cameras.at(0); // auto const &gltf_camera = gltf.cameras.at(0);
assert(gltf_camera.type == fx::gltf::Camera::Type::Perspective); // assert(gltf_camera.type == fx::gltf::Camera::Type::Perspective);
auto const &perspective = gltf_camera.perspective; // auto const &perspective = gltf_camera.perspective;
m_camera = std::make_shared<Camera>(perspective.yfov, perspective.aspectRatio); // m_camera = std::make_shared<Camera>(perspective.yfov, perspective.aspectRatio);
} else { // } else {
m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio()); m_camera = std::make_shared<Camera>(90., m_gameWindow->aspectRatio());
} // }
std::vector<Model> models; // std::vector<Model> models;
for (auto const &mesh : gltf.meshes) { // for (auto const &mesh : gltf.meshes) {
std::vector<Mesh_> meshes; // std::vector<Mesh_> meshes;
for (auto const &primitive : mesh.primitives) { // for (auto const &primitive : mesh.primitives) {
auto const &material = gltf.materials.at(primitive.material); // auto const &material = gltf.materials.at(primitive.material);
auto baseColorTexture = material.pbrMetallicRoughness.baseColorTexture.index; // auto baseColorTexture = material.pbrMetallicRoughness.baseColorTexture.index;
auto normalTexture = material.normalTexture.index; // auto normalTexture = material.normalTexture.index;
std::vector<std::reference_wrapper<const Texture>> primitive_textures; // std::vector<std::reference_wrapper<const Texture>> primitive_textures;
// Check if texture already exists, if not load it. // // Check if texture already exists, if not load it.
if (baseColorTexture != -1 && !m_textures.contains(baseColorTexture)) { // if (baseColorTexture != -1 && !m_textures.contains(baseColorTexture)) {
auto const &gltf_texture = gltf.textures.at(baseColorTexture); // auto const &gltf_texture = gltf.textures.at(baseColorTexture);
m_textures.emplace(baseColorTexture, // m_textures.emplace(baseColorTexture,
Texture(gltf_texture, // Texture(gltf_texture,
gltf_path.parent_path(), // gltf_path.parent_path(),
gltf.images, // gltf.images,
gltf.bufferViews, // gltf.bufferViews,
gltf.buffers, // gltf.buffers,
gltf.samplers, // gltf.samplers,
TextureType::Diffuse)); // TextureType::Diffuse));
primitive_textures.emplace_back(m_textures.at(baseColorTexture)); // primitive_textures.emplace_back(m_textures.at(baseColorTexture));
} // }
if (normalTexture != -1 && !m_textures.contains(normalTexture)) { // if (normalTexture != -1 && !m_textures.contains(normalTexture)) {
auto const &gltf_texture = gltf.textures.at(normalTexture); // auto const &gltf_texture = gltf.textures.at(normalTexture);
m_textures.emplace(normalTexture, // m_textures.emplace(normalTexture,
Texture(gltf_texture, // Texture(gltf_texture,
gltf_path.parent_path(), // gltf_path.parent_path(),
gltf.images, // gltf.images,
gltf.bufferViews, // gltf.bufferViews,
gltf.buffers, // gltf.buffers,
gltf.samplers, // gltf.samplers,
TextureType::Normal)); // TextureType::Normal));
primitive_textures.emplace_back(m_textures.at(normalTexture)); // primitive_textures.emplace_back(m_textures.at(normalTexture));
} // }
meshes.emplace_back(Mesh_({primitive, gltf, locations}, primitive_textures)); // meshes.emplace_back(Mesh_({primitive, gltf, locations}, primitive_textures));
} // }
models.emplace_back(Model(mesh.name, std::move(meshes))); // models.emplace_back(Model(mesh.name, std::move(meshes)));
} // }
m_models = std::move(models); // m_models = std::move(models);
std::vector<ModelEntity> entities; // std::vector<ModelEntity> entities;
for (auto const &node : gltf.nodes) { // for (auto const &node : gltf.nodes) {
if (node.mesh == -1) { // if (node.mesh == -1) {
continue; // continue;
} // }
ModelEntity entity(Entity::Prototype(node.name, {}, {}, 1.0F), // ModelEntity entity(Entity::Prototype(node.name, {}, {}, 1.0F),
m_models[static_cast<unsigned>(node.mesh)], // m_models[static_cast<unsigned>(node.mesh)],
defaultProgram); // defaultProgram);
if (!node.translation.empty()) { // if (!node.translation.empty()) {
entity.setPosition( // entity.setPosition(
glm::vec3(node.translation[0], node.translation[1], node.translation[2])); // glm::vec3(node.translation[0], node.translation[1], node.translation[2]));
} // }
if (!node.rotation.empty()) { // if (!node.rotation.empty()) {
entity.setRotation(glm::eulerAngles( // entity.setRotation(glm::eulerAngles(
glm::quat(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]))); // glm::quat(node.rotation[3], node.rotation[0], node.rotation[1],
} // node.rotation[2])));
// }
if (!node.scale.empty()) { // if (!node.scale.empty()) {
entity.setScale(node.scale[0]); // entity.setScale(node.scale[0]);
} // }
entities.push_back(std::move(entity)); // entities.push_back(std::move(entity));
} // }
for (auto const &node : gltf.nodes) { // for (auto const &node : gltf.nodes) {
for (auto const &child : node.children) { // for (auto const &child : node.children) {
if (!node.translation.empty()) { // if (!node.translation.empty()) {
entities[child].translate( // entities[child].translate(
glm::vec3(node.translation[0], node.translation[1], node.translation[2])); // glm::vec3(node.translation[0], node.translation[1], node.translation[2]));
} // }
} // }
} // }
m_entities = std::move(entities); // m_entities = std::move(entities);
} }
void Controller::run() void Controller::run()
@@ -183,12 +184,19 @@ void Controller::run()
m_camera->lookForward(); m_camera->lookForward();
m_camera->updateVPM(); m_camera->updateVPM();
static constexpr auto MICROSECONDS_PER_SECOND = 1'000'000;
m_scene.update(
std::chrono::microseconds(static_cast<unsigned>(m_deltaTime * MICROSECONDS_PER_SECOND)),
&defaultProgram,
m_camera->getViewProj(),
m_camera->getPosition());
// Draw scene // Draw scene
defaultProgram.bind(); // defaultProgram.bind();
for (auto const &entity : m_entities) { // for (auto const &entity : m_entities) {
entity.draw(m_camera->getViewProj(), m_camera->getPosition()); // entity.draw(m_camera->getViewProj(), m_camera->getPosition());
} // }
ShaderProgram::unbind(); // ShaderProgram::unbind();
m_postProcessFrameBuffer.unbind(); m_postProcessFrameBuffer.unbind();
m_postProcessFrameBuffer.drawOnEntireScreen(); m_postProcessFrameBuffer.drawOnEntireScreen();

View File

@@ -109,7 +109,7 @@ void Helper::gl_debug_callback(GLenum source,
} }
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM)
Log::logger().debug("\n[OpenGL Debug Message]\n" Log::logger().debug("[OpenGL Debug Message]\n"
"Message: {}\n" "Message: {}\n"
"Source: {}\n" "Source: {}\n"
"Type: {}\n" "Type: {}\n"

View File

@@ -1,4 +1,6 @@
#include "Scene.h" #include "Scene.h"
#include "ShaderProgram.h"
#include "mesh.h"
#include "name.h" #include "name.h"
#include "transform.h" #include "transform.h"
#include "util/Log.h" #include "util/Log.h"
@@ -48,13 +50,50 @@ Scene::Scene()
Log::logger().info("Hello entity {}!", name); Log::logger().info("Hello entity {}!", name);
} }
auto mesh_view = m_registry.view<Mesh>(); auto mesh_view = m_registry.view<entt::resource<Mesh>>();
for (auto [entity, mesh] : mesh_view.each()) { for (auto [entity, mesh] : mesh_view.each()) {
Log::logger().info("Convert mesh {}!"); m_registry.emplace<GpuMesh>(entity, GpuMesh{mesh});
// Remove Mesh resource as it is no longer needed.
m_registry.erase<entt::resource<Mesh>>(entity);
} }
} }
void Scene::update(std::chrono::duration<float> delta) void Scene::update(std::chrono::duration<float> delta,
ShaderProgram *shaderprogram,
glm::mat4 viewProjMatrix,
glm::vec3 viewPosition)
{ {
auto mesh_view = m_registry.view<GpuMesh, Transform>();
for (auto [entity, mesh, transform] : mesh_view.each()) {
shaderprogram->bind();
// Bind modelview matrix uniform
{
// Translate * Rotate * Scale * vertex_vec;
// First scaling, then rotation, then translation
// Translate
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), transform.translation);
// Rotate
glm::mat4 rotationMatrix = glm::toMat4(transform.rotation);
// Scale
glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f), transform.scale);
glm::mat4 modelMatrix = translationMatrix * rotationMatrix * scaleMatrix;
glm::mat4 modelViewProj = viewProjMatrix * modelMatrix;
shaderprogram->setUniform("u_modelViewProjMatrix", modelViewProj);
// shaderprogram->setUniform("u_modelMatrix", modelMatrix);
// shaderprogram->setUniform("u_viewPosition", viewPosition);
}
glBindVertexArray(mesh.vao);
glDrawElements(GL_TRIANGLES, mesh.indices_count, mesh.indices_type, nullptr);
glBindVertexArray(0);
ShaderProgram::unbind();
}
} }

View File

@@ -1,18 +1,23 @@
#pragma once #pragma once
#include "mesh.h"
#include "material.h"
#include "gltf_loader.h" #include "gltf_loader.h"
#include "material.h"
#include "mesh.h"
#include <entt/entt.hpp>
#include <chrono> #include <chrono>
#include <entt/entt.hpp>
class ShaderProgram;
class Scene class Scene
{ {
public: public:
Scene(); Scene();
void update(std::chrono::duration<float> delta); void update(std::chrono::duration<float> delta,
ShaderProgram *shaderprogram,
glm::mat4 viewProjMatrix,
glm::vec3 viewPosition);
private: private:
entt::registry m_registry; entt::registry m_registry;

View File

@@ -8,7 +8,7 @@ static auto create_vertex_attribute_data(std::span<uint8_t const> vertex_attribu
-> VertexAttributeData -> VertexAttributeData
{ {
T attribute_data; T attribute_data;
attribute_data.reserve(vertex_attribute_data.size_bytes()); attribute_data.resize(vertex_attribute_data.size_bytes());
std::memcpy( std::memcpy(
attribute_data.data(), vertex_attribute_data.data(), vertex_attribute_data.size_bytes()); attribute_data.data(), vertex_attribute_data.data(), vertex_attribute_data.size_bytes());
@@ -20,7 +20,7 @@ template <typename T>
static auto create_indices(std::span<uint8_t const> gltf_index_data) -> Indices static auto create_indices(std::span<uint8_t const> gltf_index_data) -> Indices
{ {
T index_data; T index_data;
index_data.reserve(gltf_index_data.size_bytes()); index_data.resize(gltf_index_data.size_bytes());
std::memcpy(index_data.data(), gltf_index_data.data(), gltf_index_data.size_bytes()); std::memcpy(index_data.data(), gltf_index_data.data(), gltf_index_data.size_bytes());
@@ -105,7 +105,7 @@ static auto load_material(fx::gltf::Material const &material,
static auto load_attribute(std::string_view attribute_name, static auto load_attribute(std::string_view attribute_name,
uint32_t attribute_id, uint32_t attribute_id,
fx::gltf::Document const &gltf) -> std::optional<VertexAttributeData> fx::gltf::Document const &gltf) -> std::optional<std::pair<std::size_t,VertexAttributeData>>
{ {
auto const &attribute_accessor = gltf.accessors.at(attribute_id); auto const &attribute_accessor = gltf.accessors.at(attribute_id);
@@ -165,13 +165,12 @@ static auto load_attribute(std::string_view attribute_name,
std::terminate(); std::terminate();
}(); }();
return std::move(vertex_attribute_data); return std::make_pair(vertex_attribute_id.value(), std::move(vertex_attribute_data));
} }
auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive, auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive,
fx::gltf::Document const &gltf, fx::gltf::Document const &gltf,
std::filesystem::path const &document_path, std::string_view primitive_identifier,
unsigned primitive_id,
entt::resource_cache<Material> &material_cache, entt::resource_cache<Material> &material_cache,
entt::resource_cache<Mesh> &mesh_cache) -> GltfPrimitive entt::resource_cache<Mesh> &mesh_cache) -> GltfPrimitive
{ {
@@ -188,13 +187,13 @@ auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive,
std::map<Mesh::VertexAttributeId, VertexAttributeData> attributes; std::map<Mesh::VertexAttributeId, VertexAttributeData> attributes;
for (auto const &attribute : gltf_primitive.attributes) { for (auto const &attribute : gltf_primitive.attributes) {
auto vertex_attribute_data = load_attribute(attribute.first, attribute.second, gltf); auto vertex_attribute = load_attribute(attribute.first, attribute.second, gltf);
if (!vertex_attribute_data.has_value()) { if (!vertex_attribute.has_value()) {
continue; continue;
} }
attributes.emplace(attribute.second, std::move(vertex_attribute_data.value())); attributes.emplace(vertex_attribute.value().first, std::move(vertex_attribute.value().second));
} }
// Load indices // Load indices
@@ -206,11 +205,10 @@ auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive,
std::span<uint8_t const> indices_data_span = std::span<uint8_t const> indices_data_span =
indices_buffer_span.subspan(indices_buffer_view.byteOffset, indices_buffer_view.byteLength); indices_buffer_span.subspan(indices_buffer_view.byteOffset, indices_buffer_view.byteLength);
auto indices = [indices_data_span, &indices_accessor]() { Indices indices = [indices_data_span, &indices_accessor]() {
if (indices_accessor.componentType == fx::gltf::Accessor::ComponentType::UnsignedByte) { if (indices_accessor.componentType == fx::gltf::Accessor::ComponentType::UnsignedByte) {
return create_indices<Indices::UnsignedByte>(indices_data_span); return create_indices<Indices::UnsignedByte>(indices_data_span);
} }
if (indices_accessor.componentType == fx::gltf::Accessor::ComponentType::UnsignedShort) { if (indices_accessor.componentType == fx::gltf::Accessor::ComponentType::UnsignedShort) {
return create_indices<Indices::UnsignedShort>(indices_data_span); return create_indices<Indices::UnsignedShort>(indices_data_span);
} }
@@ -222,12 +220,10 @@ auto load_gltf_primitive(fx::gltf::Primitive const &gltf_primitive,
std::terminate(); std::terminate();
}(); }();
std::string const mesh_name = entt::hashed_string const mesh_hash(primitive_identifier.data());
document_path.string() + ".primitive." + std::to_string(primitive_id);
entt::hashed_string const mesh_hash(mesh_name.c_str());
entt::resource<Mesh> mesh = entt::resource<Mesh> mesh =
mesh_cache.load(mesh_hash, Mesh{.attributes = attributes, .indices = indices}) mesh_cache.load(mesh_hash, Mesh{.attributes = attributes, .indices = std::move(indices)})
.first->second; .first->second;
// Get material by hash // Get material by hash
@@ -274,8 +270,13 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
primitives.reserve(gltf_mesh.primitives.size()); primitives.reserve(gltf_mesh.primitives.size());
for (auto const &gltf_primitive : gltf_mesh.primitives) { for (auto const &gltf_primitive : gltf_mesh.primitives) {
std::string const primitive_identifier = document_path.string() + "." + gltf_mesh.name +
"." + ".primitive." +
std::to_string(primitive_count);
primitives.push_back(load_gltf_primitive( primitives.push_back(load_gltf_primitive(
gltf_primitive, gltf, document_path, primitive_count, material_cache, mesh_cache)); gltf_primitive, gltf, primitive_identifier, material_cache, mesh_cache));
++primitive_count;
} }
if (gltf_mesh.name.empty()) { if (gltf_mesh.name.empty()) {
@@ -296,13 +297,10 @@ auto GltfLoader::operator()(std::filesystem::path const &document_path) -> resul
for (std::size_t i = 0; i < gltf.nodes.size(); ++i) { for (std::size_t i = 0; i < gltf.nodes.size(); ++i) {
auto const &node = gltf.nodes.at(i); auto const &node = gltf.nodes.at(i);
auto mesh = [this, &node, &gltf]() -> std::optional<entt::resource<GltfMesh>> { auto mesh = [this, &node, &gltf_meshes]() -> std::optional<entt::resource<GltfMesh>> {
if (node.mesh != -1) { if (node.mesh != -1) {
// Get mesh by hash auto const &gltf_mesh = gltf_meshes.at(node.mesh);
auto const &gltf_mesh = gltf.meshes.at(node.mesh); return {gltf_mesh};
entt::hashed_string mesh_hash(gltf_mesh.name.c_str());
entt::resource<GltfMesh> mesh = gltf_mesh_cache[mesh_hash];
return {mesh};
} }
return {}; return {};

View File

@@ -1,30 +1,81 @@
#include "mesh.h" #include "mesh.h"
#include "util/Log.h"
#include <exception>
GpuMesh::GpuMesh(Mesh const &mesh) GpuMesh::GpuMesh(Mesh const &mesh)
{ {
glGenVertexArrays(1, &vao); glGenVertexArrays(1, &vao);
glBindVertexArray(vao); glBindVertexArray(vao);
// Vertex attributes
for (auto const &[attribute_id, attribute_data] : mesh.attributes) { for (auto const &[attribute_id, attribute_data] : mesh.attributes) {
// BUG: https://github.com/llvm/llvm-project/issues/48582 // BUG: https://github.com/llvm/llvm-project/issues/48582
auto attr_id = attribute_id; auto attr_id = attribute_id;
std::visit([=](auto&& arg) {
GLuint vbo{}; GLuint vbo{};
glGenBuffers(1, &vbo); glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo);
std::visit(
[attr_id](auto &&arg) {
glBufferData(GL_ARRAY_BUFFER, arg.size(), arg.data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, arg.size(), arg.data(), GL_STATIC_DRAW);
int const components = [arg]() -> int {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, VertexAttributeData::Scalar>) {
return 1;
}
if constexpr (std::is_same_v<T, VertexAttributeData::Vec2>) {
return 2;
}
if constexpr (std::is_same_v<T, VertexAttributeData::Vec3>) {
return 3;
}
if constexpr (std::is_same_v<T, VertexAttributeData::Vec4>) {
return 4;
}
std::terminate();
}();
glEnableVertexAttribArray(attr_id); glEnableVertexAttribArray(attr_id);
glVertexAttribPointer( glVertexAttribPointer(
attr_id, attr_id,
accessor_byte_size(position_accessor.type), components,
static_cast<GLenum>(position_accessor.componentType), GL_FLOAT, // static_cast<GLenum>(position_accessor.componentType),
position_accessor.normalized ? GL_TRUE : GL_FALSE, false, // position_accessor.normalized ? GL_TRUE : GL_FALSE,
position_buffer_view.byteStride, 0,
reinterpret_cast<void *>( nullptr);
position_accessor },
.byteOffset)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast, attribute_data.values);
// performance-no-int-to-ptr)
} }
// Indices
GLuint ebo{};
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
std::visit(
[this](auto &&arg) {
glBufferData(GL_ELEMENT_ARRAY_BUFFER, arg.size(), arg.data(), GL_STATIC_DRAW);
indices_count = arg.size();
indices_type = [arg]() -> GLenum {
using T = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<T, Indices::UnsignedByte>) {
return GL_UNSIGNED_BYTE;
} }
if constexpr (std::is_same_v<T, Indices::UnsignedShort>) {
return GL_UNSIGNED_SHORT;
}
if constexpr (std::is_same_v<T, Indices::UnsignedInt>) {
return GL_UNSIGNED_INT;
}
std::terminate();
}();
},
mesh.indices.values);
glBindVertexArray(0);
}

View File

@@ -1,11 +1,11 @@
#pragma once #pragma once
#include <array>
#include <cstdint> #include <cstdint>
#include <glad/gl.h> #include <glad/gl.h>
#include <map> #include <map>
#include <variant> #include <variant>
#include <vector> #include <vector>
#include <array>
struct VertexAttributeData struct VertexAttributeData
{ {
@@ -45,11 +45,20 @@ struct GpuMesh
GpuMesh(GpuMesh const &) = delete; GpuMesh(GpuMesh const &) = delete;
auto operator=(GpuMesh const &) -> GpuMesh & = delete; auto operator=(GpuMesh const &) -> GpuMesh & = delete;
GpuMesh(GpuMesh &&other) noexcept : vao(other.vao) { other.vao = 0; } GpuMesh(GpuMesh &&other) noexcept
: vao(other.vao), indices_count(other.indices_count), indices_type(other.indices_type)
{
other.vao = 0;
}
auto operator=(GpuMesh &&other) noexcept -> GpuMesh & auto operator=(GpuMesh &&other) noexcept -> GpuMesh &
{ {
vao = other.vao; vao = other.vao;
indices_count = other.indices_count;
indices_type = other.indices_type;
// Deinitialize other
other.vao = 0; other.vao = 0;
return *this; return *this;
}; };
@@ -57,4 +66,7 @@ struct GpuMesh
// TODO: also store vertex buffers. // TODO: also store vertex buffers.
GLuint vao{}; GLuint vao{};
GLsizei indices_count{};
GLenum indices_type{};
}; };