Big skeletal animation update

Added MeshInfos demo
Added MD5Mesh/MD5Anim loader support
Added Node class
Fixed ResourceParams not being exported
Added support for skeletal animation
(Animation/Mesh/Joint/SkeletalMesh/Skeleton)
Meshes are now only stored with VertexStruct_XYZ_Normal_UV_Tangent type
Moved Sequence declaration to Sequence.hpp

-Animation:
Renamed Create to Create[Keyframe|Skeletal]

-AxisAlignedBox:
Added Contains method
Added GetCorner method
Added GetCube method
Added Transform method

-Cube/Rect:
Added GetPosition method
Added GetSize method
(Almost) Fixed ExtendTo method
Fixed GetCenter method

-File:
Added GetDirectory static function
Added GetPath method
Renamed GetDirectoryPath method to GetDirectory

-Math module:
Fixed constructor/methods taking a non-const array
GetNormal/Normalize methods now takes an optionnal integer pointer
(returning length)
Made all classes default constructor trivial
Inverse, MakeIdentity, MakeZero, Normalize, Set methods now returns
reference to object

-Matrix4:
Modified methods to avoid copies
Removed COW (Too much overhead)
Removed Concatenate[Affine] static function

-Mesh:
Renamed Create to Create[Keyframe|Skeletal|Static]
Renamed Skin to Material

-MeshParams:
No longer takes declaration argument
Renamed loadAnimations to animated
Storage default to BufferStorage_Hardware if supported and
BufferStorage_Software otherwise

-OpenGL:
Added glGetBooleanv function
Added glIsEnabled function

-Quaternion:
Added ComputeW method
Added Conjugate method

-Renderer:
Added IsEnabled static function
Fixed GetLineWidth function not being static
Removed SetVertexDeclaration

-RenderWindow:
Made CopyTo[Image|Texture] method constant

-Resource
Fixed RemoveResourceListener crash

-ResourceLoader:
Loaders are now used in a LIFO context

-Stream:
Renamed GetLine method to ReadLine

-String:
Fixed Simplified

-Utility module
Added configuration define for strict resource parsing

-VertexBuffer
Now takes a VertexDeclaration pointer

-VertexDeclaration
No longer throw an error when getting a non-existing element


Former-commit-id: f7358c1231d6af48b799d2f24f077a001e16785b
This commit is contained in:
Lynix
2012-11-21 17:23:50 +01:00
parent 84f73f2b6a
commit 70ef422950
99 changed files with 6270 additions and 1983 deletions

View File

