Asset+Component: Add model component and asset
This commit is contained in:
@@ -31,6 +31,7 @@ public:
|
|||||||
bool fastIs() const = delete;
|
bool fastIs() const = delete;
|
||||||
|
|
||||||
virtual bool isFont() const { return false; }
|
virtual bool isFont() const { return false; }
|
||||||
|
virtual bool isModel() const { return false; }
|
||||||
virtual bool isShader() const { return false; }
|
virtual bool isShader() const { return false; }
|
||||||
virtual bool isTexture() const { return false; }
|
virtual bool isTexture() const { return false; }
|
||||||
virtual bool isTexture2D() const { return false; }
|
virtual bool isTexture2D() const { return false; }
|
||||||
|
|||||||
@@ -0,0 +1,110 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdint> // uint32_t
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
|
|
||||||
|
#include "assimp/Importer.hpp"
|
||||||
|
#include "assimp/postprocess.h"
|
||||||
|
#include "assimp/scene.h"
|
||||||
|
#include "assimp/texture.h"
|
||||||
|
#include "ruc/format/log.h"
|
||||||
|
|
||||||
|
#include "inferno/asset/model.h"
|
||||||
|
#include "inferno/asset/texture.h"
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
std::shared_ptr<Model> Model::create(std::string_view path)
|
||||||
|
{
|
||||||
|
auto result = std::shared_ptr<Model>(new Model(path));
|
||||||
|
|
||||||
|
Assimp::Importer importer; // importer destructor uses RAII cleanup
|
||||||
|
const aiScene* scene = importer.ReadFile(
|
||||||
|
path.data(),
|
||||||
|
aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_JoinIdenticalVertices | aiProcess_SortByPType);
|
||||||
|
|
||||||
|
VERIFY(scene != nullptr && (scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) == 0 && scene->mRootNode != nullptr,
|
||||||
|
"assimp loading file failed: {}", importer.GetErrorString());
|
||||||
|
|
||||||
|
processScene(result, scene);
|
||||||
|
processNode(result, scene->mRootNode, scene);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::processScene(std::shared_ptr<Model> model, const aiScene* scene)
|
||||||
|
{
|
||||||
|
VERIFY(scene->HasMeshes(), "malformed model");
|
||||||
|
VERIFY(scene->mNumTextures < 2, "unsupported model type");
|
||||||
|
|
||||||
|
if (scene->mNumTextures == 1) {
|
||||||
|
aiTexture* texture = scene->mTextures[0];
|
||||||
|
model->m_texture = Texture2D::create(texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::processNode(std::shared_ptr<Model> model, aiNode* node, const aiScene* scene)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < node->mNumMeshes; ++i) {
|
||||||
|
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
|
||||||
|
processMesh(model, mesh, scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < node->mNumChildren; ++i) {
|
||||||
|
processNode(model, node->mChildren[i], scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::processMesh(std::shared_ptr<Model> model, aiMesh* mesh, const aiScene* scene)
|
||||||
|
{
|
||||||
|
VERIFY(mesh->HasPositions(), "malformed model");
|
||||||
|
VERIFY(mesh->HasNormals(), "malformed model");
|
||||||
|
|
||||||
|
// Pre-allocate memory
|
||||||
|
model->m_vertices = std::vector<Vertex>(mesh->mNumVertices);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
aiVector3D v = mesh->mVertices[i];
|
||||||
|
model->m_vertices[i].position = { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size of vertices == size of normals
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
aiVector3D normal = mesh->mNormals[i];
|
||||||
|
model->m_vertices[i].normal = { normal.x, normal.y, normal.x };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh->HasTextureCoords(0)) {
|
||||||
|
// Size of vertices == size of texture coordinates
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumVertices; ++i) {
|
||||||
|
aiVector3D tc = mesh->mTextureCoords[0][i];
|
||||||
|
model->m_vertices[i].textureCoordinates = { tc.x, tc.y };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: position in the texture atlas
|
||||||
|
|
||||||
|
if (mesh->HasFaces()) {
|
||||||
|
for (uint32_t i = 0; i < mesh->mNumFaces; ++i) {
|
||||||
|
aiFace face = mesh->mFaces[i];
|
||||||
|
for (uint32_t j = 0; j < face.mNumIndices; ++j) {
|
||||||
|
model->m_elements.push_back(face.mIndices[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ruc::debug("mesh: {:p}", mesh->mTextureCoordsNames);
|
||||||
|
// for (size_t i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) {
|
||||||
|
// ruc::debug("mesh: {}", mesh->mTextureCoordsNames[i]);
|
||||||
|
// }
|
||||||
|
|
||||||
|
ruc::debug("has texture: {}", scene->HasTextures());
|
||||||
|
|
||||||
|
ruc::error("asset::model vert {}", model->m_vertices.size());
|
||||||
|
ruc::error("asset::model elem {}", model->m_elements.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint> // uint32_t
|
||||||
|
#include <memory>
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "assimp/scene.h"
|
||||||
|
|
||||||
|
#include "inferno/asset/asset-manager.h"
|
||||||
|
#include "inferno/render/renderer.h"
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
class Texture2D;
|
||||||
|
|
||||||
|
class Model final : public Asset {
|
||||||
|
public:
|
||||||
|
virtual ~Model() {}
|
||||||
|
|
||||||
|
// Factory function
|
||||||
|
static std::shared_ptr<Model> create(std::string_view path);
|
||||||
|
|
||||||
|
std::span<const Vertex> vertices() const { return m_vertices; }
|
||||||
|
std::span<const uint32_t> elements() const { return m_elements; }
|
||||||
|
std::shared_ptr<Texture2D> texture() const { return m_texture; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Model(std::string_view path)
|
||||||
|
: Asset(path)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void processScene(std::shared_ptr<Model> model, const aiScene* scene);
|
||||||
|
static void processNode(std::shared_ptr<Model> model, aiNode* node, const aiScene* scene);
|
||||||
|
static void processMesh(std::shared_ptr<Model> model, aiMesh* mesh, const aiScene* scene);
|
||||||
|
|
||||||
|
virtual bool isModel() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Vertex> m_vertices;
|
||||||
|
std::vector<uint32_t> m_elements;
|
||||||
|
// Some file formats embed their texture
|
||||||
|
std::shared_ptr<Texture2D> m_texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "inferno/component/model-component.h"
|
||||||
|
#include "inferno/asset/asset-manager.h"
|
||||||
|
#include "inferno/asset/model.h"
|
||||||
|
#include "inferno/asset/texture.h"
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
void fromJson(const ruc::Json& json, ModelComponent& value)
|
||||||
|
{
|
||||||
|
VERIFY(json.type() == ruc::Json::Type::Object);
|
||||||
|
|
||||||
|
if (json.exists("model") && json.at("model").type() == ruc::Json::Type::String) {
|
||||||
|
value.model = AssetManager::the().load<Model>(json.at("model").asString());
|
||||||
|
}
|
||||||
|
if (json.exists("texture") && json.at("texture").type() == ruc::Json::Type::String) {
|
||||||
|
value.texture = AssetManager::the().load<Texture2D>(json.at("texture").asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory> // std::shared_ptr
|
||||||
|
|
||||||
|
#include "ruc/json/json.h"
|
||||||
|
|
||||||
|
#include "inferno/asset/model.h"
|
||||||
|
#include "inferno/asset/texture.h"
|
||||||
|
|
||||||
|
namespace Inferno {
|
||||||
|
|
||||||
|
struct ModelComponent {
|
||||||
|
std::shared_ptr<Model> model;
|
||||||
|
std::shared_ptr<Texture2D> texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
void fromJson(const ruc::Json& json, ModelComponent& value);
|
||||||
|
|
||||||
|
} // namespace Inferno
|
||||||
Reference in New Issue
Block a user