162 lines
5.8 KiB
C
162 lines
5.8 KiB
C
#include "Geometry/Mesh.h"
|
|
#include "Common/String.h"
|
|
#include "Material/StandardLit.h"
|
|
#include "assimp/cimport.h"
|
|
#include "assimp/scene.h"
|
|
#include "assimp/postprocess.h"
|
|
#include "cglm/struct/mat4.h"
|
|
|
|
static texture_handle_t load_material_texture(const struct aiMaterial* material, enum aiTextureType type, const char* filename, scene_t* scene)
|
|
{
|
|
struct aiString path;
|
|
if (AI_SUCCESS == aiGetMaterialTexture(material, type, 0, &path, NULL, NULL, NULL, NULL, NULL, NULL))
|
|
{
|
|
if (!is_absolute_path(path.data))
|
|
{
|
|
char directory[1024];
|
|
get_path_directory(filename, directory, 1024);
|
|
char image_path[1024];
|
|
memcpy(image_path, path.data, 1024);
|
|
string_join(directory, image_path, path.data, 1024);
|
|
}
|
|
|
|
return texture_load(path.data, true, true, UINT_8, &scene->textures);
|
|
}
|
|
return invalid_texture_handle();
|
|
}
|
|
|
|
mesh_handle_t mesh_load(const char* filename, scene_t* scene)
|
|
{
|
|
mesh_handle_t entity = {0};
|
|
entity.model_id = UINT32_MAX;
|
|
entity.instance_id = UINT32_MAX;
|
|
|
|
const struct aiScene* mesh_scene = aiImportFile(filename, aiProcessPreset_TargetRealtime_Quality);
|
|
if (mesh_scene == NULL)
|
|
{
|
|
perror(aiGetErrorString());
|
|
return entity;
|
|
}
|
|
|
|
entity.material_id = scene->materials.count;
|
|
|
|
// Reserve a model sized for the imported geometry.
|
|
uint64_t triangle_reserve = 0;
|
|
for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++)
|
|
{
|
|
const struct aiMesh* mesh = mesh_scene->mMeshes[i];
|
|
if (mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Each face is expected to be a triangle; we still validate per face below.
|
|
triangle_reserve += (uint64_t)mesh->mNumFaces;
|
|
}
|
|
|
|
entity.model_id = scene_add_mesh_model(scene, triangle_reserve);
|
|
mesh_model_t* model = NULL;
|
|
if (entity.model_id != UINT32_MAX && entity.model_id < scene->mesh_models.capacity)
|
|
{
|
|
model = &scene->mesh_models.buffer[entity.model_id];
|
|
}
|
|
|
|
for (uint32_t i = 0; i < mesh_scene->mNumMaterials; i++)
|
|
{
|
|
const struct aiMaterial* src = mesh_scene->mMaterials[i];
|
|
|
|
struct aiColor4D base_color = {0.73f};
|
|
aiGetMaterialColor(src, AI_MATKEY_COLOR_DIFFUSE, &base_color);
|
|
|
|
float roughness = 0.75f;
|
|
aiGetMaterialFloat(src, AI_MATKEY_ROUGHNESS_FACTOR, &roughness);
|
|
|
|
float metallic = 0.0f;
|
|
aiGetMaterialFloat(src, AI_MATKEY_METALLIC_FACTOR, &metallic);
|
|
|
|
texture_handle_t albedo_entity = load_material_texture(src, aiTextureType_DIFFUSE, filename, scene);
|
|
texture_handle_t normal_entity = load_material_texture(src, aiTextureType_NORMALS, filename, scene);
|
|
texture_handle_t roughness_entity = load_material_texture(src, aiTextureType_DIFFUSE_ROUGHNESS, filename, scene);
|
|
texture_handle_t metallic_entity = load_material_texture(src, aiTextureType_METALNESS, filename, scene);
|
|
|
|
standard_lit_properties_t prop =
|
|
{
|
|
.albedo = {base_color.r, base_color.g, base_color.b},
|
|
.roughness = roughness,
|
|
.metallic = metallic,
|
|
|
|
.albedo_texture = albedo_entity,
|
|
.normal_texture = normal_entity,
|
|
.roughness_texture = roughness_entity,
|
|
.metallic_texture = metallic_entity,
|
|
};
|
|
|
|
material_create_standard_lit_default(&prop, &scene->materials);
|
|
entity.material_count++;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < mesh_scene->mNumMeshes; i++)
|
|
{
|
|
const struct aiMesh* mesh = mesh_scene->mMeshes[i];
|
|
|
|
//TODO: Handle all primitive types, not just triangles
|
|
if (mesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
bool has_uv = mesh->mTextureCoords[0] != NULL && mesh->mNumUVComponents[0] >= 2;
|
|
|
|
for (uint32_t j = 0; j < mesh->mNumFaces; j++)
|
|
{
|
|
const struct aiFace* face = &mesh->mFaces[j];
|
|
if (face->mNumIndices != 3)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
uint32_t index0 = face->mIndices[0];
|
|
uint32_t index1 = face->mIndices[1];
|
|
uint32_t index2 = face->mIndices[2];
|
|
|
|
vertex_t vertices[3] = {0};
|
|
for (uint32_t k = 0; k < 3; k++)
|
|
{
|
|
vertices[k].position = (vec3s){mesh->mVertices[face->mIndices[k]].x, mesh->mVertices[face->mIndices[k]].y, mesh->mVertices[face->mIndices[k]].z};
|
|
vertices[k].normal = (vec3s){mesh->mNormals[face->mIndices[k]].x, mesh->mNormals[face->mIndices[k]].y, mesh->mNormals[face->mIndices[k]].z};
|
|
vertices[k].tangent = (vec3s){mesh->mTangents[face->mIndices[k]].x, mesh->mTangents[face->mIndices[k]].y, mesh->mTangents[face->mIndices[k]].z};
|
|
if (has_uv)
|
|
{
|
|
vertices[k].uv = (vec2s){mesh->mTextureCoords[0][face->mIndices[k]].x, mesh->mTextureCoords[0][face->mIndices[k]].y};
|
|
}
|
|
}
|
|
|
|
if (model != NULL)
|
|
{
|
|
triangle_create(vertices[0], vertices[1], vertices[2], (uint8_t)(entity.material_id + mesh->mMaterialIndex), &model->triangles);
|
|
}
|
|
entity.triangle_count++;
|
|
}
|
|
}
|
|
|
|
if (model != NULL && model->triangles.count > 0)
|
|
{
|
|
bvh_tree_free(&model->blas);
|
|
if (bvh_tree_init(&model->blas, &model->triangles))
|
|
{
|
|
(void)bvh_tree_build(&model->blas);
|
|
if (model->blas.nodes != NULL && model->blas.node_count > 0)
|
|
{
|
|
model->local_bounds = model->blas.nodes[0].bounds;
|
|
}
|
|
}
|
|
|
|
mat4s identity = glms_mat4_identity();
|
|
entity.local_to_world = identity;
|
|
entity.instance_id = scene_add_mesh_instance(scene, entity.model_id, identity);
|
|
}
|
|
|
|
aiReleaseImport(mesh_scene);
|
|
return entity;
|
|
}
|