From e5e30260050ed28ea0f1969fe8557302f193efb1 Mon Sep 17 00:00:00 2001 From: SirLynix Date: Wed, 4 May 2022 12:50:05 +0200 Subject: [PATCH] Push current work --- examples/Showcase/main.cpp | 163 ++-- include/Nazara/Math/OrientedBox.inl | 4 +- include/Nazara/Utility/Animation.hpp | 5 +- include/Nazara/Utility/Sequence.hpp | 6 +- include/Nazara/Utility/Skeleton.hpp | 2 + plugins/Assimp/Plugin.cpp | 1024 +++++++++++++------------- src/Nazara/Core/PluginManager.cpp | 20 +- src/Nazara/Utility/Animation.cpp | 6 + src/Nazara/Utility/Skeleton.cpp | 3 +- 9 files changed, 653 insertions(+), 580 deletions(-) diff --git a/examples/Showcase/main.cpp b/examples/Showcase/main.cpp index 4f22de5c4..ce8c3121e 100644 --- a/examples/Showcase/main.cpp +++ b/examples/Showcase/main.cpp @@ -33,6 +33,10 @@ int main() Nz::Modules nazara(rendererConfig); Nz::PluginManager::Mount(Nz::Plugin::Assimp); + Nz::CallOnExit unmountAssimp([] + { + Nz::PluginManager::Unmount(Nz::Plugin::Assimp); + }); std::shared_ptr device = Nz::Graphics::Instance()->GetRenderDevice(); @@ -55,19 +59,27 @@ int main() texParams.renderDevice = device; entt::entity playerEntity = registry.create(); + entt::entity playerRotation = registry.create(); + entt::entity playerCamera = registry.create(); { auto& playerNode = registry.emplace(playerEntity); playerNode.SetPosition(0.f, 1.8f, 1.f); - playerNode.SetRotation(Nz::EulerAnglesf(-30.f, 0.f, 0.f)); auto& playerBody = registry.emplace(playerEntity, &physSytem.GetPhysWorld()); - playerBody.SetMass(0.f); - playerBody.SetGeom(std::make_shared(1.8f, 0.5f)); + playerBody.SetMass(42.f); + playerBody.SetGeom(std::make_shared(Nz::Vector3f::Unit())); - auto& playerComponent = registry.emplace(playerEntity, window.GetRenderTarget()); - playerComponent.UpdateZNear(0.2f); - playerComponent.UpdateRenderMask(1); - playerComponent.UpdateClearColor(Nz::Color(127, 127, 127)); + auto& playerRotNode = registry.emplace(playerRotation); + playerRotNode.SetParent(playerNode); + + auto& cameraNode = registry.emplace(playerCamera); + cameraNode.SetParent(playerRotNode); + + auto& cameraComponent = registry.emplace(playerCamera, window.GetRenderTarget()); + cameraComponent.UpdateZNear(0.2f); + cameraComponent.UpdateZFar(10000.f); + cameraComponent.UpdateRenderMask(1); + cameraComponent.UpdateClearColor(Nz::Color(0.5f, 0.5f, 0.5f)); } Nz::FieldOffsets skeletalOffsets(Nz::StructLayout::Std140); @@ -76,16 +88,11 @@ int main() std::vector skeletalBufferMem(skeletalOffsets.GetAlignedSize()); Nz::Matrix4f* matrices = Nz::AccessByOffset(skeletalBufferMem.data(), arrayOffset); - std::shared_ptr bobAnim = Nz::Animation::LoadFromFile(resourceDir / "hellknight/idle2.md5anim"); - if (!bobAnim) - { - NazaraError("Failed to load bob anim"); - return __LINE__; - } - Nz::MeshParams meshParams; meshParams.animated = true; - //meshParams.center = true; + meshParams.center = true; + meshParams.texCoordScale = Nz::Vector2f(1.f, -1.f); + meshParams.texCoordOffset = Nz::Vector2f(0.f, 1.f); //meshParams.matrix = Nz::Matrix4f::Scale(Nz::Vector3f(10.f)); meshParams.vertexDeclaration = Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent_Skinning); @@ -96,9 +103,22 @@ int main() return __LINE__; } + Nz::AnimationParams matParams; + matParams.skeleton = bobMesh->GetSkeleton(); + + std::shared_ptr bobAnim = Nz::Animation::LoadFromFile(resourceDir / "hellknight/idle.md5anim", matParams); + if (!bobAnim) + { + NazaraError("Failed to load bob anim"); + return __LINE__; + } + Nz::Skeleton skeleton = *bobMesh->GetSkeleton(); - bobAnim->AnimateSkeleton(&skeleton, 0, 1, 0.5f); + std::cout << "joint count: " << skeleton.GetJointCount() << std::endl; + //std::cout << "anim joint count: " << bobAnim->GetJointCount() << std::endl; + + //bobAnim->AnimateSkeleton(&skeleton, 0, 1, 0.5f); /*for (std::size_t i = 0; i < bobMesh->GetSubMeshCount(); ++i) { @@ -114,42 +134,70 @@ int main() Nz::SkinPosition(skinningData, 0, mapper.GetVertexCount()); }*/ - for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i) - matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix(); + /*for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i) + matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix();*/ std::shared_ptr renderBuffer = device->InstantiateBuffer(Nz::BufferType::Uniform, skeletalBufferMem.size(), Nz::BufferUsage::Write, skeletalBufferMem.data()); - entt::entity bobEntity = registry.create(); + const Nz::Boxf& bobAABB = bobMesh->GetAABB(); + std::shared_ptr bobGfxMesh = std::make_shared(*bobMesh); + + std::shared_ptr bobModel = std::make_shared(std::move(bobGfxMesh), bobAABB); + for (std::size_t i = 0; i < bobMesh->GetMaterialCount(); ++i) { - const Nz::Boxf& bobAABB = bobMesh->GetAABB(); - std::shared_ptr bobGfxMesh = std::make_shared(*bobMesh); + std::string matPath; + bobMesh->GetMaterialData(i).GetStringParameter(Nz::MaterialData::DiffuseTexturePath, &matPath); - std::shared_ptr bobModel = std::make_shared(std::move(bobGfxMesh), bobAABB); - for (std::size_t i = 0; i < bobMesh->GetMaterialCount(); ++i) + std::shared_ptr bobMat = std::make_shared(); + + std::shared_ptr bobMatPass = std::make_shared(Nz::BasicMaterial::GetSettings()); + bobMatPass->SetSharedUniformBuffer(0, renderBuffer); + + bobMatPass->EnableDepthBuffer(true); { - std::string matPath; - bobMesh->GetMaterialData(i).GetStringParameter(Nz::MaterialData::FilePath, &matPath); - - std::shared_ptr bobMat = std::make_shared(); - - std::shared_ptr bobMatPass = std::make_shared(Nz::BasicMaterial::GetSettings()); - bobMatPass->SetSharedUniformBuffer(0, renderBuffer); - - bobMatPass->EnableDepthBuffer(true); + Nz::BasicMaterial basicMat(*bobMatPass); + if (matPath.find("gob") != matPath.npos) { - Nz::BasicMaterial basicMat(*bobMatPass); - basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(matPath + ".tga", texParams)); - } - if (i == 0 || i == 3) - bobMat->AddPass("ForwardPass", bobMatPass); + bobMatPass->EnableFlag(Nz::MaterialPassFlag::SortByDistance); - bobModel->SetMaterial(i, bobMat); + basicMat.SetAlphaMap(Nz::Texture::LoadFromFile(matPath, texParams)); + bobMatPass->EnableDepthWrite(false); + + bobMatPass->EnableBlending(true); + bobMatPass->SetBlendEquation(Nz::BlendEquation::Add, Nz::BlendEquation::Add); + bobMatPass->SetBlendFunc(Nz::BlendFunc::SrcAlpha, Nz::BlendFunc::InvSrcAlpha, Nz::BlendFunc::One, Nz::BlendFunc::Zero); + } + else + basicMat.SetDiffuseMap(Nz::Texture::LoadFromFile(matPath, texParams)); } + bobMat->AddPass("ForwardPass", bobMatPass); + + bobModel->SetMaterial(i, bobMat); + } + + /*for (std::size_t y = 0; y < 50; ++y) + { + for (std::size_t x = 0; x < 50; ++x) + { + entt::entity bobEntity = registry.create(); + + auto& bobNode = registry.emplace(bobEntity); + bobNode.SetPosition(Nz::Vector3f(x - 25.f, bobAABB.height / 2.f, -float(y))); + bobNode.SetRotation(Nz::EulerAnglesf(-90.f, -90.f, 0.f)); + bobNode.SetScale(1.f / 40.f * 0.5f); + + auto& bobGfx = registry.emplace(bobEntity); + bobGfx.AttachRenderable(bobModel, 0xFFFFFFFF); + } + }*/ + + entt::entity bobEntity = registry.create(); + { auto& bobNode = registry.emplace(bobEntity); - bobNode.SetPosition(Nz::Vector3f(0.f, bobAABB.height / 2.f, 0.f)); - bobNode.SetRotation(Nz::EulerAnglesf(-90.f, -90.f, 0.f)); + bobNode.SetRotation(Nz::EulerAnglesf(90.f, -90.f, 0.f)); bobNode.SetScale(1.f / 40.f * 0.5f); + bobNode.SetPosition(bobNode.GetScale() * Nz::Vector3f(0.f, bobAABB.height / 2.f, 0.f)); auto& bobGfx = registry.emplace(bobEntity); bobGfx.AttachRenderable(bobModel, 0xFFFFFFFF); @@ -197,10 +245,13 @@ int main() planeGfx.AttachRenderable(planeModel, 0xFFFFFFFF); } + window.EnableEventPolling(true); + Nz::Clock fpsClock, updateClock; float incr = 0.f; unsigned int currentFrame = 0; unsigned int nextFrame = 1; + Nz::EulerAnglesf camAngles = Nz::EulerAnglesf(-30.f, 0.f, 0.f); Nz::UInt64 lastTime = Nz::GetElapsedMicroseconds(); Nz::UInt64 fps = 0; while (window.IsOpen()) @@ -222,7 +273,21 @@ int main() break; case Nz::WindowEventType::MouseMoved: + { + // Gestion de la caméra free-fly (Rotation) + float sensitivity = 0.3f; // Sensibilité de la souris + + // On modifie l'angle de la caméra grâce au déplacement relatif sur X de la souris + camAngles.yaw = camAngles.yaw - event.mouseMove.deltaX * sensitivity; + camAngles.yaw.Normalize(); + + // Idem, mais pour éviter les problèmes de calcul de la matrice de vue, on restreint les angles + camAngles.pitch = Nz::Clamp(camAngles.pitch - event.mouseMove.deltaY * sensitivity, -89.f, 89.f); + + auto& playerRotNode = registry.get(playerRotation); + playerRotNode.SetRotation(camAngles); break; + } default: break; @@ -237,8 +302,22 @@ int main() auto& playerBody = registry.get(playerEntity); + float mass = playerBody.GetMass(); + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Space)) - playerBody.AddForce(Nz::Vector3f(0.f, playerBody.GetMass() * 50.f, 0.f)); + playerBody.AddForce(Nz::Vector3f(0.f, mass * 50.f, 0.f)); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Up) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Z)) + playerBody.AddForce(Nz::Vector3f::Forward() * 25.f * mass, Nz::CoordSys::Local); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Down) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::S)) + playerBody.AddForce(Nz::Vector3f::Backward() * 25.f * mass, Nz::CoordSys::Local); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Left) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Q)) + playerBody.AddForce(Nz::Vector3f::Left() * 25.f * mass, Nz::CoordSys::Local); + + if (Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::Right) || Nz::Keyboard::IsKeyPressed(Nz::Keyboard::VKey::D)) + playerBody.AddForce(Nz::Vector3f::Right() * 25.f * mass, Nz::CoordSys::Local); incr += 1.f / 60.f * 30.f; if (incr >= 1.f) @@ -251,6 +330,8 @@ int main() nextFrame = 0; } + std::cout << currentFrame << std::endl; + bobAnim->AnimateSkeleton(&skeleton, currentFrame, nextFrame, incr); for (std::size_t i = 0; i < skeleton.GetJointCount(); ++i) matrices[i] = skeleton.GetJoint(i)->GetSkinningMatrix(); diff --git a/include/Nazara/Math/OrientedBox.inl b/include/Nazara/Math/OrientedBox.inl index 17a3f3c56..7e67e0143 100644 --- a/include/Nazara/Math/OrientedBox.inl +++ b/include/Nazara/Math/OrientedBox.inl @@ -256,7 +256,7 @@ namespace Nz Vector3& OrientedBox::operator()(unsigned int i) { #if NAZARA_MATH_SAFE - if (i > BoxCornerCount) + if (i >= BoxCornerCount) { std::ostringstream ss; ss << "Index out of range: (" << i << " >= " << BoxCornerCount << ")"; @@ -281,7 +281,7 @@ namespace Nz Vector3 OrientedBox::operator()(unsigned int i) const { #if NAZARA_MATH_SAFE - if (i > BoxCornerCount) + if (i >= BoxCornerCount) { std::ostringstream ss; ss << "Index out of range: (" << i << " >= " << BoxCornerCount << ")"; diff --git a/include/Nazara/Utility/Animation.hpp b/include/Nazara/Utility/Animation.hpp index 04056409a..db6f4d60c 100644 --- a/include/Nazara/Utility/Animation.hpp +++ b/include/Nazara/Utility/Animation.hpp @@ -21,12 +21,16 @@ namespace Nz { + class Skeleton; + struct NAZARA_UTILITY_API AnimationParams : ResourceParameters { // La frame de fin à charger std::size_t endFrame = 0xFFFFFFFF; // La frame de début à charger std::size_t startFrame = 0; + // Reference skeleton + const Skeleton* skeleton = nullptr; bool IsValid() const; }; @@ -34,7 +38,6 @@ namespace Nz class Animation; struct Sequence; struct SequenceJoint; - class Skeleton; using AnimationLibrary = ObjectLibrary; using AnimationLoader = ResourceLoader; diff --git a/include/Nazara/Utility/Sequence.hpp b/include/Nazara/Utility/Sequence.hpp index 66a6d3dd6..852afe45f 100644 --- a/include/Nazara/Utility/Sequence.hpp +++ b/include/Nazara/Utility/Sequence.hpp @@ -23,9 +23,9 @@ namespace Nz struct SequenceJoint { - Quaternionf rotation; - Vector3f position; - Vector3f scale; + Quaternionf rotation = Quaternionf::Identity(); + Vector3f position = Vector3f::Zero(); + Vector3f scale = Vector3f::Unit(); }; } diff --git a/include/Nazara/Utility/Skeleton.hpp b/include/Nazara/Utility/Skeleton.hpp index 0c5b14e7b..888472df8 100644 --- a/include/Nazara/Utility/Skeleton.hpp +++ b/include/Nazara/Utility/Skeleton.hpp @@ -57,6 +57,8 @@ namespace Nz // Signals: NazaraSignal(OnSkeletonJointsInvalidated, const Skeleton* /*skeleton*/); + static constexpr std::size_t InvalidJointIndex = std::numeric_limits::max(); + private: void InvalidateJoints(); void InvalidateJointMap(); diff --git a/plugins/Assimp/Plugin.cpp b/plugins/Assimp/Plugin.cpp index 33450275f..7c72f5098 100644 --- a/plugins/Assimp/Plugin.cpp +++ b/plugins/Assimp/Plugin.cpp @@ -43,33 +43,136 @@ SOFTWARE. #include #include #include +#include +#include #include +#include -using namespace Nz; - -void ProcessJoints(aiNode* node, Skeleton* skeleton, const std::unordered_set& joints) +struct SceneInfo { - std::string_view jointName(node->mName.data, node->mName.length); - if (joints.count(jointName)) + struct Node { - Joint* joint = skeleton->GetJoint(std::string(jointName)); + const aiNode* node; + std::size_t totalChildrenCount; + }; - if (node->mParent) - joint->SetParent(skeleton->GetJoint(node->mParent->mName.C_Str())); + struct SkeletalMesh + { + const aiMesh* mesh; + std::size_t nodeIndex; + std::size_t skeletonRootIndex; + std::unordered_map bones; + }; - Matrix4f transformMatrix(node->mTransformation.a1, node->mTransformation.a2, node->mTransformation.a3, node->mTransformation.a4, - node->mTransformation.b1, node->mTransformation.b2, node->mTransformation.b3, node->mTransformation.b4, - node->mTransformation.c1, node->mTransformation.c2, node->mTransformation.c3, node->mTransformation.c4, - node->mTransformation.d1, node->mTransformation.d2, node->mTransformation.d3, node->mTransformation.d4); + struct StaticMesh + { + const aiMesh* mesh; + std::size_t nodeIndex; + }; - transformMatrix.Transpose(); - transformMatrix.InverseTransform(); + std::unordered_multimap nodeByName; + std::vector nodes; + std::vector skeletalMeshes; + std::vector staticMeshes; +}; - joint->SetInverseBindMatrix(transformMatrix); +void VisitNodes(SceneInfo& sceneInfo, const aiScene* scene, const aiNode* node) +{ + std::size_t nodeIndex = sceneInfo.nodes.size(); + sceneInfo.nodeByName.emplace(node->mName.C_Str(), nodeIndex); + auto& sceneNode = sceneInfo.nodes.emplace_back(); + sceneNode.node = node; + + for (unsigned int i = 0; i < node->mNumMeshes; ++i) + { + const aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + if (mesh->HasBones()) + { + auto& skeletalMesh = sceneInfo.skeletalMeshes.emplace_back(); + skeletalMesh.mesh = mesh; + skeletalMesh.nodeIndex = nodeIndex; + + for (unsigned int boneIndex = 0; boneIndex < mesh->mNumBones; ++boneIndex) + skeletalMesh.bones.emplace(mesh->mBones[boneIndex]->mName.C_Str(), boneIndex); + } + else + { + auto& staticMesh = sceneInfo.staticMeshes.emplace_back(); + staticMesh.mesh = mesh; + staticMesh.nodeIndex = nodeIndex; + } + } + + std::size_t prevNodeCount = sceneInfo.nodes.size(); + + for (unsigned int i = 0; i < node->mNumChildren; ++i) + VisitNodes(sceneInfo, scene, node->mChildren[i]); + + // Can't use sceneNode from there + + sceneInfo.nodes[nodeIndex].totalChildrenCount = sceneInfo.nodes.size() - prevNodeCount; +} + +bool FindSkeletonRoot(SceneInfo& sceneInfo, SceneInfo::SkeletalMesh& skeletalMesh, const aiNode* node) +{ + if (skeletalMesh.bones.find(node->mName.C_Str()) != skeletalMesh.bones.end()) + { + // Get to parents until there's only one child + while (node->mParent && node->mParent->mNumChildren != 1) + node = node->mParent; + + /*if (!node->mParent && node->mNumChildren > 1) + { + NazaraError("failed to identify skeleton root node"); + return false; + }*/ + + auto range = sceneInfo.nodeByName.equal_range(node->mName.C_Str()); + if (std::distance(range.first, range.second) != 1) + { + NazaraError("failed to identify skeleton root node: " + std::to_string(std::distance(range.first, range.second)) + " node(s) matched"); + return false; + } + + skeletalMesh.skeletonRootIndex = range.first->second; + return true; } for (unsigned int i = 0; i < node->mNumChildren; ++i) - ProcessJoints(node->mChildren[i], skeleton, joints); + { + if (FindSkeletonRoot(sceneInfo, skeletalMesh, node->mChildren[i])) + return true; + } + + return false; +} + +void ProcessJoints(const SceneInfo::SkeletalMesh& skeletalMesh, Nz::Skeleton* skeleton, const aiNode* node, std::size_t& jointIndex) +{ + Nz::Joint* joint = skeleton->GetJoint(jointIndex); + joint->SetName(node->mName.C_Str()); + + if (jointIndex != 0) + joint->SetParent(skeleton->GetJoint(node->mParent->mName.C_Str())); + + jointIndex++; + + if (auto it = skeletalMesh.bones.find(node->mName.C_Str()); it != skeletalMesh.bones.end()) + { + const aiBone* bone = skeletalMesh.mesh->mBones[it->second]; + + Nz::Matrix4f offsetMatrix(bone->mOffsetMatrix.a1, bone->mOffsetMatrix.b1, bone->mOffsetMatrix.c1, bone->mOffsetMatrix.d1, + bone->mOffsetMatrix.a2, bone->mOffsetMatrix.b2, bone->mOffsetMatrix.c2, bone->mOffsetMatrix.d2, + bone->mOffsetMatrix.a3, bone->mOffsetMatrix.b3, bone->mOffsetMatrix.c3, bone->mOffsetMatrix.d3, + bone->mOffsetMatrix.a4, bone->mOffsetMatrix.b4, bone->mOffsetMatrix.c4, bone->mOffsetMatrix.d4); + + joint->SetInverseBindMatrix(offsetMatrix); + } + else + joint->SetInverseBindMatrix(Nz::Matrix4f::Identity()); + + for (unsigned int i = 0; i < node->mNumChildren; ++i) + ProcessJoints(skeletalMesh, skeleton, node->mChildren[i], jointIndex); } bool IsSupported(const std::string_view& extension) @@ -82,17 +185,19 @@ bool IsSupported(const std::string_view& extension) return (aiIsExtensionSupported(dotExt.data()) == AI_TRUE); } -Ternary CheckAnimation(Stream& /*stream*/, const AnimationParams& parameters) +Nz::Ternary CheckAnimation(Nz::Stream& /*stream*/, const Nz::AnimationParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) - return Ternary::False; + return Nz::Ternary::False; - return Ternary::Unknown; + return Nz::Ternary::Unknown; } -std::shared_ptr LoadAnimation(Stream& stream, const AnimationParams& parameters) +std::shared_ptr LoadAnimation(Nz::Stream& stream, const Nz::AnimationParams& parameters) { + NazaraAssert(parameters.IsValid(), "invalid animation parameters"); + std::string streamPath = Nz::PathToString(stream.GetPath()); FileIOUserdata userdata; @@ -104,22 +209,25 @@ std::shared_ptr LoadAnimation(Stream& stream, const AnimationParams& fileIO.OpenProc = StreamOpener; fileIO.UserData = reinterpret_cast(&userdata); - unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_Debone + unsigned int postProcess = aiProcess_CalcTangentSpace /*| aiProcess_Debone*/ | aiProcess_FindInvalidData | aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder | aiProcess_GenSmoothNormals | aiProcess_GenUVCoords | aiProcess_JoinIdenticalVertices | aiProcess_LimitBoneWeights | aiProcess_MakeLeftHanded - | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes + /*| aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes*/ | aiProcess_RemoveComponent | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType | aiProcess_SplitLargeMeshes | aiProcess_TransformUVCoords | aiProcess_Triangulate; aiPropertyStore* properties = aiCreatePropertyStore(); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); - //aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, ~aiComponent_ANIMATIONS); + aiSetImportPropertyInteger(properties, AI_CONFIG_PP_SBP_REMOVE, ~aiPrimitiveType_TRIANGLE); //< We only want triangles + Nz::CallOnExit releaseProperties([&] { aiReleasePropertyStore(properties); }); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); - aiReleasePropertyStore(properties); + Nz::CallOnExit releaseScene([&] { aiReleaseImport(scene); }); + + releaseProperties.CallAndReset(); if (!scene) { @@ -133,60 +241,134 @@ std::shared_ptr LoadAnimation(Stream& stream, const AnimationParams& return nullptr; } - aiAnimation* animation = scene->mAnimations[0]; + SceneInfo sceneInfo; + VisitNodes(sceneInfo, scene, scene->mRootNode); + + const aiAnimation* animation = scene->mAnimations[0]; unsigned int maxFrameCount = 0; for (unsigned int i = 0; i < animation->mNumChannels; ++i) { - aiNodeAnim* nodeAnim = animation->mChannels[i]; + const aiNodeAnim* nodeAnim = animation->mChannels[i]; maxFrameCount = std::max({ maxFrameCount, nodeAnim->mNumPositionKeys, nodeAnim->mNumRotationKeys, nodeAnim->mNumScalingKeys }); } - std::shared_ptr anim = std::make_shared(); + std::shared_ptr anim = std::make_shared(); - anim->CreateSkeletal(maxFrameCount, animation->mNumChannels); + anim->CreateSkeletal(maxFrameCount, parameters.skeleton->GetJointCount()); - Sequence sequence; + Nz::Sequence sequence; sequence.firstFrame = 0; sequence.frameCount = maxFrameCount; - sequence.frameRate = animation->mTicksPerSecond; + sequence.frameRate = (animation->mTicksPerSecond != 0.0) ? animation->mTicksPerSecond : 24.0; anim->AddSequence(sequence); - SequenceJoint* sequenceJoints = anim->GetSequenceJoints(); - - Quaternionf rotationQuat = Quaternionf::Identity(); - for (unsigned int i = 0; i < animation->mNumChannels; ++i) { - aiNodeAnim* nodeAnim = animation->mChannels[i]; - for (unsigned int j = 0; j < nodeAnim->mNumPositionKeys; ++j) + const aiNodeAnim* nodeAnim = animation->mChannels[i]; + + std::size_t jointIndex = parameters.skeleton->GetJointIndex(nodeAnim->mNodeName.C_Str()); + if (jointIndex == Nz::Skeleton::InvalidJointIndex) + continue; + + Nz::Vector3f currentPosition = Nz::Vector3f::Zero(); + Nz::Vector3f currentScale = Nz::Vector3f::Unit(); + Nz::Quaternionf currentRotation = Nz::Quaternionf::Identity(); + + unsigned int positionKeyIndex = std::numeric_limits::max(); + unsigned int rotationKeyIndex = std::numeric_limits::max(); + unsigned int scaleKeyIndex = std::numeric_limits::max(); + + for (unsigned int frameIndex = 0; frameIndex < maxFrameCount; ++frameIndex) { - SequenceJoint& sequenceJoint = sequenceJoints[i*animation->mNumChannels + j]; + double frameTime = frameIndex; - aiQuaternion rotation = nodeAnim->mRotationKeys[j].mValue; - aiVector3D position = nodeAnim->mPositionKeys[j].mValue; + for (unsigned int nextPos = positionKeyIndex + 1; nextPos < nodeAnim->mNumPositionKeys; ++nextPos) + { + if (nodeAnim->mPositionKeys[nextPos].mTime > frameTime) + { + if (--nextPos != positionKeyIndex) + { + const aiVector3D& vec = nodeAnim->mPositionKeys[nextPos].mValue; + currentPosition = Nz::Vector3f(vec.x, vec.y, vec.z); + positionKeyIndex = nextPos; + } + break; + } + } - sequenceJoint.position = Vector3f(position.x, position.y, position.z); - sequenceJoint.rotation = Quaternionf(rotation.w, rotation.x, rotation.y, rotation.z); - sequenceJoint.scale.Set(1.f); + for (unsigned int nextRot = rotationKeyIndex + 1; nextRot < nodeAnim->mNumRotationKeys; ++nextRot) + { + if (nodeAnim->mRotationKeys[nextRot].mTime > frameTime) + { + if (--nextRot != rotationKeyIndex) + { + const aiQuaternion& rot = nodeAnim->mRotationKeys[nextRot].mValue; + currentRotation = Nz::Quaternionf(rot.w, rot.x, rot.y, rot.z); + rotationKeyIndex = nextRot; + } + break; + } + } + + // TODO: Scale + + Nz::SequenceJoint* sequenceJoints = anim->GetSequenceJoints(frameIndex); + sequenceJoints[jointIndex].position = currentPosition; + sequenceJoints[jointIndex].rotation = currentRotation; + sequenceJoints[jointIndex].scale = currentScale; } } + Nz::Quaternionf rotationQuat = Nz::Quaternionf::Identity(); + + /*for (unsigned int i = 0; i < animation->mNumChannels; ++i) + { + const aiNodeAnim* nodeAnim = animation->mChannels[i]; + + unsigned int keyCount = std::max({ nodeAnim->mNumPositionKeys, nodeAnim->mNumRotationKeys, nodeAnim->mNumScalingKeys }); + if (nodeAnim->mNumPositionKeys != keyCount && nodeAnim->mNumPositionKeys != 0) + NazaraWarning("expected at least one position key, got 0"); + + if (nodeAnim->mNumRotationKeys != keyCount && nodeAnim->mNumRotationKeys != 0) + NazaraWarning("expected at least one rotation key, got 0"); + + if (nodeAnim->mNumScalingKeys != keyCount && nodeAnim->mNumScalingKeys != 0) + NazaraWarning("expected at least one scaling key, got 0"); + + for (unsigned int j = 0; j < keyCount; ++j) + { + unsigned int posKey = std::min(j, nodeAnim->mNumPositionKeys - 1); + unsigned int rotKey = std::min(j, nodeAnim->mNumRotationKeys - 1); + unsigned int scaleKey = std::min(j, nodeAnim->mNumScalingKeys - 1); + + aiQuaternion rotation = nodeAnim->mRotationKeys[posKey].mValue; + aiVector3D position = nodeAnim->mPositionKeys[rotKey].mValue; + aiVector3D scaling = nodeAnim->mScalingKeys[scaleKey].mValue; + + Nz::SequenceJoint& sequenceJoint = sequenceJoints[i*animation->mNumChannels + j]; + + sequenceJoint.position = Nz::Vector3f(position.x, position.y, position.z); + sequenceJoint.rotation = Nz::Quaternionf(rotation.w, rotation.x, rotation.y, rotation.z); + sequenceJoint.scale = Nz::Vector3f(scaling.x, scaling.y, scaling.z); + } + }*/ + return anim; } -Ternary CheckMesh(Stream& /*stream*/, const MeshParams& parameters) +Nz::Ternary CheckMesh(Nz::Stream& /*stream*/, const Nz::MeshParams& parameters) { bool skip; if (parameters.custom.GetBooleanParameter("SkipAssimpLoader", &skip) && skip) - return Ternary::False; + return Nz::Ternary::False; - return Ternary::Unknown; + return Nz::Ternary::Unknown; } -std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) +std::shared_ptr LoadMesh(Nz::Stream& stream, const Nz::MeshParams& parameters) { std::string streamPath = Nz::PathToString(stream.GetPath()); @@ -199,12 +381,12 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) fileIO.OpenProc = StreamOpener; fileIO.UserData = reinterpret_cast(&userdata); - unsigned int postProcess = aiProcess_CalcTangentSpace | aiProcess_Debone + unsigned int postProcess = aiProcess_CalcTangentSpace /*| aiProcess_Debone*/ | aiProcess_FindInvalidData | aiProcess_FixInfacingNormals | aiProcess_FlipWindingOrder | aiProcess_GenSmoothNormals | aiProcess_GenUVCoords | aiProcess_JoinIdenticalVertices | aiProcess_LimitBoneWeights | aiProcess_MakeLeftHanded - | aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes + /*| aiProcess_OptimizeGraph | aiProcess_OptimizeMeshes*/ | aiProcess_RemoveComponent | aiProcess_RemoveRedundantMaterials | aiProcess_SortByPType | aiProcess_SplitLargeMeshes | aiProcess_TransformUVCoords | aiProcess_Triangulate; @@ -223,20 +405,20 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) int excludedComponents = 0; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Color)) + if (!parameters.vertexDeclaration->HasComponent(Nz::VertexComponent::Color)) excludedComponents |= aiComponent_COLORS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Normal)) + if (!parameters.vertexDeclaration->HasComponent(Nz::VertexComponent::Normal)) excludedComponents |= aiComponent_NORMALS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent::Tangent)) + if (!parameters.vertexDeclaration->HasComponent(Nz::VertexComponent::Tangent)) excludedComponents |= aiComponent_TANGENTS_AND_BITANGENTS; - if (!parameters.vertexDeclaration->HasComponent(VertexComponent::TexCoord)) + if (!parameters.vertexDeclaration->HasComponent(Nz::VertexComponent::TexCoord)) excludedComponents |= aiComponent_TEXCOORDS; aiPropertyStore* properties = aiCreatePropertyStore(); - CallOnExit releaseProperties([&] { aiReleasePropertyStore(properties); }); + Nz::CallOnExit releaseProperties([&] { aiReleasePropertyStore(properties); }); aiSetImportPropertyFloat(properties, AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE, float(smoothingAngle)); aiSetImportPropertyInteger(properties, AI_CONFIG_PP_LBW_MAX_WEIGHTS, 4); @@ -246,7 +428,7 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) aiSetImportPropertyInteger(properties, AI_CONFIG_PP_RVC_FLAGS, excludedComponents); const aiScene* scene = aiImportFileExWithProperties(userdata.originalFilePath, postProcess, &fileIO, properties); - CallOnExit releaseScene([&] { aiReleaseImport(scene); }); + Nz::CallOnExit releaseScene([&] { aiReleaseImport(scene); }); releaseProperties.CallAndReset(); @@ -256,275 +438,244 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) return nullptr; } - std::unordered_set joints; + SceneInfo sceneInfo; + VisitNodes(sceneInfo, scene, scene->mRootNode); - bool animatedMesh = false; - if (parameters.animated) + for (auto& skeletalMesh : sceneInfo.skeletalMeshes) { - for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) - { - aiMesh* currentMesh = scene->mMeshes[meshIndex]; - if (currentMesh->HasBones()) // Inline functions can be safely called - { - animatedMesh = true; - for (unsigned int boneIndex = 0; boneIndex < currentMesh->mNumBones; ++boneIndex) - { - aiBone* bone = currentMesh->mBones[boneIndex]; - joints.insert(bone->mName.C_Str()); - } - } - } + if (!FindSkeletonRoot(sceneInfo, skeletalMesh, scene->mRootNode)) + return nullptr; } - std::shared_ptr mesh = std::make_shared(); - if (animatedMesh) + std::shared_ptr mesh = std::make_shared(); + if (parameters.animated && !sceneInfo.skeletalMeshes.empty()) { - mesh->CreateSkeletal(UInt32(joints.size())); + auto& skeletalMesh = sceneInfo.skeletalMeshes.front(); + auto& skeletalRoot = sceneInfo.nodes[skeletalMesh.skeletonRootIndex]; - Skeleton* skeleton = mesh->GetSkeleton(); + mesh->CreateSkeletal(Nz::SafeCast(skeletalRoot.totalChildrenCount + 1)); - // First, assign names - unsigned int jointIndex = 0; - for (std::string_view jointName : joints) - skeleton->GetJoint(jointIndex++)->SetName(std::string(jointName)); + Nz::Skeleton* skeleton = mesh->GetSkeleton(); - ProcessJoints(scene->mRootNode, skeleton, joints); + std::size_t jointIndex = 0; + ProcessJoints(skeletalMesh, skeleton, skeletalRoot.node, jointIndex); // aiMaterial index in scene => Material index and data in Mesh - std::unordered_map> materials; + std::unordered_map> materials; - for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) + const aiMesh* iMesh = skeletalMesh.mesh; + + unsigned int indexCount = iMesh->mNumFaces * 3; + unsigned int vertexCount = iMesh->mNumVertices; + + // Index buffer + bool largeIndices = (vertexCount > std::numeric_limits::max()); + + std::shared_ptr indexBuffer = std::make_shared((largeIndices) ? Nz::IndexType::U32 : Nz::IndexType::U16, indexCount, parameters.indexBufferFlags, parameters.bufferFactory); + + Nz::IndexMapper indexMapper(*indexBuffer); + Nz::IndexIterator index = indexMapper.begin(); + + for (unsigned int faceIndex = 0; faceIndex < iMesh->mNumFaces; ++faceIndex) { - aiMesh* iMesh = scene->mMeshes[meshIndex]; - if (iMesh->HasBones()) - continue; + const aiFace& face = iMesh->mFaces[faceIndex]; + if (face.mNumIndices != 3) + NazaraWarning("Assimp plugin: This face is not a triangle!"); - unsigned int indexCount = iMesh->mNumFaces * 3; - unsigned int vertexCount = iMesh->mNumVertices; + *index++ = face.mIndices[0]; + *index++ = face.mIndices[1]; + *index++ = face.mIndices[2]; + } + indexMapper.Unmap(); - // Index buffer - bool largeIndices = (vertexCount > std::numeric_limits::max()); + // Make sure the normal/tangent matrix won't rescale our vectors + Nz::Matrix4f normalTangentMatrix = parameters.matrix; + if (normalTangentMatrix.HasScale()) + normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - std::shared_ptr indexBuffer = std::make_shared((largeIndices) ? IndexType::U32 : IndexType::U16, indexCount, parameters.indexBufferFlags, parameters.bufferFactory); + std::shared_ptr vertexBuffer = std::make_shared(Nz::VertexDeclaration::Get(Nz::VertexLayout::XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.vertexBufferFlags, parameters.bufferFactory); - IndexMapper indexMapper(*indexBuffer); - IndexIterator index = indexMapper.begin(); + Nz::VertexMapper vertexMapper(*vertexBuffer); - for (unsigned int faceIndex = 0; faceIndex < iMesh->mNumFaces; ++faceIndex) + // Vertex positions + if (auto posPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Position)) + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { - const aiFace& face = iMesh->mFaces[faceIndex]; - if (face.mNumIndices != 3) - NazaraWarning("Assimp plugin: This face is not a triangle!"); - - *index++ = face.mIndices[0]; - *index++ = face.mIndices[1]; - *index++ = face.mIndices[2]; + aiVector3D position = iMesh->mVertices[vertexIdx]; + *posPtr++ = parameters.matrix * Nz::Vector3f(position.x, position.y, position.z); } - indexMapper.Unmap(); - - // Make sure the normal/tangent matrix won't rescale our vectors - Nz::Matrix4f normalTangentMatrix = parameters.matrix; - if (normalTangentMatrix.HasScale()) - normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - - std::shared_ptr vertexBuffer = std::make_shared(VertexDeclaration::Get(VertexLayout::XYZ_Normal_UV_Tangent_Skinning), vertexCount, parameters.vertexBufferFlags, parameters.bufferFactory); - - VertexMapper vertexMapper(*vertexBuffer); - - // Vertex positions - if (auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D position = iMesh->mVertices[vertexIdx]; - *posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z); - } - } - - // Vertex normals - if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D normal = iMesh->mNormals[vertexIdx]; - *normalPtr++ = normalTangentMatrix.Transform({ normal.x, normal.y, normal.z }, 0.f); - } - } - - // Vertex tangents - bool generateTangents = false; - if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent)) - { - if (iMesh->HasTangentsAndBitangents()) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D tangent = iMesh->mTangents[vertexIdx]; - *tangentPtr++ = normalTangentMatrix.Transform({ tangent.x, tangent.y, tangent.z }, 0.f); - } - } - else - generateTangents = true; - } - - // Vertex UVs - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) - { - if (iMesh->HasTextureCoords(0)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx]; - *uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale; - } - } - else - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *uvPtr++ = Vector2f::Zero(); - } - } - - // Vertex colors - if (auto colorPtr = vertexMapper.GetComponentPtr(VertexComponent::Color)) - { - if (iMesh->HasVertexColors(0)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiColor4D color = iMesh->mColors[0][vertexIdx]; - *colorPtr++ = Color(UInt8(color.r * 255.f), UInt8(color.g * 255.f), UInt8(color.b * 255.f), UInt8(color.a * 255.f)); - } - } - else - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *colorPtr++ = Color::White; - } - } - - auto jointIndicesPtr = vertexMapper.GetComponentPtr(VertexComponent::JointIndices); - auto jointWeightPtr = vertexMapper.GetComponentPtr(VertexComponent::JointWeights); - - if (jointIndicesPtr || jointWeightPtr) - { - std::vector weightIndices(iMesh->mNumVertices, 0); - - for (unsigned int boneIndex = 0; boneIndex < iMesh->mNumBones; ++boneIndex) - { - aiBone* bone = iMesh->mBones[boneIndex]; - for (unsigned int weightIndex = 0; weightIndex < bone->mNumWeights; ++weightIndex) - { - aiVertexWeight& vertexWeight = bone->mWeights[weightIndex]; - - std::size_t vertexWeightIndex = weightIndices[vertexWeight.mVertexId]++; - - if (jointIndicesPtr) - jointIndicesPtr[vertexWeight.mVertexId][vertexWeightIndex] = boneIndex; - - if (jointWeightPtr) - jointWeightPtr[vertexWeight.mVertexId][vertexWeightIndex] = vertexWeight.mWeight; - } - } - } - - // Submesh - std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); - subMesh->SetMaterialIndex(iMesh->mMaterialIndex); - - auto matIt = materials.find(iMesh->mMaterialIndex); - if (matIt == materials.end()) - { - ParameterList matData; - aiMaterial* aiMat = scene->mMaterials[iMesh->mMaterialIndex]; - - auto ConvertColor = [&](const char* aiKey, unsigned int aiType, unsigned int aiIndex, const char* colorKey) - { - aiColor4D color; - if (aiGetMaterialColor(aiMat, aiKey, aiType, aiIndex, &color) == aiReturn_SUCCESS) - { - matData.SetParameter(colorKey, Color(color.r, color.g, color.b, color.a)); - return true; - } - - return false; - }; - - auto ConvertTexture = [&](aiTextureType aiType, const char* textureKey, const char* wrapKey = nullptr) - { - aiString path; - aiTextureMapMode mapMode[3]; - if (aiGetMaterialTexture(aiMat, aiType, 0, &path, nullptr, nullptr, nullptr, nullptr, &mapMode[0], nullptr) == aiReturn_SUCCESS) - { - matData.SetParameter(textureKey, PathToString(stream.GetDirectory() / std::string_view(path.data, path.length))); - - if (wrapKey) - { - SamplerWrap wrap = SamplerWrap::Clamp; - switch (mapMode[0]) - { - case aiTextureMapMode_Clamp: - case aiTextureMapMode_Decal: - wrap = SamplerWrap::Clamp; - break; - - case aiTextureMapMode_Mirror: - wrap = SamplerWrap::MirroredRepeat; - break; - - case aiTextureMapMode_Wrap: - wrap = SamplerWrap::Repeat; - break; - - default: - NazaraWarning("Assimp texture map mode 0x" + NumberToString(mapMode[0], 16) + " not handled"); - break; - } - - matData.SetParameter(wrapKey, static_cast(wrap)); - } - - return true; - } - - return false; - }; - - ConvertColor(AI_MATKEY_COLOR_AMBIENT, MaterialData::AmbientColor); - - if (!ConvertColor(AI_MATKEY_BASE_COLOR, MaterialData::BaseColor)) - ConvertColor(AI_MATKEY_COLOR_DIFFUSE, MaterialData::BaseColor); - - ConvertColor(AI_MATKEY_COLOR_SPECULAR, MaterialData::SpecularColor); - - if (!ConvertTexture(aiTextureType_BASE_COLOR, MaterialData::BaseColorTexturePath, MaterialData::BaseColorWrap)) - ConvertTexture(aiTextureType_DIFFUSE, MaterialData::BaseColorTexturePath, MaterialData::BaseColorWrap); - - ConvertTexture(aiTextureType_DIFFUSE_ROUGHNESS, MaterialData::RoughnessTexturePath, MaterialData::RoughnessWrap); - ConvertTexture(aiTextureType_EMISSIVE, MaterialData::EmissiveTexturePath, MaterialData::EmissiveWrap); - ConvertTexture(aiTextureType_HEIGHT, MaterialData::HeightTexturePath, MaterialData::HeightWrap); - ConvertTexture(aiTextureType_METALNESS, MaterialData::MetallicTexturePath, MaterialData::MetallicWrap); - ConvertTexture(aiTextureType_NORMALS, MaterialData::NormalTexturePath, MaterialData::NormalWrap); - ConvertTexture(aiTextureType_OPACITY, MaterialData::AlphaTexturePath, MaterialData::AlphaWrap); - ConvertTexture(aiTextureType_SPECULAR, MaterialData::SpecularTexturePath, MaterialData::SpecularWrap); - - aiString name; - if (aiGetMaterialString(aiMat, AI_MATKEY_NAME, &name) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::Name, std::string(name.data, name.length)); - - int iValue; - if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::FaceCulling, !iValue); - - matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first; - } - - subMesh->SetMaterialIndex(matIt->first); - - mesh->AddSubMesh(subMesh); } - mesh->SetMaterialCount(std::max(UInt32(materials.size()), 1)); + // Vertex normals + if (auto normalPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Normal)) + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + { + aiVector3D normal = iMesh->mNormals[vertexIdx]; + *normalPtr++ = normalTangentMatrix.Transform({ normal.x, normal.y, normal.z }, 0.f); + } + } + + // Vertex tangents + bool generateTangents = false; + if (auto tangentPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Tangent)) + { + if (iMesh->HasTangentsAndBitangents()) + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + { + aiVector3D tangent = iMesh->mTangents[vertexIdx]; + *tangentPtr++ = normalTangentMatrix.Transform({ tangent.x, tangent.y, tangent.z }, 0.f); + } + } + else + generateTangents = true; + } + + // Vertex UVs + if (auto uvPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::TexCoord)) + { + if (iMesh->HasTextureCoords(0)) + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + { + aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx]; + *uvPtr++ = parameters.texCoordOffset + Nz::Vector2f(uv.x, uv.y) * parameters.texCoordScale; + } + } + else + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + *uvPtr++ = Nz::Vector2f::Zero(); + } + } + + // Vertex colors + if (auto colorPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Color)) + { + if (iMesh->HasVertexColors(0)) + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + { + aiColor4D color = iMesh->mColors[0][vertexIdx]; + *colorPtr++ = Nz::Color(color.r, color.g, color.b, color.a); + } + } + else + { + for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) + *colorPtr++ = Nz::Color::White; + } + } + + auto jointIndicesPtr = vertexMapper.GetComponentPtr(VertexComponent::JointIndices); + auto jointWeightPtr = vertexMapper.GetComponentPtr(VertexComponent::JointWeights); + + if (jointIndicesPtr || jointWeightPtr) + { + std::vector weightIndices(iMesh->mNumVertices, 0); + + for (unsigned int boneIndex = 0; boneIndex < iMesh->mNumBones; ++boneIndex) + { + aiBone* bone = iMesh->mBones[boneIndex]; + for (unsigned int weightIndex = 0; weightIndex < bone->mNumWeights; ++weightIndex) + { + aiVertexWeight& vertexWeight = bone->mWeights[weightIndex]; + + std::size_t vertexWeightIndex = weightIndices[vertexWeight.mVertexId]++; + + if (jointIndicesPtr) + jointIndicesPtr[vertexWeight.mVertexId][vertexWeightIndex] = boneIndex; + + if (jointWeightPtr) + jointWeightPtr[vertexWeight.mVertexId][vertexWeightIndex] = vertexWeight.mWeight; + } + } + } + + // Submesh + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); + subMesh->SetMaterialIndex(iMesh->mMaterialIndex); + + auto matIt = materials.find(iMesh->mMaterialIndex); + if (matIt == materials.end()) + { + Nz::ParameterList matData; + aiMaterial* aiMat = scene->mMaterials[iMesh->mMaterialIndex]; + + auto ConvertColor = [&](const char* aiKey, unsigned int aiType, unsigned int aiIndex, const char* colorKey) + { + aiColor4D color; + if (aiGetMaterialColor(aiMat, aiKey, aiType, aiIndex, &color) == aiReturn_SUCCESS) + { + matData.SetParameter(colorKey, Nz::Color(color.r, color.g, color.b, color.a)); + } + }; + + auto ConvertTexture = [&](aiTextureType aiType, const char* textureKey, const char* wrapKey = nullptr) + { + aiString path; + aiTextureMapMode mapMode[3]; + if (aiGetMaterialTexture(aiMat, aiType, 0, &path, nullptr, nullptr, nullptr, nullptr, &mapMode[0], nullptr) == aiReturn_SUCCESS) + { + matData.SetParameter(textureKey, (stream.GetDirectory() / std::string_view(path.data, path.length)).generic_u8string()); + + if (wrapKey) + { + Nz::SamplerWrap wrap = Nz::SamplerWrap::Clamp; + switch (mapMode[0]) + { + case aiTextureMapMode_Clamp: + case aiTextureMapMode_Decal: + wrap = Nz::SamplerWrap::Clamp; + break; + + case aiTextureMapMode_Mirror: + wrap = Nz::SamplerWrap::MirroredRepeat; + break; + + case aiTextureMapMode_Wrap: + wrap = Nz::SamplerWrap::Repeat; + break; + + default: + NazaraWarning("Assimp texture map mode 0x" + Nz::NumberToString(mapMode[0], 16) + " not handled"); + break; + } + + matData.SetParameter(wrapKey, static_cast(wrap)); + } + } + }; + + ConvertColor(AI_MATKEY_COLOR_AMBIENT, Nz::MaterialData::AmbientColor); + ConvertColor(AI_MATKEY_COLOR_DIFFUSE, Nz::MaterialData::DiffuseColor); + ConvertColor(AI_MATKEY_COLOR_SPECULAR, Nz::MaterialData::SpecularColor); + + ConvertTexture(aiTextureType_DIFFUSE, Nz::MaterialData::DiffuseTexturePath, Nz::MaterialData::DiffuseWrap); + ConvertTexture(aiTextureType_EMISSIVE, Nz::MaterialData::EmissiveTexturePath); + ConvertTexture(aiTextureType_HEIGHT, Nz::MaterialData::HeightTexturePath); + ConvertTexture(aiTextureType_NORMALS, Nz::MaterialData::NormalTexturePath); + ConvertTexture(aiTextureType_OPACITY, Nz::MaterialData::AlphaTexturePath); + ConvertTexture(aiTextureType_SPECULAR, Nz::MaterialData::SpecularTexturePath, Nz::MaterialData::SpecularWrap); + + aiString name; + if (aiGetMaterialString(aiMat, AI_MATKEY_NAME, &name) == aiReturn_SUCCESS) + matData.SetParameter(Nz::MaterialData::Name, std::string(name.data, name.length)); + + int iValue; + if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) + matData.SetParameter(Nz::MaterialData::FaceCulling, !iValue); + + matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(Nz::UInt32(materials.size()), std::move(matData)))).first; + } + + subMesh->SetMaterialIndex(matIt->first); + + mesh->AddSubMesh(subMesh); + + mesh->SetMaterialCount(std::max(Nz::SafeCast(materials.size()), 1)); for (const auto& pair : materials) mesh->SetMaterialData(pair.second.first, pair.second.second); } @@ -533,24 +684,22 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) mesh->CreateStatic(); // aiMaterial index in scene => Material index and data in Mesh - std::unordered_map> materials; + std::unordered_map> materials; for (unsigned int meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { aiMesh* iMesh = scene->mMeshes[meshIndex]; - if (iMesh->HasBones()) - continue; // Don't process skeletal meshes unsigned int indexCount = iMesh->mNumFaces * 3; unsigned int vertexCount = iMesh->mNumVertices; // Index buffer - bool largeIndices = (vertexCount > std::numeric_limits::max()); + bool largeIndices = (vertexCount > std::numeric_limits::max()); - std::shared_ptr indexBuffer = std::make_shared((largeIndices) ? IndexType::U32 : IndexType::U16, indexCount, parameters.indexBufferFlags, parameters.bufferFactory); + std::shared_ptr indexBuffer = std::make_shared((largeIndices) ? Nz::IndexType::U32 : Nz::IndexType::U16, indexCount, parameters.indexBufferFlags, parameters.bufferFactory); - IndexMapper indexMapper(*indexBuffer); - IndexIterator index = indexMapper.begin(); + Nz::IndexMapper indexMapper(*indexBuffer); + Nz::IndexIterator index = indexMapper.begin(); for (unsigned int faceIndex = 0; faceIndex < iMesh->mNumFaces; ++faceIndex) { @@ -559,196 +708,12 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) NazaraWarning("Assimp plugin: This face is not a triangle!"); // Index buffer - bool largeIndices = (vertexCount > std::numeric_limits::max()); + *index++ = face.mIndices[0]; + *index++ = face.mIndices[1]; + *index++ = face.mIndices[2]; - std::shared_ptr indexBuffer = std::make_shared((largeIndices) ? IndexType::U32 : IndexType::U16, indexCount, parameters.indexBufferFlags, parameters.bufferFactory); - - IndexMapper indexMapper(*indexBuffer); - IndexIterator index = indexMapper.begin(); - - for (unsigned int faceIdx = 0; faceIdx < iMesh->mNumFaces; ++faceIdx) - { - aiFace& face = iMesh->mFaces[faceIdx]; - if (face.mNumIndices != 3) - NazaraWarning("Assimp plugin: This face is not a triangle!"); - - *index++ = face.mIndices[0]; - *index++ = face.mIndices[1]; - *index++ = face.mIndices[2]; - } indexMapper.Unmap(); - - // Vertex buffer - - // Make sure the normal/tangent matrix won't rescale our vectors - Nz::Matrix4f normalTangentMatrix = parameters.matrix; - if (normalTangentMatrix.HasScale()) - normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - - std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, vertexCount, parameters.vertexBufferFlags, parameters.bufferFactory); - - VertexMapper vertexMapper(*vertexBuffer); - - // Vertex positions - if (auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D position = iMesh->mVertices[vertexIdx]; - *posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z); - } - } - - // Vertex normals - if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D normal = iMesh->mNormals[vertexIdx]; - *normalPtr++ = normalTangentMatrix.Transform({normal.x, normal.y, normal.z}, 0.f); - } - } - - // Vertex tangents - bool generateTangents = false; - if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent)) - { - if (iMesh->HasTangentsAndBitangents()) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D tangent = iMesh->mTangents[vertexIdx]; - *tangentPtr++ = normalTangentMatrix.Transform({tangent.x, tangent.y, tangent.z}, 0.f); - } - } - else - generateTangents = true; - } - - // Vertex UVs - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) - { - if (iMesh->HasTextureCoords(0)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx]; - *uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale; - } - } - else - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *uvPtr++ = Vector2f::Zero(); - } - } - - // Vertex colors - if (auto colorPtr = vertexMapper.GetComponentPtr(VertexComponent::Color)) - { - if (iMesh->HasVertexColors(0)) - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - { - aiColor4D color = iMesh->mColors[0][vertexIdx]; - *colorPtr++ = Color(color.r, color.g, color.b, color.a); - } - } - else - { - for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *colorPtr++ = Color::White; - } - } - - vertexMapper.Unmap(); - - // Submesh - std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); - subMesh->GenerateAABB(); - subMesh->SetMaterialIndex(iMesh->mMaterialIndex); - - if (generateTangents) - subMesh->GenerateTangents(); - - auto matIt = materials.find(iMesh->mMaterialIndex); - if (matIt == materials.end()) - { - ParameterList matData; - aiMaterial* aiMat = scene->mMaterials[iMesh->mMaterialIndex]; - - auto ConvertColor = [&] (const char* aiKey, unsigned int aiType, unsigned int aiIndex, const char* colorKey) - { - aiColor4D color; - if (aiGetMaterialColor(aiMat, aiKey, aiType, aiIndex, &color) == aiReturn_SUCCESS) - { - matData.SetParameter(colorKey, Color(color.r, color.g, color.b, color.a)); - } - }; - - auto ConvertTexture = [&] (aiTextureType aiType, const char* textureKey, const char* wrapKey = nullptr) - { - aiString path; - aiTextureMapMode mapMode[3]; - if (aiGetMaterialTexture(aiMat, aiType, 0, &path, nullptr, nullptr, nullptr, nullptr, &mapMode[0], nullptr) == aiReturn_SUCCESS) - { - matData.SetParameter(textureKey, Nz::PathToString(stream.GetDirectory() / std::string_view(path.data, path.length))); - - if (wrapKey) - { - SamplerWrap wrap = SamplerWrap::Clamp; - switch (mapMode[0]) - { - case aiTextureMapMode_Clamp: - case aiTextureMapMode_Decal: - wrap = SamplerWrap::Clamp; - break; - - case aiTextureMapMode_Mirror: - wrap = SamplerWrap::MirroredRepeat; - break; - - case aiTextureMapMode_Wrap: - wrap = SamplerWrap::Repeat; - break; - - default: - NazaraWarning("Assimp texture map mode 0x" + NumberToString(mapMode[0], 16) + " not handled"); - break; - } - - matData.SetParameter(wrapKey, static_cast(wrap)); - } - } - }; - - ConvertColor(AI_MATKEY_COLOR_AMBIENT, MaterialData::AmbientColor); - ConvertColor(AI_MATKEY_COLOR_DIFFUSE, MaterialData::BaseColor); - ConvertColor(AI_MATKEY_COLOR_SPECULAR, MaterialData::SpecularColor); - - ConvertTexture(aiTextureType_DIFFUSE, MaterialData::BaseColorTexturePath, MaterialData::BaseColorWrap); - ConvertTexture(aiTextureType_EMISSIVE, MaterialData::EmissiveTexturePath); - ConvertTexture(aiTextureType_HEIGHT, MaterialData::HeightTexturePath); - ConvertTexture(aiTextureType_NORMALS, MaterialData::NormalTexturePath); - ConvertTexture(aiTextureType_OPACITY, MaterialData::AlphaTexturePath); - ConvertTexture(aiTextureType_SPECULAR, MaterialData::SpecularTexturePath, MaterialData::SpecularWrap); - - aiString name; - if (aiGetMaterialString(aiMat, AI_MATKEY_NAME, &name) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::Name, std::string(name.data, name.length)); - - int iValue; - if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::FaceCulling, !iValue); - - matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first; - } - - subMesh->SetMaterialIndex(matIt->first); - - mesh->AddSubMesh(subMesh); } - indexMapper.Unmap(); // Vertex buffer @@ -757,22 +722,22 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) if (normalTangentMatrix.HasScale()) normalTangentMatrix.ApplyScale(1.f / normalTangentMatrix.GetScale()); - std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, vertexCount, parameters.vertexBufferFlags, parameters.bufferFactory); + std::shared_ptr vertexBuffer = std::make_shared(parameters.vertexDeclaration, vertexCount, parameters.vertexBufferFlags, parameters.bufferFactory); - VertexMapper vertexMapper(*vertexBuffer); + Nz::VertexMapper vertexMapper(*vertexBuffer); // Vertex positions - if (auto posPtr = vertexMapper.GetComponentPtr(VertexComponent::Position)) + if (auto posPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Position)) { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { aiVector3D position = iMesh->mVertices[vertexIdx]; - *posPtr++ = parameters.matrix * Vector3f(position.x, position.y, position.z); + *posPtr++ = parameters.matrix * Nz::Vector3f(position.x, position.y, position.z); } } // Vertex normals - if (auto normalPtr = vertexMapper.GetComponentPtr(VertexComponent::Normal)) + if (auto normalPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Normal)) { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { @@ -783,7 +748,7 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) // Vertex tangents bool generateTangents = false; - if (auto tangentPtr = vertexMapper.GetComponentPtr(VertexComponent::Tangent)) + if (auto tangentPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Tangent)) { if (iMesh->HasTangentsAndBitangents()) { @@ -798,45 +763,45 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) } // Vertex UVs - if (auto uvPtr = vertexMapper.GetComponentPtr(VertexComponent::TexCoord)) + if (auto uvPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::TexCoord)) { if (iMesh->HasTextureCoords(0)) { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { aiVector3D uv = iMesh->mTextureCoords[0][vertexIdx]; - *uvPtr++ = parameters.texCoordOffset + Vector2f(uv.x, uv.y) * parameters.texCoordScale; + *uvPtr++ = parameters.texCoordOffset + Nz::Vector2f(uv.x, uv.y) * parameters.texCoordScale; } } else { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *uvPtr++ = Vector2f::Zero(); + *uvPtr++ = Nz::Vector2f::Zero(); } } // Vertex colors - if (auto colorPtr = vertexMapper.GetComponentPtr(VertexComponent::Color)) + if (auto colorPtr = vertexMapper.GetComponentPtr(Nz::VertexComponent::Color)) { if (iMesh->HasVertexColors(0)) { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) { aiColor4D color = iMesh->mColors[0][vertexIdx]; - *colorPtr++ = Color(UInt8(color.r * 255.f), UInt8(color.g * 255.f), UInt8(color.b * 255.f), UInt8(color.a * 255.f)); + *colorPtr++ = Nz::Color(color.r, color.g, color.b, color.a); } } else { for (unsigned int vertexIdx = 0; vertexIdx < vertexCount; ++vertexIdx) - *colorPtr++ = Color::White; + *colorPtr++ = Nz::Color::White; } } vertexMapper.Unmap(); // Submesh - std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); + std::shared_ptr subMesh = std::make_shared(vertexBuffer, indexBuffer); subMesh->GenerateAABB(); subMesh->SetMaterialIndex(iMesh->mMaterialIndex); @@ -846,7 +811,7 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) auto matIt = materials.find(iMesh->mMaterialIndex); if (matIt == materials.end()) { - ParameterList matData; + Nz::ParameterList matData; aiMaterial* aiMat = scene->mMaterials[iMesh->mMaterialIndex]; auto ConvertColor = [&] (const char* aiKey, unsigned int aiType, unsigned int aiIndex, const char* colorKey) @@ -854,7 +819,7 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) aiColor4D color; if (aiGetMaterialColor(aiMat, aiKey, aiType, aiIndex, &color) == aiReturn_SUCCESS) { - matData.SetParameter(colorKey, Color(static_cast(color.r * 255), static_cast(color.g * 255), static_cast(color.b * 255), static_cast(color.a * 255))); + matData.SetParameter(colorKey, Nz::Color(color.r, color.g, color.b, color.a)); } }; @@ -868,24 +833,24 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) if (wrapKey) { - SamplerWrap wrap = SamplerWrap::Clamp; + Nz::SamplerWrap wrap = Nz::SamplerWrap::Clamp; switch (mapMode[0]) { case aiTextureMapMode_Clamp: case aiTextureMapMode_Decal: - wrap = SamplerWrap::Clamp; + wrap = Nz::SamplerWrap::Clamp; break; case aiTextureMapMode_Mirror: - wrap = SamplerWrap::MirroredRepeat; + wrap = Nz::SamplerWrap::MirroredRepeat; break; case aiTextureMapMode_Wrap: - wrap = SamplerWrap::Repeat; + wrap = Nz::SamplerWrap::Repeat; break; default: - NazaraWarning("Assimp texture map mode 0x" + NumberToString(mapMode[0], 16) + " not handled"); + NazaraWarning("Assimp texture map mode 0x" + Nz::NumberToString(mapMode[0], 16) + " not handled"); break; } @@ -894,34 +859,33 @@ std::shared_ptr LoadMesh(Stream& stream, const MeshParams& parameters) } }; - ConvertColor(AI_MATKEY_COLOR_AMBIENT, MaterialData::AmbientColor); - ConvertColor(AI_MATKEY_COLOR_DIFFUSE, MaterialData::DiffuseColor); - ConvertColor(AI_MATKEY_COLOR_SPECULAR, MaterialData::SpecularColor); + ConvertColor(AI_MATKEY_COLOR_AMBIENT, Nz::MaterialData::AmbientColor); + ConvertColor(AI_MATKEY_COLOR_DIFFUSE, Nz::MaterialData::DiffuseColor); + ConvertColor(AI_MATKEY_COLOR_SPECULAR, Nz::MaterialData::SpecularColor); - ConvertTexture(aiTextureType_DIFFUSE, MaterialData::DiffuseTexturePath, MaterialData::DiffuseWrap); - ConvertTexture(aiTextureType_EMISSIVE, MaterialData::EmissiveTexturePath); - ConvertTexture(aiTextureType_HEIGHT, MaterialData::HeightTexturePath); - ConvertTexture(aiTextureType_NORMALS, MaterialData::NormalTexturePath); - ConvertTexture(aiTextureType_OPACITY, MaterialData::AlphaTexturePath); - ConvertTexture(aiTextureType_SPECULAR, MaterialData::SpecularTexturePath, MaterialData::SpecularWrap); + ConvertTexture(aiTextureType_DIFFUSE, Nz::MaterialData::DiffuseTexturePath, Nz::MaterialData::DiffuseWrap); + ConvertTexture(aiTextureType_EMISSIVE, Nz::MaterialData::EmissiveTexturePath); + ConvertTexture(aiTextureType_HEIGHT, Nz::MaterialData::HeightTexturePath); + ConvertTexture(aiTextureType_NORMALS, Nz::MaterialData::NormalTexturePath); + ConvertTexture(aiTextureType_OPACITY, Nz::MaterialData::AlphaTexturePath); + ConvertTexture(aiTextureType_SPECULAR, Nz::MaterialData::SpecularTexturePath, Nz::MaterialData::SpecularWrap); aiString name; if (aiGetMaterialString(aiMat, AI_MATKEY_NAME, &name) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::Name, std::string(name.data, name.length)); + matData.SetParameter(Nz::MaterialData::Name, std::string(name.data, name.length)); int iValue; if (aiGetMaterialInteger(aiMat, AI_MATKEY_TWOSIDED, &iValue) == aiReturn_SUCCESS) - matData.SetParameter(MaterialData::FaceCulling, !iValue); + matData.SetParameter(Nz::MaterialData::FaceCulling, !iValue); - matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(UInt32(materials.size()), std::move(matData)))).first; + matIt = materials.insert(std::make_pair(iMesh->mMaterialIndex, std::make_pair(Nz::UInt32(materials.size()), std::move(matData)))).first; } subMesh->SetMaterialIndex(matIt->first); mesh->AddSubMesh(subMesh); - - mesh->SetMaterialCount(std::max(UInt32(materials.size()), 1)); + mesh->SetMaterialCount(std::max(Nz::UInt32(materials.size()), 1)); for (const auto& pair : materials) mesh->SetMaterialData(pair.second.first, pair.second.second); } diff --git a/src/Nazara/Core/PluginManager.cpp b/src/Nazara/Core/PluginManager.cpp index 9ff6563ca..13092e9fd 100644 --- a/src/Nazara/Core/PluginManager.cpp +++ b/src/Nazara/Core/PluginManager.cpp @@ -211,7 +211,16 @@ namespace Nz { NAZARA_USE_ANONYMOUS_NAMESPACE - Unmount(s_pluginFiles[UnderlyingCast(plugin)]); + std::filesystem::path pluginName = s_pluginFiles[UnderlyingCast(plugin)]; + +#ifdef NAZARA_DEBUG + std::filesystem::path debugPath = pluginName; + debugPath += "-d"; + + Unmount(debugPath); +#endif + + Unmount(pluginName); } /*! @@ -233,7 +242,14 @@ namespace Nz return; } - std::filesystem::path canonicalPath = std::filesystem::canonical(pluginPath); + std::filesystem::path path = pluginPath; + if (path.extension() != NAZARA_DYNLIB_EXTENSION) + path += NAZARA_DYNLIB_EXTENSION; + + if (!std::filesystem::exists(path)) + return; + + std::filesystem::path canonicalPath = std::filesystem::canonical(path); auto it = s_plugins.find(canonicalPath); if (it == s_plugins.end()) { diff --git a/src/Nazara/Utility/Animation.cpp b/src/Nazara/Utility/Animation.cpp index 542a7f877..57c2c3899 100644 --- a/src/Nazara/Utility/Animation.cpp +++ b/src/Nazara/Utility/Animation.cpp @@ -34,6 +34,12 @@ namespace Nz return false; } + if (!skeleton) + { + NazaraError("You must set a valid skeleton to load an animation"); + return false; + } + return true; } diff --git a/src/Nazara/Utility/Skeleton.cpp b/src/Nazara/Utility/Skeleton.cpp index 99dfe6d31..b283701ea 100644 --- a/src/Nazara/Utility/Skeleton.cpp +++ b/src/Nazara/Utility/Skeleton.cpp @@ -140,7 +140,8 @@ namespace Nz UpdateJointMap(); auto it = m_impl->jointMap.find(jointName); - NazaraAssert(it != m_impl->jointMap.end(), "joint not found"); + if (it == m_impl->jointMap.end()) + return InvalidJointIndex; return it->second; }