Issue 1117: Smd load multiple animations

Read an animation list from a file
pull/2249/head
wxyu 2018-11-30 09:47:29 +08:00
parent 8c2e975508
commit 19521d222b
3 changed files with 145 additions and 45 deletions

View File

@ -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)
{ {

View File

@ -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

View File

@ -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