@@ -0,0 +1,384 @@
// Copyright (C) 2012 Jérôme Leclercq
// This file is part of the "Nazara Engine - Utility module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Skeleton.hpp>
#include <Nazara/Utility/AxisAlignedBox.hpp>
#include <map>
#include <Nazara/Utility/Debug.hpp>
struct NzSkeletonImpl
{
std::map<NzString, unsigned int> jointMap;
std::vector<NzJoint> joints;
NzAxisAlignedBox aabb;
bool jointMapUpdated = false;
};
NzSkeleton::NzSkeleton(const NzSkeleton& skeleton)
{
if (skeleton.m_impl)
{
m_impl = new NzSkeletonImpl;
m_impl->jointMap = skeleton.m_impl->jointMap;
m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated;
m_impl->joints = skeleton.m_impl->joints;
}
else
m_impl = nullptr;
}
NzSkeleton::~NzSkeleton()
{
Destroy();
}
bool NzSkeleton::Create(unsigned int jointCount)
{
#if NAZARA_UTILITY_SAFE
if (jointCount == 0)
{
NazaraError("Joint count must be over 0");
return false;
}
#endif
m_impl = new NzSkeletonImpl;
m_impl->joints.resize(jointCount, NzJoint(this));
return true;
}
void NzSkeleton::Destroy()
{
if (m_impl)
{
delete m_impl;
m_impl = nullptr;
}
}
const NzAxisAlignedBox& NzSkeleton::GetAABB() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return NzAxisAlignedBox::Null;
}
#endif
if (m_impl->aabb.IsNull())
{
for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
m_impl->aabb.ExtendTo(m_impl->joints[i].GetDerivedTranslation());
}
return m_impl->aabb;
}
NzJoint* NzSkeleton::GetJoint(const NzString& jointName)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
#endif
if (!m_impl->jointMapUpdated)
UpdateJointMap();
auto it = m_impl->jointMap.find(jointName);
#if NAZARA_UTILITY_SAFE
if (it == m_impl->jointMap.end())
{
NazaraError("Joint not found");
return nullptr;
}
#endif
// Invalidation de l'AABB
m_impl->aabb.SetNull();
return &m_impl->joints[it->second];
}
NzJoint* NzSkeleton::GetJoint(unsigned int index)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
if (index >= m_impl->joints.size())
{
NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
return nullptr;
}
#endif
// Invalidation de l'AABB
m_impl->aabb.SetNull();
return &m_impl->joints[index];
}
const NzJoint* NzSkeleton::GetJoint(const NzString& jointName) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
#endif
if (!m_impl->jointMapUpdated)
UpdateJointMap();
auto it = m_impl->jointMap.find(jointName);
#if NAZARA_UTILITY_SAFE
if (it == m_impl->jointMap.end())
{
NazaraError("Joint not found");
return nullptr;
}
#endif
return &m_impl->joints[it->second];
}
const NzJoint* NzSkeleton::GetJoint(unsigned int index) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
if (index >= m_impl->joints.size())
{
NazaraError("Joint index out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
return nullptr;
}
#endif
return &m_impl->joints[index];
}
NzJoint* NzSkeleton::GetJoints()
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
#endif
return &m_impl->joints[0];
}
const NzJoint* NzSkeleton::GetJoints() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return nullptr;
}
#endif
return &m_impl->joints[0];
}
unsigned int NzSkeleton::GetJointCount() const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return 0;
}
#endif
return m_impl->joints.size();
}
int NzSkeleton::GetJointIndex(const NzString& jointName) const
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return -1;
}
#endif
if (!m_impl->jointMapUpdated)
UpdateJointMap();
auto it = m_impl->jointMap.find(jointName);
#if NAZARA_UTILITY_SAFE
if (it == m_impl->jointMap.end())
{
NazaraError("Joint not found");
return -1;
}
#endif
return it->second;
}
void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return;
}
if (!skeletonA.IsValid())
{
NazaraError("Skeleton A is invalid");
return;
}
if (!skeletonB.IsValid())
{
NazaraError("Skeleton B is invalid");
return;
}
if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
{
NazaraError("Skeletons must have the same joint count");
return;
}
#endif
NzJoint* jointsA = &skeletonA.m_impl->joints[0];
NzJoint* jointsB = &skeletonB.m_impl->joints[0];
for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
m_impl->joints[i].Interpolate(jointsA[i], jointsB[i], interpolation);
}
void NzSkeleton::Interpolate(const NzSkeleton& skeletonA, const NzSkeleton& skeletonB, float interpolation, unsigned int* indices, unsigned int indiceCount)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Skeleton not created");
return;
}
if (!skeletonA.IsValid())
{
NazaraError("Skeleton A is invalid");
return;
}
if (!skeletonB.IsValid())
{
NazaraError("Skeleton B is invalid");
return;
}
if (skeletonA.GetJointCount() != skeletonB.GetJointCount() || m_impl->joints.size() != skeletonA.GetJointCount())
{
NazaraError("Skeletons must have the same joint count");
return;
}
#endif
NzJoint* jointsA = &skeletonA.m_impl->joints[0];
NzJoint* jointsB = &skeletonB.m_impl->joints[0];
for (unsigned int i = 0; i < indiceCount; ++i)
{
unsigned int index = indices[i];
#if NAZARA_UTILITY_SAFE
if (index >= m_impl->joints.size())
{
NazaraError("Index #" + NzString::Number(i) + " out of range (" + NzString::Number(index) + " >= " + NzString::Number(m_impl->joints.size()) + ')');
return;
}
#endif
m_impl->joints[index].Interpolate(jointsA[index], jointsB[index], interpolation);
}
}
bool NzSkeleton::IsValid() const
{
return m_impl != nullptr;
}
NzSkeleton& NzSkeleton::operator=(const NzSkeleton& skeleton)
{
Destroy();
if (skeleton.m_impl)
{
m_impl = new NzSkeletonImpl;
m_impl->jointMap = skeleton.m_impl->jointMap;
m_impl->jointMapUpdated = skeleton.m_impl->jointMapUpdated;
m_impl->joints = skeleton.m_impl->joints;
}
return *this;
}
void NzSkeleton::InvalidateJointMap()
{
#ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Invalid skeleton");
return;
}
#endif
m_impl->jointMapUpdated = false;
}
void NzSkeleton::UpdateJointMap() const
{
#ifdef NAZARA_DEBUG
if (!m_impl)
{
NazaraError("Invalid skeleton");
return;
}
#endif
m_impl->jointMap.clear();
for (unsigned int i = 0; i < m_impl->joints.size(); ++i)
{
NzString name = m_impl->joints[i].GetName();
if (!name.IsEmpty())
{
#if NAZARA_UTILITY_SAFE
auto it = m_impl->jointMap.find(name);
if (it != m_impl->jointMap.end())
{
NazaraWarning("Joint name \"" + name + "\" is already present in joint map for joint #" + NzString::Number(it->second));
continue;
}
#endif
m_impl->jointMap[name] = i;
}
}
m_impl->jointMapUpdated = true;
}