2026-07-17 15:30:29 +01:00
|
|
|
#include "HydraGLTFLoader.h"
|
|
|
|
|
#include "../actor/HydraActorManager.h"
|
|
|
|
|
#include "../actor/HydraActorManager.h"
|
|
|
|
|
#include "../actor/HydraGLTFActor.h"
|
|
|
|
|
#include "../engine/HydraEngine.h"
|
|
|
|
|
#include "../ecs/HydraECS.h"
|
|
|
|
|
#include "../ecs/components/HydraPositionComponent.h"
|
|
|
|
|
#include "../ecs/components/HydraMeshComponent.h"
|
|
|
|
|
#include "../ecs/components/HydraRenderableComponent.h"
|
|
|
|
|
#include "../ecs/components/HydraMaterialComponent.h"
|
|
|
|
|
|
|
|
|
|
#include "../mesh/HydraMesh.h"
|
|
|
|
|
#include "../mesh/HydraMeshManager.h"
|
|
|
|
|
#include "../mesh/StandardVertex.h"
|
|
|
|
|
#include "../buffer/HydraTextureBufferManager.h"
|
|
|
|
|
#include "../buffer/HydraMaterialBufferManager.h"
|
|
|
|
|
#include "../buffer/HydraMaterialBuffer.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
HydraID HydraGLTFLoader::LoadGLTFFile(std::string filename)
|
|
|
|
|
{
|
|
|
|
|
HydraID actor_id = INVALID_HYDRA_ID;
|
|
|
|
|
HydraActorManager *actor_manager = GetEngine()->ActorManager();
|
|
|
|
|
actor_id = actor_manager->CreateActor<HydraGLTFActor>();
|
|
|
|
|
|
|
|
|
|
// Create an instance of the Importer class
|
|
|
|
|
Assimp::Importer importer;
|
|
|
|
|
|
|
|
|
|
// And have it read the given file with some example postprocessing
|
|
|
|
|
// Usually - if speed is not the most important aspect for you - you'll
|
|
|
|
|
// probably to request more postprocessing than we do in this example.
|
|
|
|
|
const aiScene *scene = importer.ReadFile(filename,
|
|
|
|
|
aiProcess_CalcTangentSpace |
|
|
|
|
|
aiProcess_Triangulate |
|
|
|
|
|
aiProcess_JoinIdenticalVertices |
|
|
|
|
|
aiProcess_SortByPType |
|
|
|
|
|
aiProcess_FlipUVs);
|
|
|
|
|
|
|
|
|
|
std::vector<uint32_t> texture_lookup;
|
|
|
|
|
std::vector<uint32_t> material_lookup;
|
|
|
|
|
|
|
|
|
|
assert(scene != nullptr && "Failed to load file");
|
|
|
|
|
|
|
|
|
|
HydraECS *ecs = GetEngine()->ECS();
|
|
|
|
|
HydraPositionComponent position_component = {};
|
|
|
|
|
ecs->AddComponent<HydraPositionComponent>(actor_id, position_component);
|
|
|
|
|
|
|
|
|
|
_ProcessGLTFTextures(scene, texture_lookup, actor_id);
|
|
|
|
|
_ProcessGLTFMaterials(scene, texture_lookup, material_lookup, filename);
|
|
|
|
|
|
|
|
|
|
HydraID root_id = _ProcessGLTFNode(scene, scene->mRootNode, material_lookup);
|
|
|
|
|
|
|
|
|
|
actor_manager->SetRelationship(actor_id, root_id);
|
|
|
|
|
return root_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HydraID HydraGLTFLoader::_ProcessGLTFNode(aiScene const *scene, aiNode *parent_node, std::vector<uint32_t> material_lookup)
|
|
|
|
|
{
|
|
|
|
|
HydraActorManager *actor_manager = GetEngine()->ActorManager();
|
|
|
|
|
HydraID parent_actor_id = actor_manager->CreateActor<HydraGLTFActor>();
|
|
|
|
|
|
|
|
|
|
HydraECS *ecs = GetEngine()->ECS();
|
|
|
|
|
HydraPositionComponent position_component;
|
|
|
|
|
|
|
|
|
|
aiVector3D tmp_scaling = {};
|
|
|
|
|
aiQuaternion tmp_rotation = {};
|
|
|
|
|
aiVector3D tmp_position = {};
|
|
|
|
|
|
|
|
|
|
parent_node->mTransformation.Decompose(tmp_scaling, tmp_rotation, tmp_position);
|
|
|
|
|
|
|
|
|
|
glm::dvec3 scaling = glm::dvec3(tmp_scaling.x, tmp_scaling.y, tmp_scaling.z);
|
|
|
|
|
glm::quat rotation = glm::quat(tmp_rotation.w, tmp_rotation.x, tmp_rotation.y, tmp_rotation.z);
|
|
|
|
|
glm::dvec3 position = glm::dvec3(tmp_position.x, tmp_position.y, tmp_position.z);
|
|
|
|
|
|
|
|
|
|
glm::vec3 euler_angle = glm::eulerAngles(rotation);
|
|
|
|
|
ecs->AddComponent<HydraPositionComponent>(parent_actor_id, position_component);
|
|
|
|
|
|
|
|
|
|
actor_manager->SetScale(parent_actor_id, scaling);
|
|
|
|
|
actor_manager->SetPosition(parent_actor_id, position);
|
|
|
|
|
actor_manager->SetOrientation(parent_actor_id, euler_angle.x, euler_angle.y, euler_angle.z);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i_mesh = 0; i_mesh < parent_node->mNumMeshes; i_mesh++)
|
|
|
|
|
{
|
|
|
|
|
aiMesh *mesh = scene->mMeshes[parent_node->mMeshes[i_mesh]];
|
|
|
|
|
_ProcessGLTFMesh(scene, parent_actor_id, mesh, material_lookup);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (uint32_t i_node = 0; i_node < parent_node->mNumChildren; i_node++)
|
|
|
|
|
{
|
|
|
|
|
HydraID child_actor_id = _ProcessGLTFNode(scene, parent_node->mChildren[i_node], material_lookup);
|
|
|
|
|
actor_manager->SetRelationship(parent_actor_id, child_actor_id);
|
|
|
|
|
}
|
|
|
|
|
return parent_actor_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HydraGLTFLoader::_ProcessGLTFMesh(aiScene const *scene, HydraID parent_actor_id, aiMesh *mesh, std::vector<uint32_t> material_lookup)
|
|
|
|
|
{
|
|
|
|
|
HydraActorManager *actor_manager = GetEngine()->ActorManager();
|
|
|
|
|
HydraID mesh_actor_id = actor_manager->CreateActor<HydraGLTFActor>();
|
|
|
|
|
|
|
|
|
|
aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
|
|
|
|
|
std::vector<StandardVertex> vertexes;
|
|
|
|
|
std::vector<uint32_t> indexes;
|
|
|
|
|
HydraECS *ecs = GetEngine()->ECS();
|
|
|
|
|
|
|
|
|
|
HydraPositionComponent position_component = {};
|
|
|
|
|
|
|
|
|
|
HydraMeshManager *mesh_manager = GetEngine()->MeshManager();
|
|
|
|
|
HydraID mesh_id = mesh_manager->CreateMesh();
|
|
|
|
|
|
|
|
|
|
ecs->AddComponent<HydraPositionComponent>(mesh_actor_id, position_component);
|
|
|
|
|
|
|
|
|
|
HydraID material_id = material_lookup[mesh->mMaterialIndex];
|
|
|
|
|
|
|
|
|
|
if(material_id != INVALID_HYDRA_ID)
|
|
|
|
|
{
|
|
|
|
|
HydraMaterialComponent mat_comp;
|
|
|
|
|
mat_comp.material_id = material_id;
|
|
|
|
|
ecs->AddComponent<HydraMaterialComponent>(mesh_actor_id, mat_comp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HydraMesh *hydra_mesh = mesh_manager->GetMesh(mesh_id);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i_face = 0; i_face < mesh->mNumFaces; i_face++)
|
|
|
|
|
{
|
|
|
|
|
aiFace face = mesh->mFaces[i_face];
|
|
|
|
|
|
|
|
|
|
for (uint32_t i_index = 0; i_index < face.mNumIndices; i_index++)
|
|
|
|
|
{
|
|
|
|
|
hydra_mesh->indexes.push_back(face.mIndices[i_index]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (uint32_t i_verts = 0; i_verts < mesh->mNumVertices; i_verts++)
|
|
|
|
|
{
|
|
|
|
|
StandardVertex vert = {};
|
|
|
|
|
if (mesh->HasPositions())
|
|
|
|
|
{
|
|
|
|
|
vert.position[0] = mesh->mVertices[i_verts].x;
|
|
|
|
|
vert.position[1] = mesh->mVertices[i_verts].y;
|
|
|
|
|
vert.position[2] = mesh->mVertices[i_verts].z;
|
|
|
|
|
}
|
|
|
|
|
if (mesh->HasNormals())
|
|
|
|
|
{
|
|
|
|
|
vert.normal[0] = mesh->mNormals[i_verts].x;
|
|
|
|
|
vert.normal[1] = mesh->mNormals[i_verts].y;
|
|
|
|
|
vert.normal[2] = mesh->mNormals[i_verts].z;
|
|
|
|
|
}
|
2026-07-17 15:35:16 +01:00
|
|
|
|
2026-07-17 15:30:29 +01:00
|
|
|
if(mesh->HasTangentsAndBitangents())
|
|
|
|
|
{
|
|
|
|
|
vert.bitanget[0] = mesh->mBitangents[i_verts].x;
|
|
|
|
|
vert.bitanget[1] = mesh->mBitangents[i_verts].y;
|
|
|
|
|
vert.bitanget[2] = mesh->mBitangents[i_verts].z;
|
|
|
|
|
|
|
|
|
|
vert.tangent[0] = mesh->mTangents[i_verts].x;
|
|
|
|
|
vert.tangent[1] = mesh->mTangents[i_verts].y;
|
|
|
|
|
vert.tangent[2] = mesh->mTangents[i_verts].z;
|
|
|
|
|
}
|
|
|
|
|
if (mesh->HasTextureCoords(0))
|
|
|
|
|
{
|
|
|
|
|
vert.text_coord0[0] = mesh->mTextureCoords[0][i_verts].x;
|
|
|
|
|
vert.text_coord0[1] = mesh->mTextureCoords[0][i_verts].y;
|
|
|
|
|
}
|
|
|
|
|
vert.chunk_id[0] = mesh_actor_id;
|
|
|
|
|
vert.chunk_id[1] = material_id;
|
|
|
|
|
|
|
|
|
|
hydra_mesh->vertexes.push_back(vert);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HydraMeshComponent mesh_comp;
|
|
|
|
|
|
|
|
|
|
mesh_comp.mesh_id = mesh_id;
|
|
|
|
|
mesh_comp.mesh_state = HYDRA_STATE::Waiting;
|
|
|
|
|
|
|
|
|
|
ecs->AddComponent<HydraMeshComponent>(mesh_actor_id, mesh_comp);
|
|
|
|
|
|
|
|
|
|
aiString mat_name;
|
|
|
|
|
mat->Get(AI_MATKEY_NAME, mat_name);
|
|
|
|
|
|
|
|
|
|
// Add renderable component
|
|
|
|
|
HydraRenderableComponent render_comp;
|
|
|
|
|
render_comp.renderable_types.set((uint32_t)HYDRA_RENDERABLE_TYPE::HYDRA_COLOUR, true);
|
|
|
|
|
|
|
|
|
|
ecs->AddComponent<HydraRenderableComponent>(mesh_actor_id, render_comp);
|
|
|
|
|
|
|
|
|
|
actor_manager->SetRelationship(parent_actor_id, mesh_actor_id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void HydraGLTFLoader::_ProcessGLTFMaterials(aiScene const *scene,
|
|
|
|
|
std::vector<uint32_t> &texture_lookup,
|
|
|
|
|
std::vector<uint32_t> &material_lookup,
|
|
|
|
|
std::string filename)
|
|
|
|
|
{
|
|
|
|
|
material_lookup.resize(scene->mNumMaterials);
|
|
|
|
|
HydraTextureBufferManager *texture_manager = GetEngine()->TextureBufferManager();
|
|
|
|
|
for (uint32_t i_mat = 0; i_mat < scene->mNumMaterials; i_mat++)
|
|
|
|
|
{
|
|
|
|
|
HydraMaterialBuffer material;
|
|
|
|
|
aiMaterial *mat = scene->mMaterials[i_mat];
|
|
|
|
|
|
|
|
|
|
aiColor3D color(0.f, 0.f, 0.f);
|
|
|
|
|
aiString name;
|
|
|
|
|
|
|
|
|
|
mat->Get(AI_MATKEY_COLOR_DIFFUSE, color);
|
|
|
|
|
|
|
|
|
|
std::string mat_name = filename + std::to_string(i_mat);
|
|
|
|
|
aiTexture diffuse_tex;
|
|
|
|
|
|
|
|
|
|
uint32_t diffuse_tex_count = mat->GetTextureCount(aiTextureType::aiTextureType_DIFFUSE);
|
|
|
|
|
uint32_t metal_tex_count = mat->GetTextureCount(aiTextureType::aiTextureType_METALNESS);
|
|
|
|
|
uint32_t metalrough_tex_count = mat->GetTextureCount(aiTextureType::aiTextureType_GLTF_METALLIC_ROUGHNESS);
|
|
|
|
|
uint32_t normal_tex_count = mat->GetTextureCount(aiTextureType::aiTextureType_NORMALS);
|
|
|
|
|
uint32_t rough_tex_count = mat->GetTextureCount(aiTextureType::aiTextureType_DIFFUSE_ROUGHNESS);
|
|
|
|
|
|
|
|
|
|
// have to do something here for multiple diffuse textures at some point.
|
|
|
|
|
aiString texture_path;
|
|
|
|
|
aiTextureMapping texture_mapping;
|
|
|
|
|
uint32_t uv_index;
|
|
|
|
|
|
|
|
|
|
if (diffuse_tex_count > 0)
|
|
|
|
|
{
|
|
|
|
|
mat->GetTexture(aiTextureType::aiTextureType_DIFFUSE, 0, &texture_path, &texture_mapping, &uv_index);
|
|
|
|
|
std::string path = std::string(texture_path.C_Str());
|
|
|
|
|
uint32_t texture_index = atoi(path.substr(1).c_str());
|
|
|
|
|
HydraID texture_id = texture_lookup[texture_index];
|
|
|
|
|
material.diffuse_texture_id = texture_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(metalrough_tex_count > 0)
|
|
|
|
|
{
|
|
|
|
|
mat->GetTexture(aiTextureType::aiTextureType_GLTF_METALLIC_ROUGHNESS, 0, &texture_path, &texture_mapping, &uv_index);
|
|
|
|
|
std::string path = std::string(texture_path.C_Str());
|
|
|
|
|
uint32_t texture_index = atoi(path.substr(1).c_str());
|
|
|
|
|
HydraID texture_id = texture_lookup[texture_index];
|
|
|
|
|
material.metallic_rough_texture_id = texture_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(normal_tex_count > 0)
|
|
|
|
|
{
|
|
|
|
|
mat->GetTexture(aiTextureType::aiTextureType_NORMALS, 0, &texture_path, &texture_mapping, &uv_index);
|
|
|
|
|
std::string path = std::string(texture_path.C_Str());
|
|
|
|
|
uint32_t texture_index = atoi(path.substr(1).c_str());
|
|
|
|
|
HydraID texture_id = texture_lookup[texture_index];
|
|
|
|
|
material.normal_texture_id = texture_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
material.diffuse_colour[0] = color.r;
|
|
|
|
|
material.diffuse_colour[1] = color.g;
|
|
|
|
|
material.diffuse_colour[2] = color.b;
|
|
|
|
|
material.diffuse_colour[3] = 1.0f;
|
|
|
|
|
|
|
|
|
|
HydraID material_id = GetEngine()->MaterialBufferManager()->CreateMaterial(material);
|
|
|
|
|
|
|
|
|
|
material_lookup[i_mat] = material_id;
|
|
|
|
|
if (material_id == INVALID_HYDRA_ID)
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error("Could not create material");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// @brief Load all of the scene textures
|
|
|
|
|
/// @param scene containing scene
|
|
|
|
|
/// @param texture_lookup index of texture in the scene to the Hydra texture ID
|
|
|
|
|
void HydraGLTFLoader::_ProcessGLTFTextures(aiScene const *scene, std::vector<uint32_t> &texture_lookup, HydraID actor_id)
|
|
|
|
|
{
|
|
|
|
|
HydraTextureBufferManager *texture_manager = GetEngine()->TextureBufferManager();
|
|
|
|
|
// Make space for the texture lookups
|
|
|
|
|
texture_lookup.resize(scene->mNumTextures);
|
|
|
|
|
|
|
|
|
|
for (uint32_t i_tex = 0; i_tex < scene->mNumTextures; i_tex++)
|
|
|
|
|
{
|
|
|
|
|
std::string texture_name = std::to_string(actor_id) + "_" + std::to_string(i_tex);
|
|
|
|
|
aiTexture *tex = scene->mTextures[i_tex];
|
|
|
|
|
// Create a holder for the texture
|
|
|
|
|
int32_t width = 0;
|
|
|
|
|
int32_t height = 0;
|
|
|
|
|
int32_t channels = 0;
|
|
|
|
|
//stbi_set_flip_vertically_on_load(1);
|
|
|
|
|
stbi_uc* data = stbi_load_from_memory(reinterpret_cast<stbi_uc*>(tex->pcData), tex->mWidth, &width, &height, &channels, 4);
|
|
|
|
|
|
2026-07-28 19:02:45 +01:00
|
|
|
HydraID texture_id = texture_manager->CreateTexture(texture_name,
|
2026-07-17 15:30:29 +01:00
|
|
|
width,
|
|
|
|
|
height,
|
|
|
|
|
GL_RGBA8,
|
|
|
|
|
GL_LINEAR_MIPMAP_LINEAR,
|
|
|
|
|
GL_LINEAR,
|
2026-07-28 00:26:04 +01:00
|
|
|
1,
|
2026-07-17 15:30:29 +01:00
|
|
|
GL_RGBA,
|
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
|
5,
|
|
|
|
|
data);
|
2026-07-28 19:02:45 +01:00
|
|
|
texture_manager->BindTexture(texture_id, GL_TEXTURE_2D);
|
2026-07-17 15:30:29 +01:00
|
|
|
// store the texture id against the scene index for the texture. Materials will have *n where n is the index
|
|
|
|
|
texture_lookup[i_tex] = texture_id;
|
|
|
|
|
}
|
|
|
|
|
}
|