Created
August 10, 2020 10:07
-
-
Save NotAPenguin0/baa53c45cb44aedaa67e83f2c3281636 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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