/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ #include "Geometry.hpp" #include "Vertex.hpp" #include "Base/Utils.hpp" #include "Base/Logger.hpp" #if __has_include("assimp/Importer.hpp") #include #include #include #include #define ASSIMP_AVAILABLE #endif #include #include "msdfgen.h" #include "msdfgen-ext.h" #include "msdf-atlas-gen/msdf-atlas-gen.h" namespace OpenVulkano::Scene { Geometry::Geometry(const Geometry& other) { this->vertexCount = other.vertexCount; this->indexCount = other.indexCount; this->indexType = other.indexType; this->aabb = other.aabb; this->ownsMemory = other.ownsMemory; this->freeAfterUpload = other.freeAfterUpload; this->renderGeo = nullptr; this->vertices = new Vertex[vertexCount]; if (other.vertices) { std::copy(other.vertices, other.vertices + other.vertexCount, this->vertices); } this->indices = malloc(static_cast(Utils::EnumAsInt(other.indexType)) * other.indexCount); if (other.indices) { if (other.indexType == VertexIndexType::UINT16) { std::copy(static_cast(other.indices), static_cast(other.indices) + other.indexCount, static_cast(this->indices)); } else { std::copy(static_cast(other.indices), static_cast(other.indices) + other.indexCount, static_cast(this->indices)); } } } Geometry& Geometry::operator=(const Geometry& other) { Geometry tmp(other); this->Swap(tmp); return *this; } Geometry::Geometry(Geometry&& other) noexcept { this->vertexCount = other.vertexCount; this->indexCount = other.indexCount; this->indexType = other.indexType; this->ownsMemory = other.ownsMemory; this->freeAfterUpload = other.freeAfterUpload; this->aabb = std::move(other.aabb); this->vertices = other.vertices; this->indices = other.indices; this->renderGeo = other.renderGeo; other.vertexCount = other.indexCount = 0; other.vertices = nullptr; other.indices = nullptr; other.renderGeo = nullptr; } Geometry& Geometry::operator=(Geometry&& other) noexcept { if (this != &other) { Close(); this->vertexCount = other.vertexCount; this->indexCount = other.indexCount; this->indexType = other.indexType; this->ownsMemory = other.ownsMemory; this->freeAfterUpload = other.freeAfterUpload; this->aabb = std::move(other.aabb); this->vertices = other.vertices; this->indices = other.indices; this->renderGeo = other.renderGeo; other.vertexCount = other.indexCount = 0; other.vertices = nullptr; other.indices = nullptr; other.renderGeo = nullptr; } return *this; } Geometry::~Geometry() { Geometry::Close(); } void Geometry::Swap(Geometry& other) noexcept { std::swap(this->vertexCount, other.vertexCount); std::swap(this->indexCount, other.indexCount); std::swap(this->aabb, other.aabb); std::swap(this->indexType, other.indexType); std::swap(this->vertices, other.vertices); std::swap(this->indices, other.indices); std::swap(this->renderGeo, other.renderGeo); std::swap(this->ownsMemory, other.ownsMemory); std::swap(this->freeAfterUpload, other.freeAfterUpload); } void Geometry::Init(uint32_t vertexCount, uint32_t indexCount) { if (this->vertexCount || this->indexCount) throw std::runtime_error("Geometry is already initialized."); this->vertexCount = vertexCount; this->indexCount = indexCount; indexType = (vertexCount > UINT16_MAX) ? VertexIndexType::UINT32 : VertexIndexType::UINT16; vertices = new Vertex[vertexCount]; indices = malloc(static_cast(Utils::EnumAsInt(indexType)) * indexCount); renderGeo = nullptr; } void Geometry::InitFromFile(const std::string& file) { #ifdef ASSIMP_AVAILABLE Assimp::Importer importer; const uint32_t flags = aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_GenNormals | aiProcess_ImproveCacheLocality | aiProcess_RemoveRedundantMaterials | aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_ConvertToLeftHanded | aiProcess_PreTransformVertices | aiProcess_OptimizeGraph; const aiScene* scene = importer.ReadFile(file, flags); if (!scene) throw std::runtime_error("Failed to load file \"" + file + "\" Error: " + importer.GetErrorString()); if (!scene->HasMeshes()) throw std::runtime_error("File \"" + file + "\" does not have any meshes"); if (scene->mNumMeshes > 1) Logger::DATA->warn("File {0} contains more than one mesh. Only first one will be loaded", file); Init(scene->mMeshes[0]); importer.FreeScene(); #else throw std::runtime_error("ASSIMP not available!"); #endif } void Geometry::Init(aiMesh* mesh) { #ifdef ASSIMP_AVAILABLE aabb.Reset(); Init(mesh->mNumVertices, mesh->mNumFaces * 3); // Reserve the space for the data for (unsigned int i = 0; i < mesh->mNumVertices; i++) { vertices[i].Set(mesh->mVertices[i]); if (mesh->HasNormals()) vertices[i].SetNormal(mesh->mNormals[i]); if (mesh->HasTangentsAndBitangents()) { vertices[i].SetTangentAndBiTangent(mesh->mTangents[i], mesh->mBitangents[i]); } if (mesh->HasTextureCoords(0)) vertices[i].SetTextureCoordinates(mesh->mTextureCoords[0][i]); if (mesh->HasVertexColors(0)) vertices[i].SetColor(mesh->mColors[0][i]); aabb.Grow(vertices[i].position); } for (unsigned int i = 0; i < mesh->mNumFaces; i++) { const aiFace face = mesh->mFaces[i]; if (face.mNumIndices != 3) throw std::runtime_error("Mesh is not a triangle mesh!"); for (unsigned int j = 0; j < face.mNumIndices; j++) { if (indexType == VertexIndexType::UINT16) { static_cast(indices)[i * face.mNumIndices + j] = static_cast(face.mIndices[j]); } else { static_cast(indices)[i * face.mNumIndices + j] = face.mIndices[j]; } } } //TODO load bones //TODO load materials #else throw std::runtime_error("ASSIMP not available!"); #endif } void Geometry::SetIndices(const uint32_t* data, uint32_t size, uint32_t indicesOffset) const { for(uint32_t i = 0; i < size; i++) { if (indexType == VertexIndexType::UINT16) { static_cast(indices)[i + indicesOffset] = static_cast(data[i]); } else { static_cast(indices)[i + indicesOffset] = data[i]; } } } void Geometry::Close() { if (ownsMemory) { vertexCount = 0; indexCount = 0; Free(); } if (renderGeo) { renderGeo->Close(); renderGeo = nullptr; } } void Geometry::Free() { delete[] vertices; free(indices); vertices = nullptr; indices = nullptr; } }