Issue 1117: Smd load multiple animations
Read an animation list from a filepull/2249/head
parent
8c2e975508
commit
19521d222b
|
@ -58,6 +58,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <assimp/DefaultIOSystem.h>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#ifndef _WIN32
|
||||||
|
#define strtok_s strtok_r
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
@ -120,43 +126,17 @@ void SMDImporter::SetupProperties(const Importer* pImp)
|
||||||
if(static_cast<unsigned int>(-1) == configFrameID) {
|
if(static_cast<unsigned int>(-1) == configFrameID) {
|
||||||
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bLoadAnimationList = pImp->GetPropertyBool(AI_CONFIG_IMPORT_SMD_LOAD_ANIMATION_LIST, true);
|
||||||
|
noSkeletonMesh = pImp->GetPropertyBool(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void SMDImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
void SMDImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
|
||||||
|
|
||||||
// Check whether we can read from the file
|
|
||||||
if( file.get() == NULL) {
|
|
||||||
throw DeadlyImportError( "Failed to open SMD/VTA file " + pFile + ".");
|
|
||||||
}
|
|
||||||
|
|
||||||
iFileSize = (unsigned int)file->FileSize();
|
|
||||||
|
|
||||||
// Allocate storage and copy the contents of the file to a memory buffer
|
|
||||||
this->pScene = pScene;
|
this->pScene = pScene;
|
||||||
|
ReadSmd(pFile, pIOHandler);
|
||||||
mBuffer.resize( iFileSize + 1 );
|
|
||||||
TextFileToBuffer(file.get(), mBuffer );
|
|
||||||
|
|
||||||
iSmallestFrame = INT_MAX;
|
|
||||||
bHasUVs = true;
|
|
||||||
iLineNumber = 1;
|
|
||||||
|
|
||||||
// Reserve enough space for ... hm ... 10 textures
|
|
||||||
aszTextures.reserve(10);
|
|
||||||
|
|
||||||
// Reserve enough space for ... hm ... 1000 triangles
|
|
||||||
asTriangles.reserve(1000);
|
|
||||||
|
|
||||||
// Reserve enough space for ... hm ... 20 bones
|
|
||||||
asBones.reserve(20);
|
|
||||||
|
|
||||||
|
|
||||||
// parse the file ...
|
|
||||||
ParseFile();
|
|
||||||
|
|
||||||
// If there are no triangles it seems to be an animation SMD,
|
// If there are no triangles it seems to be an animation SMD,
|
||||||
// containing only the animation skeleton.
|
// containing only the animation skeleton.
|
||||||
|
@ -203,13 +183,13 @@ void SMDImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
||||||
CreateOutputMaterials();
|
CreateOutputMaterials();
|
||||||
}
|
}
|
||||||
|
|
||||||
// build the output animation
|
|
||||||
CreateOutputAnimations();
|
|
||||||
|
|
||||||
// build output nodes (bones are added as empty dummy nodes)
|
// build output nodes (bones are added as empty dummy nodes)
|
||||||
CreateOutputNodes();
|
CreateOutputNodes();
|
||||||
|
|
||||||
if (pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE)
|
// build the output animation
|
||||||
|
CreateOutputAnimations(pFile, pIOHandler);
|
||||||
|
|
||||||
|
if ((pScene->mFlags & AI_SCENE_FLAGS_INCOMPLETE) && !noSkeletonMesh)
|
||||||
{
|
{
|
||||||
SkeletonMeshBuilder skeleton(pScene);
|
SkeletonMeshBuilder skeleton(pScene);
|
||||||
}
|
}
|
||||||
|
@ -521,12 +501,35 @@ void SMDImporter::CreateOutputNodes()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// create output animations
|
// create output animations
|
||||||
void SMDImporter::CreateOutputAnimations()
|
void SMDImporter::CreateOutputAnimations(const std::string &pFile, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
pScene->mNumAnimations = 1;
|
std::vector<std::tuple<std::string, std::string>> animFileList;
|
||||||
pScene->mAnimations = new aiAnimation*[1];
|
|
||||||
aiAnimation*& anim = pScene->mAnimations[0] = new aiAnimation();
|
|
||||||
|
|
||||||
|
if (bLoadAnimationList) GetAnimationFileList(pFile, pIOHandler, animFileList);
|
||||||
|
int animCount = animFileList.size() + 1;
|
||||||
|
pScene->mNumAnimations = 1;
|
||||||
|
pScene->mAnimations = new aiAnimation*[animCount];
|
||||||
|
memset(pScene->mAnimations, 0, sizeof(aiAnimation*)*animCount);
|
||||||
|
CreateOutputAnimation(0, "");
|
||||||
|
|
||||||
|
for (auto &animFile : animFileList)
|
||||||
|
{
|
||||||
|
ReadSmd(std::get<1>(animFile), pIOHandler);
|
||||||
|
if (asBones.empty()) continue;
|
||||||
|
|
||||||
|
FixTimeValues();
|
||||||
|
CreateOutputAnimation(pScene->mNumAnimations++, std::get<0>(animFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMDImporter::CreateOutputAnimation(int index, const std::string &name)
|
||||||
|
{
|
||||||
|
aiAnimation*& anim = pScene->mAnimations[index] = new aiAnimation();
|
||||||
|
|
||||||
|
if (name.length())
|
||||||
|
{
|
||||||
|
anim->mName.Set(name.c_str());
|
||||||
|
}
|
||||||
anim->mDuration = dLengthOfAnim;
|
anim->mDuration = dLengthOfAnim;
|
||||||
anim->mNumChannels = asBones.size();
|
anim->mNumChannels = asBones.size();
|
||||||
anim->mTicksPerSecond = 25.0; // FIXME: is this correct?
|
anim->mTicksPerSecond = 25.0; // FIXME: is this correct?
|
||||||
|
@ -537,14 +540,14 @@ void SMDImporter::CreateOutputAnimations()
|
||||||
unsigned int a = 0;
|
unsigned int a = 0;
|
||||||
for (std::vector<SMD::Bone>::const_iterator
|
for (std::vector<SMD::Bone>::const_iterator
|
||||||
i = asBones.begin();
|
i = asBones.begin();
|
||||||
i != asBones.end();++i)
|
i != asBones.end(); ++i)
|
||||||
{
|
{
|
||||||
aiNodeAnim* p = pp[a] = new aiNodeAnim();
|
aiNodeAnim* p = pp[a] = new aiNodeAnim();
|
||||||
|
|
||||||
// copy the name of the bone
|
// copy the name of the bone
|
||||||
p->mNodeName.Set( i->mName);
|
p->mNodeName.Set(i->mName);
|
||||||
|
|
||||||
p->mNumRotationKeys = (unsigned int) (*i).sAnim.asKeys.size();
|
p->mNumRotationKeys = (unsigned int)(*i).sAnim.asKeys.size();
|
||||||
if (p->mNumRotationKeys)
|
if (p->mNumRotationKeys)
|
||||||
{
|
{
|
||||||
p->mNumPositionKeys = p->mNumRotationKeys;
|
p->mNumPositionKeys = p->mNumRotationKeys;
|
||||||
|
@ -559,7 +562,7 @@ void SMDImporter::CreateOutputAnimations()
|
||||||
|
|
||||||
// compute the rotation quaternion from the euler angles
|
// compute the rotation quaternion from the euler angles
|
||||||
// aiQuaternion: The order of the parameters is yzx?
|
// aiQuaternion: The order of the parameters is yzx?
|
||||||
pRotKeys->mValue = aiQuaternion( (*qq).vRot.y, (*qq).vRot.z, (*qq).vRot.x );
|
pRotKeys->mValue = aiQuaternion((*qq).vRot.y, (*qq).vRot.z, (*qq).vRot.x);
|
||||||
pVecKeys->mValue = (*qq).vPos;
|
pVecKeys->mValue = (*qq).vPos;
|
||||||
|
|
||||||
++pVecKeys; ++pRotKeys;
|
++pVecKeys; ++pRotKeys;
|
||||||
|
@ -571,6 +574,56 @@ void SMDImporter::CreateOutputAnimations()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMDImporter::GetAnimationFileList(const std::string &pFile, IOSystem* pIOHandler, std::vector<std::tuple<std::string, std::string>>& outList)
|
||||||
|
{
|
||||||
|
auto base = DefaultIOSystem::absolutePath(pFile);
|
||||||
|
auto name = DefaultIOSystem::completeBaseName(pFile);
|
||||||
|
auto path = base + "/" + name + "_animation.txt";
|
||||||
|
|
||||||
|
std::unique_ptr<IOStream> file(pIOHandler->Open(path.c_str(), "rb"));
|
||||||
|
if (file.get() == NULL) return;
|
||||||
|
|
||||||
|
// Allocate storage and copy the contents of the file to a memory buffer
|
||||||
|
std::vector<char> buf;
|
||||||
|
size_t fileSize = file->FileSize();
|
||||||
|
buf.resize(fileSize + 1);
|
||||||
|
TextFileToBuffer(file.get(), buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
*_animation.txt format:
|
||||||
|
name path
|
||||||
|
idle idle.smd
|
||||||
|
jump anim/jump.smd
|
||||||
|
walk.smd
|
||||||
|
...
|
||||||
|
*/
|
||||||
|
std::string animName, animPath;
|
||||||
|
char *tok1, *tok2;
|
||||||
|
char *context1, *context2;
|
||||||
|
|
||||||
|
tok1 = strtok_s(&buf[0], "\r\n", &context1);
|
||||||
|
while (tok1 != NULL) {
|
||||||
|
tok2 = strtok_s(tok1, " \t", &context2);
|
||||||
|
if (tok2)
|
||||||
|
{
|
||||||
|
char *p = tok2;
|
||||||
|
tok2 = strtok_s(NULL, " \t", &context2);
|
||||||
|
if (tok2)
|
||||||
|
{
|
||||||
|
animPath = tok2;
|
||||||
|
animName = p;
|
||||||
|
}
|
||||||
|
else // No name
|
||||||
|
{
|
||||||
|
animPath = p;
|
||||||
|
animName = DefaultIOSystem::completeBaseName(animPath);
|
||||||
|
}
|
||||||
|
outList.push_back(std::make_tuple(animName, base + "/" + animPath));
|
||||||
|
}
|
||||||
|
tok1 = strtok_s(NULL, "\r\n", &context1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void SMDImporter::ComputeAbsoluteBoneTransformations()
|
void SMDImporter::ComputeAbsoluteBoneTransformations()
|
||||||
{
|
{
|
||||||
|
@ -735,6 +788,42 @@ void SMDImporter::ParseFile()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMDImporter::ReadSmd(const std::string &pFile, IOSystem* pIOHandler)
|
||||||
|
{
|
||||||
|
std::unique_ptr<IOStream> file(pIOHandler->Open(pFile, "rb"));
|
||||||
|
|
||||||
|
// Check whether we can read from the file
|
||||||
|
if (file.get() == NULL) {
|
||||||
|
throw DeadlyImportError("Failed to open SMD/VTA file " + pFile + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
iFileSize = (unsigned int)file->FileSize();
|
||||||
|
|
||||||
|
// Allocate storage and copy the contents of the file to a memory buffer
|
||||||
|
mBuffer.resize(iFileSize + 1);
|
||||||
|
TextFileToBuffer(file.get(), mBuffer);
|
||||||
|
|
||||||
|
iSmallestFrame = INT_MAX;
|
||||||
|
bHasUVs = true;
|
||||||
|
iLineNumber = 1;
|
||||||
|
|
||||||
|
// Reserve enough space for ... hm ... 10 textures
|
||||||
|
aszTextures.reserve(10);
|
||||||
|
|
||||||
|
// Reserve enough space for ... hm ... 1000 triangles
|
||||||
|
asTriangles.reserve(1000);
|
||||||
|
|
||||||
|
// Reserve enough space for ... hm ... 20 bones
|
||||||
|
asBones.reserve(20);
|
||||||
|
|
||||||
|
aszTextures.clear();
|
||||||
|
asTriangles.clear();
|
||||||
|
asBones.clear();
|
||||||
|
|
||||||
|
// parse the file ...
|
||||||
|
ParseFile();
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
unsigned int SMDImporter::GetTextureIndex(const std::string& filename)
|
unsigned int SMDImporter::GetTextureIndex(const std::string& filename)
|
||||||
{
|
{
|
||||||
|
|
|
@ -219,6 +219,7 @@ protected:
|
||||||
/** Parse the SMD file and create the output scene
|
/** Parse the SMD file and create the output scene
|
||||||
*/
|
*/
|
||||||
void ParseFile();
|
void ParseFile();
|
||||||
|
void ReadSmd(const std::string &pFile, IOSystem* pIOHandler);
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Parse the triangles section of the SMD file
|
/** Parse the triangles section of the SMD file
|
||||||
|
@ -344,7 +345,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
void CreateOutputMeshes();
|
void CreateOutputMeshes();
|
||||||
void CreateOutputNodes();
|
void CreateOutputNodes();
|
||||||
void CreateOutputAnimations();
|
void CreateOutputAnimations(const std::string &pFile, IOSystem* pIOHandler);
|
||||||
|
void CreateOutputAnimation(int index, const std::string &name);
|
||||||
|
void GetAnimationFileList(const std::string &pFile, IOSystem* pIOHandler, std::vector<std::tuple<std::string, std::string>>& outList);
|
||||||
void CreateOutputMaterials();
|
void CreateOutputMaterials();
|
||||||
|
|
||||||
|
|
||||||
|
@ -413,6 +416,8 @@ private:
|
||||||
*/
|
*/
|
||||||
unsigned int iLineNumber;
|
unsigned int iLineNumber;
|
||||||
|
|
||||||
|
bool bLoadAnimationList = true;
|
||||||
|
bool noSkeletonMesh = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -673,6 +673,12 @@ enum aiComponent
|
||||||
#define AI_CONFIG_IMPORT_SMD_KEYFRAME "IMPORT_SMD_KEYFRAME"
|
#define AI_CONFIG_IMPORT_SMD_KEYFRAME "IMPORT_SMD_KEYFRAME"
|
||||||
#define AI_CONFIG_IMPORT_UNREAL_KEYFRAME "IMPORT_UNREAL_KEYFRAME"
|
#define AI_CONFIG_IMPORT_UNREAL_KEYFRAME "IMPORT_UNREAL_KEYFRAME"
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** Smd load multiple animations
|
||||||
|
*
|
||||||
|
* Property type: bool. Default value: true.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_IMPORT_SMD_LOAD_ANIMATION_LIST "IMPORT_SMD_LOAD_ANIMATION_LIST"
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** @brief Configures the AC loader to collect all surfaces which have the
|
/** @brief Configures the AC loader to collect all surfaces which have the
|
||||||
|
|
Loading…
Reference in New Issue