Skip to content

Instantly share code, notes, and snippets.

@NotAPenguin0
Created August 10, 2020 10:07
Show Gist options
  • Select an option

  • Save NotAPenguin0/baa53c45cb44aedaa67e83f2c3281636 to your computer and use it in GitHub Desktop.

Select an option

Save NotAPenguin0/baa53c45cb44aedaa67e83f2c3281636 to your computer and use it in GitHub Desktop.
using ModelMaterials = std::vector<Handle<Material>>;
static Handle<Texture> get_texture_if_present(Context& ctx, fs::path const& cwd, aiMaterial* material, aiTextureType type, bool srgb = false) {
if (material->GetTextureCount(type) > 0) {
aiString path;
material->GetTexture(type, 0, &path);
fs::path load_path = cwd / fs::path(path.C_Str());
Handle<Texture> handle = ctx.request_texture(load_path.generic_string(), srgb);
return handle;
}
return { Handle<Texture>::none };
}
static ModelMaterials load_materials(Context& ctx, fs::path const& cwd, aiScene const* scene) {
ModelMaterials materials;
for (size_t i = 0; i < scene->mNumMaterials; ++i) {
aiMaterial* mat = scene->mMaterials[i];
Material material;
material.color = get_texture_if_present(ctx, cwd, mat, aiTextureType_DIFFUSE, true);
material.normal = get_texture_if_present(ctx, cwd, mat, aiTextureType_NORMALS);
material.metallic = get_texture_if_present(ctx, cwd, mat, aiTextureType_METALNESS);
material.roughness = get_texture_if_present(ctx, cwd, mat, aiTextureType_DIFFUSE_ROUGHNESS);
material.ambient_occlusion = get_texture_if_present(ctx, cwd, mat, aiTextureType_AMBIENT_OCCLUSION);
Handle<Material> handle = assets::take(std::move(material));
materials.push_back(handle);
}
return materials;
}
static void process_node(Context& ctx, std::vector<Handle<Mesh>>& meshes, ModelMaterials materials,
Model cur_entity, aiNode const* node, aiScene const* scene) {
using namespace components;
for (size_t i = 0; i < node->mNumMeshes; ++i) {
ecs::entity_t child_entity = ctx.world->create_entity(cur_entity.id);
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
// Create an entity for this mesh. We need these components added before add_mesh will work
ctx.world->lock();
ctx.world->ecs().add_component<StaticMesh>(child_entity);
ctx.world->ecs().add_component<MeshRenderer>(child_entity);
ctx.world->unlock();
Handle<Mesh> mesh_handle = assets::insert_pending<Mesh>();
meshes.push_back(mesh_handle);
ctx.tasks->launch(load_model_mesh, ModelMeshLoadInfo{&ctx, mesh_handle, mesh});
ctx.world->lock();
Handle<Material> material = materials[mesh->mMaterialIndex];
ctx.world->ecs().get_component<MeshRenderer>(child_entity).material = material;
ctx.world->ecs().get_component<StaticMesh>(child_entity).mesh = mesh_handle;
ctx.world->ecs().get_component<Transform>(child_entity).scale = glm::vec3(10.0f); // Don't hardcode! TODO!
ctx.world->unlock();
}
for (size_t i = 0; i < node->mNumChildren; ++i) {
ecs::entity_t child_entity = ctx.world->create_entity(cur_entity.id);
process_node(ctx, meshes, materials, { child_entity }, node->mChildren[i], scene);
}
}
static void do_model_load(ftl::TaskScheduler* scheduler, ModelLoadInfo load_info) {
Assimp::Importer* importer = new Assimp::Importer;
constexpr int postprocess = aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenNormals | aiProcess_CalcTangentSpace;
aiScene const* scene = importer->ReadFile(std::string(load_info.path), postprocess);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE ||
!scene->mRootNode) {
throw std::runtime_error("Failed to load model");
}
world::World& world = *load_info.ctx->world;
ecs::entity_t root = world.create_entity();
Model model{ root };
ModelMaterials materials = load_materials(*load_info.ctx, fs::path(load_info.path).parent_path(), scene);
std::vector<Handle<Mesh>> meshes;
process_node(*load_info.ctx, meshes, materials, model, scene->mRootNode, scene);
TaskManager& task_manager = *load_info.ctx->tasks;
task_manager.wait_task(
[meshes]() -> TaskStatus {
for (auto mesh : meshes) {
if (!assets::is_ready(mesh)) { return TaskStatus::Running; }
}
// TODO: check materials too?
return TaskStatus::Completed;
},
[importer, load_info, model]() mutable -> void {
delete importer;
io::log("finished loading model");
assets::finalize_load(load_info.handle, std::move(model));
}
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment