MD3
- rough support for multi-part player models. SceneCombiner - added support for cross-attachments of nodes in the whole graph git-svn-id: https://assimp.svn.sourceforge.net/svnroot/assimp/trunk@345 67173fc5-114c-0410-ac8e-9d2fd5bffc1fpull/1/head
parent
e6758ce923
commit
d70c092b71
|
@ -153,8 +153,10 @@ struct LoadRequest
|
||||||
, refCnt (1)
|
, refCnt (1)
|
||||||
, scene (NULL)
|
, scene (NULL)
|
||||||
, loaded (false)
|
, loaded (false)
|
||||||
, map (*_map)
|
{
|
||||||
{}
|
if (_map)
|
||||||
|
map = *_map;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string file;
|
const std::string file;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
|
@ -163,8 +165,9 @@ struct LoadRequest
|
||||||
bool loaded;
|
bool loaded;
|
||||||
BatchLoader::PropertyMap map;
|
BatchLoader::PropertyMap map;
|
||||||
|
|
||||||
bool operator== (const std::string& f)
|
bool operator== (const std::string& f) {
|
||||||
{return file == f;}
|
return file == f;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -48,13 +48,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "MaterialSystem.h"
|
#include "MaterialSystem.h"
|
||||||
#include "StringComparison.h"
|
#include "StringComparison.h"
|
||||||
#include "ByteSwap.h"
|
#include "ByteSwap.h"
|
||||||
|
#include "SceneCombiner.h"
|
||||||
|
#include "GenericProperty.h"
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Constructor to be privately used by Importer
|
// Constructor to be privately used by Importer
|
||||||
MD3Importer::MD3Importer()
|
MD3Importer::MD3Importer()
|
||||||
|
: configFrameID (0)
|
||||||
|
, configHandleMP (true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -107,7 +110,7 @@ void MD3Importer::ValidateHeaderOffsets()
|
||||||
void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf)
|
void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf)
|
||||||
{
|
{
|
||||||
// calculate the relative offset of the surface
|
// calculate the relative offset of the surface
|
||||||
int32_t ofs = int32_t((const unsigned char*)pcSurf-this->mBuffer);
|
const int32_t ofs = int32_t((const unsigned char*)pcSurf-this->mBuffer);
|
||||||
|
|
||||||
if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > fileSize ||
|
if (pcSurf->OFS_TRIANGLES + ofs + pcSurf->NUM_TRIANGLES * sizeof(MD3::Triangle) > fileSize ||
|
||||||
pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > fileSize ||
|
pcSurf->OFS_SHADERS + ofs + pcSurf->NUM_SHADER * sizeof(MD3::Shader) > fileSize ||
|
||||||
|
@ -125,6 +128,13 @@ void MD3Importer::ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurf)
|
||||||
if (pcSurf->NUM_FRAMES > AI_MD3_MAX_FRAMES)
|
if (pcSurf->NUM_FRAMES > AI_MD3_MAX_FRAMES)
|
||||||
DefaultLogger::get()->warn("The model contains more frames than Quake 3 supports");
|
DefaultLogger::get()->warn("The model contains more frames than Quake 3 supports");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void MD3Importer::GetExtensionList(std::string& append)
|
||||||
|
{
|
||||||
|
append.append("*.md3");
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Setup configuration properties
|
// Setup configuration properties
|
||||||
void MD3Importer::SetupProperties(const Importer* pImp)
|
void MD3Importer::SetupProperties(const Importer* pImp)
|
||||||
|
@ -136,13 +146,107 @@ void MD3Importer::SetupProperties(const Importer* pImp)
|
||||||
if(0xffffffff == configFrameID) {
|
if(0xffffffff == configFrameID) {
|
||||||
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
configFrameID = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_GLOBAL_KEYFRAME,0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART
|
||||||
|
configHandleMP = (0 != pImp->GetPropertyInteger(AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART,1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Read a multi-part Q3 player model
|
||||||
|
bool MD3Importer::ReadMultipartFile()
|
||||||
|
{
|
||||||
|
std::string::size_type s = mFile.find_last_of('/');
|
||||||
|
if (s == std::string::npos) {
|
||||||
|
s = mFile.find_last_of('\\');
|
||||||
|
}
|
||||||
|
if (s == std::string::npos) {
|
||||||
|
s = 0;
|
||||||
|
}
|
||||||
|
else ++s;
|
||||||
|
std::string filename = mFile.substr(s), path = mFile.substr(0,s);
|
||||||
|
for( std::string::iterator it = filename .begin(); it != filename.end(); ++it)
|
||||||
|
*it = tolower( *it);
|
||||||
|
|
||||||
|
if (filename == "lower.md3" || filename == "upper.md3" || filename == "head.md3"){
|
||||||
|
std::string lower = path + "lower.md3";
|
||||||
|
std::string upper = path + "upper.md3";
|
||||||
|
std::string head = path + "head.md3";
|
||||||
|
|
||||||
|
// ensure we won't try to load ourselves recursively
|
||||||
|
BatchLoader::PropertyMap props;
|
||||||
|
SetGenericProperty( props.ints, AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART, 0, NULL);
|
||||||
|
|
||||||
|
// now read these three files
|
||||||
|
BatchLoader batch(mIOHandler);
|
||||||
|
batch.AddLoadRequest(lower,0,&props);
|
||||||
|
batch.AddLoadRequest(upper,0,&props);
|
||||||
|
batch.AddLoadRequest(head,0,&props);
|
||||||
|
batch.LoadAll();
|
||||||
|
|
||||||
|
// now construct a dummy scene to place these three parts in
|
||||||
|
aiScene* master = new aiScene();
|
||||||
|
aiNode* nd = master->mRootNode = new aiNode();
|
||||||
|
nd->mName.Set("<M3D_Player>");
|
||||||
|
|
||||||
|
// ... and get them. We need all of them.
|
||||||
|
aiScene* scene_lower = batch.GetImport(lower);
|
||||||
|
if (!scene_lower)
|
||||||
|
throw new ImportErrorException("M3D: Failed to read multipart model, lower.md3 fails to load");
|
||||||
|
|
||||||
|
aiScene* scene_upper = batch.GetImport(upper);
|
||||||
|
if (!scene_upper)
|
||||||
|
throw new ImportErrorException("M3D: Failed to read multipart model, upper.md3 fails to load");
|
||||||
|
|
||||||
|
aiScene* scene_head = batch.GetImport(head);
|
||||||
|
if (!scene_head)
|
||||||
|
throw new ImportErrorException("M3D: Failed to read multipart model, head.md3 fails to load");
|
||||||
|
|
||||||
|
// build attachment infos. search for typical Q3 tags
|
||||||
|
std::vector<AttachmentInfo> attach;
|
||||||
|
|
||||||
|
// original root
|
||||||
|
attach.push_back(AttachmentInfo(scene_lower, nd));
|
||||||
|
|
||||||
|
// tag_torso
|
||||||
|
aiNode* tag_torso = scene_lower->mRootNode->FindNode("tag_torso");
|
||||||
|
if (!tag_torso) {
|
||||||
|
throw new ImportErrorException("M3D: Unable to find attachment tag: tag_torso expected");
|
||||||
|
}
|
||||||
|
attach.push_back(AttachmentInfo(scene_upper,tag_torso));
|
||||||
|
|
||||||
|
// tag_head
|
||||||
|
aiNode* tag_head = scene_upper->mRootNode->FindNode("tag_head");
|
||||||
|
if (!tag_head) {
|
||||||
|
throw new ImportErrorException("M3D: Unable to find attachment tag: tag_head expected");
|
||||||
|
}
|
||||||
|
attach.push_back(AttachmentInfo(scene_head,tag_head));
|
||||||
|
|
||||||
|
// and merge the scenes
|
||||||
|
SceneCombiner::MergeScenes(&mScene,master, attach,
|
||||||
|
AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES |
|
||||||
|
AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES |
|
||||||
|
AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Imports the given file into the given scene structure.
|
// Imports the given file into the given scene structure.
|
||||||
void MD3Importer::InternReadFile(
|
void MD3Importer::InternReadFile( const std::string& pFile,
|
||||||
const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
aiScene* pScene, IOSystem* pIOHandler)
|
||||||
{
|
{
|
||||||
|
mFile = pFile;
|
||||||
|
mScene = pScene;
|
||||||
|
mIOHandler = pIOHandler;
|
||||||
|
|
||||||
|
// Load multi-part model file, if necessary
|
||||||
|
if (configHandleMP) {
|
||||||
|
if (ReadMultipartFile())
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||||
|
|
||||||
// Check whether we can read from the file
|
// Check whether we can read from the file
|
||||||
|
@ -301,8 +405,6 @@ void MD3Importer::InternReadFile(
|
||||||
LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,
|
LatLngNormalToVec3(pcVertices[pcTriangles->INDEXES[c]].NORMAL,
|
||||||
(float*)&pcMesh->mNormals[iCurrent]);
|
(float*)&pcMesh->mNormals[iCurrent]);
|
||||||
|
|
||||||
//pcMesh->mNormals[iCurrent].y *= -1.0f;
|
|
||||||
|
|
||||||
// read texture coordinates
|
// read texture coordinates
|
||||||
pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
|
pcMesh->mTextureCoords[0][iCurrent].x = pcUVs[ pcTriangles->INDEXES[c]].U;
|
||||||
pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
|
pcMesh->mTextureCoords[0][iCurrent].y = 1.0f-pcUVs[ pcTriangles->INDEXES[c]].V;
|
||||||
|
@ -355,18 +457,18 @@ void MD3Importer::InternReadFile(
|
||||||
MaterialHelper* pcHelper = new MaterialHelper();
|
MaterialHelper* pcHelper = new MaterialHelper();
|
||||||
|
|
||||||
if (szEndDir2) {
|
if (szEndDir2) {
|
||||||
if (szEndDir2[0]) {
|
|
||||||
aiString szString;
|
aiString szString;
|
||||||
|
if (szEndDir2[0]) {
|
||||||
const size_t iLen = ::strlen(szEndDir2);
|
const size_t iLen = ::strlen(szEndDir2);
|
||||||
::memcpy(szString.data,szEndDir2,iLen);
|
::memcpy(szString.data,szEndDir2,iLen);
|
||||||
szString.data[iLen] = '\0';
|
szString.data[iLen] = '\0';
|
||||||
szString.length = iLen;
|
szString.length = iLen;
|
||||||
|
|
||||||
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DefaultLogger::get()->warn("Texture file name has zero length. Skipping");
|
DefaultLogger::get()->warn("Texture file name has zero length. Using default name");
|
||||||
|
szString.Set("dummy_texture.bmp");
|
||||||
}
|
}
|
||||||
|
pcHelper->AddProperty(&szString,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int iMode = (int)aiShadingMode_Gouraud;
|
int iMode = (int)aiShadingMode_Gouraud;
|
||||||
|
@ -449,8 +551,8 @@ void MD3Importer::InternReadFile(
|
||||||
// copy rest of transformation
|
// copy rest of transformation
|
||||||
for (unsigned int a = 0; a < 3;++a) {
|
for (unsigned int a = 0; a < 3;++a) {
|
||||||
for (unsigned int m = 0; m < 3;++m) {
|
for (unsigned int m = 0; m < 3;++m) {
|
||||||
nd->mTransformation[a][m] = pcTags->orientation[a][m];
|
nd->mTransformation[m][a] = pcTags->orientation[a][m];
|
||||||
AI_SWAP4(nd->mTransformation[a][m]);
|
AI_SWAP4(nd->mTransformation[m][a]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,10 +90,7 @@ protected:
|
||||||
/** Called by Importer::GetExtensionList() for each loaded importer.
|
/** Called by Importer::GetExtensionList() for each loaded importer.
|
||||||
* See BaseImporter::GetExtensionList() for details
|
* See BaseImporter::GetExtensionList() for details
|
||||||
*/
|
*/
|
||||||
void GetExtensionList(std::string& append)
|
void GetExtensionList(std::string& append);
|
||||||
{
|
|
||||||
append.append("*.md3");
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Imports the given file into the given scene structure.
|
/** Imports the given file into the given scene structure.
|
||||||
|
@ -102,18 +99,26 @@ protected:
|
||||||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||||
IOSystem* pIOHandler);
|
IOSystem* pIOHandler);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/** Validate offsets in the header
|
/** Validate offsets in the header
|
||||||
*/
|
*/
|
||||||
void ValidateHeaderOffsets();
|
void ValidateHeaderOffsets();
|
||||||
void ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurfHeader);
|
void ValidateSurfaceHeaderOffsets(const MD3::Surface* pcSurfHeader);
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
/** Read a Q3 multipart file
|
||||||
|
* @return true if multi part has been processed
|
||||||
|
*/
|
||||||
|
bool ReadMultipartFile();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/** Configuration option: frame to be loaded */
|
/** Configuration option: frame to be loaded */
|
||||||
unsigned int configFrameID;
|
unsigned int configFrameID;
|
||||||
|
|
||||||
|
/** Configuration option: process multi-part files */
|
||||||
|
bool configHandleMP;
|
||||||
|
|
||||||
/** Header of the MD3 file */
|
/** Header of the MD3 file */
|
||||||
BE_NCONST MD3::Header* pcHeader;
|
BE_NCONST MD3::Header* pcHeader;
|
||||||
|
|
||||||
|
@ -122,6 +127,15 @@ protected:
|
||||||
|
|
||||||
/** Size of the file, in bytes */
|
/** Size of the file, in bytes */
|
||||||
unsigned int fileSize;
|
unsigned int fileSize;
|
||||||
|
|
||||||
|
/** Current file name */
|
||||||
|
std::string mFile;
|
||||||
|
|
||||||
|
/** Output scene to be filled */
|
||||||
|
aiScene* mScene;
|
||||||
|
|
||||||
|
/** IO system to be used to access the data*/
|
||||||
|
IOSystem* mIOHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
|
@ -129,7 +129,6 @@ inline void PrefixString(aiString& string,const char* prefix, unsigned int len)
|
||||||
void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len)
|
void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len)
|
||||||
{
|
{
|
||||||
ai_assert(NULL != prefix);
|
ai_assert(NULL != prefix);
|
||||||
|
|
||||||
PrefixString(node->mName,prefix,len);
|
PrefixString(node->mName,prefix,len);
|
||||||
|
|
||||||
// Process all children recursively
|
// Process all children recursively
|
||||||
|
@ -177,8 +176,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
|
||||||
master->mRootNode->mName.Set("<MergeRoot>");
|
master->mRootNode->mName.Set("<MergeRoot>");
|
||||||
|
|
||||||
std::vector<AttachmentInfo> srcList (src.size());
|
std::vector<AttachmentInfo> srcList (src.size());
|
||||||
for (unsigned int i = 0; i < srcList.size();++i)
|
for (unsigned int i = 0; i < srcList.size();++i) {
|
||||||
{
|
|
||||||
srcList[i] = AttachmentInfo(src[i],master->mRootNode);
|
srcList[i] = AttachmentInfo(src[i],master->mRootNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +188,6 @@ void SceneCombiner::MergeScenes(aiScene** _dest,std::vector<aiScene*>& src,
|
||||||
void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList)
|
void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInfo>& srcList)
|
||||||
{
|
{
|
||||||
unsigned int cnt;
|
unsigned int cnt;
|
||||||
|
|
||||||
for (cnt = 0; cnt < attach->mNumChildren;++cnt)
|
for (cnt = 0; cnt < attach->mNumChildren;++cnt)
|
||||||
AttachToGraph(attach->mChildren[cnt],srcList);
|
AttachToGraph(attach->mChildren[cnt],srcList);
|
||||||
|
|
||||||
|
@ -198,15 +195,13 @@ void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInf
|
||||||
for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin();
|
for (std::vector<NodeAttachmentInfo>::iterator it = srcList.begin();
|
||||||
it != srcList.end(); ++it)
|
it != srcList.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it).attachToNode == attach)
|
if ((*it).attachToNode == attach && !(*it).resolved)
|
||||||
++cnt;
|
++cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cnt)
|
if (cnt) {
|
||||||
{
|
|
||||||
aiNode** n = new aiNode*[cnt+attach->mNumChildren];
|
aiNode** n = new aiNode*[cnt+attach->mNumChildren];
|
||||||
if (attach->mNumChildren)
|
if (attach->mNumChildren) {
|
||||||
{
|
|
||||||
::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren);
|
::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren);
|
||||||
delete[] attach->mChildren;
|
delete[] attach->mChildren;
|
||||||
}
|
}
|
||||||
|
@ -215,14 +210,15 @@ void SceneCombiner::AttachToGraph (aiNode* attach, std::vector<NodeAttachmentInf
|
||||||
n += attach->mNumChildren;
|
n += attach->mNumChildren;
|
||||||
attach->mNumChildren += cnt;
|
attach->mNumChildren += cnt;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < srcList.size();++i)
|
for (unsigned int i = 0; i < srcList.size();++i) {
|
||||||
{
|
|
||||||
NodeAttachmentInfo& att = srcList[i];
|
NodeAttachmentInfo& att = srcList[i];
|
||||||
if (att.attachToNode == attach)
|
if (att.attachToNode == attach && !att.resolved) {
|
||||||
{
|
|
||||||
*n = att.node;
|
*n = att.node;
|
||||||
(**n).mParent = attach;
|
(**n).mParent = attach;
|
||||||
++n;
|
++n;
|
||||||
|
|
||||||
|
// mark this attachment as resolved
|
||||||
|
att.resolved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,8 +257,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
|
|
||||||
std::vector<SceneHelper> src (srcList.size()+1);
|
std::vector<SceneHelper> src (srcList.size()+1);
|
||||||
src[0].scene = master;
|
src[0].scene = master;
|
||||||
for (unsigned int i = 0; i < srcList.size();++i)
|
for (unsigned int i = 0; i < srcList.size();++i) {
|
||||||
{
|
|
||||||
src[i+1] = SceneHelper( srcList[i].scene );
|
src[i+1] = SceneHelper( srcList[i].scene );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +267,6 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
// this helper array is used as lookup table several times
|
// this helper array is used as lookup table several times
|
||||||
std::vector<unsigned int> offset(src.size());
|
std::vector<unsigned int> offset(src.size());
|
||||||
|
|
||||||
|
|
||||||
// Find duplicate scenes
|
// Find duplicate scenes
|
||||||
for (unsigned int i = 0; i < src.size();++i)
|
for (unsigned int i = 0; i < src.size();++i)
|
||||||
{
|
{
|
||||||
|
@ -316,8 +310,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
{
|
{
|
||||||
SceneHelper* cur = &src[n];
|
SceneHelper* cur = &src[n];
|
||||||
|
|
||||||
if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
|
if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
|
||||||
{
|
|
||||||
dest->mNumTextures += (*cur)->mNumTextures;
|
dest->mNumTextures += (*cur)->mNumTextures;
|
||||||
dest->mNumMaterials += (*cur)->mNumMaterials;
|
dest->mNumMaterials += (*cur)->mNumMaterials;
|
||||||
dest->mNumMeshes += (*cur)->mNumMeshes;
|
dest->mNumMeshes += (*cur)->mNumMeshes;
|
||||||
|
@ -378,11 +371,8 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
|
|
||||||
if ((*cur)->mNumTextures != dest->mNumTextures)
|
if ((*cur)->mNumTextures != dest->mNumTextures)
|
||||||
{
|
{
|
||||||
// We need to update all texture indices of the mesh.
|
// We need to update all texture indices of the mesh. So we need to search for
|
||||||
// So we need to search for a material property like
|
// a material property called '$tex.file'
|
||||||
// that follows the following pattern: "$tex.file.<s>.<n>"
|
|
||||||
// where s is the texture type (i.e. diffuse) and n is
|
|
||||||
// the index of the texture.
|
|
||||||
|
|
||||||
for (unsigned int a = 0; a < (*pip)->mNumProperties;++a)
|
for (unsigned int a = 0; a < (*pip)->mNumProperties;++a)
|
||||||
{
|
{
|
||||||
|
@ -393,8 +383,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
// In this case the property looks like this: *<n>,
|
// In this case the property looks like this: *<n>,
|
||||||
// where n is the index of the texture.
|
// where n is the index of the texture.
|
||||||
aiString& s = *((aiString*)prop->mData);
|
aiString& s = *((aiString*)prop->mData);
|
||||||
if ('*' == s.data[0])
|
if ('*' == s.data[0]) {
|
||||||
{
|
|
||||||
// Offset the index and write it back ..
|
// Offset the index and write it back ..
|
||||||
const unsigned int idx = strtol10(&s.data[1]) + offset[n];
|
const unsigned int idx = strtol10(&s.data[1]) + offset[n];
|
||||||
ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx);
|
ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx);
|
||||||
|
@ -428,8 +417,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
SceneHelper* cur = &src[n];
|
SceneHelper* cur = &src[n];
|
||||||
for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i)
|
for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i)
|
||||||
{
|
{
|
||||||
if (n != duplicates[n])
|
if (n != duplicates[n]) {
|
||||||
{
|
|
||||||
if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
|
if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
|
||||||
Copy(pip, (*cur)->mMeshes[i]);
|
Copy(pip, (*cur)->mMeshes[i]);
|
||||||
|
|
||||||
|
@ -439,7 +427,6 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
|
|
||||||
// update the material index of the mesh
|
// update the material index of the mesh
|
||||||
(*pip)->mMaterialIndex += offset[n];
|
(*pip)->mMaterialIndex += offset[n];
|
||||||
|
|
||||||
++pip;
|
++pip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,8 +468,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
{
|
{
|
||||||
Copy( &node, (*cur)->mRootNode );
|
Copy( &node, (*cur)->mRootNode );
|
||||||
|
|
||||||
if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY)
|
if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) {
|
||||||
{
|
|
||||||
// (note:) they are already 'offseted' by offset[duplicates[n]]
|
// (note:) they are already 'offseted' by offset[duplicates[n]]
|
||||||
OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]);
|
OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]);
|
||||||
}
|
}
|
||||||
|
@ -493,7 +479,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
OffsetNodeMeshIndices(node,offset[n]);
|
OffsetNodeMeshIndices(node,offset[n]);
|
||||||
}
|
}
|
||||||
if (n) // src[0] is the master node
|
if (n) // src[0] is the master node
|
||||||
nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode ));
|
nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n ));
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Copy light sources
|
// Copy light sources
|
||||||
|
@ -508,8 +494,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Copy cameras
|
// Copy cameras
|
||||||
for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras)
|
for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras) {
|
||||||
{
|
|
||||||
if (n != duplicates[n]) // duplicate scene?
|
if (n != duplicates[n]) // duplicate scene?
|
||||||
{
|
{
|
||||||
Copy(ppCameras, (*cur)->mCameras[i]);
|
Copy(ppCameras, (*cur)->mCameras[i]);
|
||||||
|
@ -519,8 +504,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Copy animations
|
// Copy animations
|
||||||
for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims)
|
for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims) {
|
||||||
{
|
|
||||||
if (n != duplicates[n]) // duplicate scene?
|
if (n != duplicates[n]) // duplicate scene?
|
||||||
{
|
{
|
||||||
Copy(ppAnims, (*cur)->mAnimations[i]);
|
Copy(ppAnims, (*cur)->mAnimations[i]);
|
||||||
|
@ -529,8 +513,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( unsigned int n = 1; n < src.size();++n )
|
for ( unsigned int n = 1; n < src.size();++n ) {
|
||||||
{
|
|
||||||
SceneHelper* cur = &src[n];
|
SceneHelper* cur = &src[n];
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// Add prefixes
|
// Add prefixes
|
||||||
|
@ -542,8 +525,7 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
for (unsigned int i = 0; i < (*cur)->mNumCameras;++i)
|
for (unsigned int i = 0; i < (*cur)->mNumCameras;++i)
|
||||||
PrefixString(dest->mCameras[i]->mName,(*cur).id,(*cur).idlen);
|
PrefixString(dest->mCameras[i]->mName,(*cur).id,(*cur).idlen);
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i)
|
for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i) {
|
||||||
{
|
|
||||||
aiAnimation* anim = dest->mAnimations[i];
|
aiAnimation* anim = dest->mAnimations[i];
|
||||||
PrefixString(anim->mName,(*cur).id,(*cur).idlen);
|
PrefixString(anim->mName,(*cur).id,(*cur).idlen);
|
||||||
|
|
||||||
|
@ -551,7 +533,6 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
for (unsigned int a = 0; a < anim->mNumChannels;++a)
|
for (unsigned int a = 0; a < anim->mNumChannels;++a)
|
||||||
PrefixString(anim->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen);
|
PrefixString(anim->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddNodePrefixes(nodes[n-1].node,(*cur).id,(*cur).idlen);
|
AddNodePrefixes(nodes[n-1].node,(*cur).id,(*cur).idlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -560,10 +541,31 @@ void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master,
|
||||||
AttachToGraph ( master, nodes);
|
AttachToGraph ( master, nodes);
|
||||||
dest->mRootNode = master->mRootNode;
|
dest->mRootNode = master->mRootNode;
|
||||||
|
|
||||||
|
// Check whether we succeeded at building the output graph
|
||||||
|
for (std::vector <NodeAttachmentInfo> ::iterator it = nodes.begin();
|
||||||
|
it != nodes.end(); ++it)
|
||||||
|
{
|
||||||
|
if (!(*it).resolved) {
|
||||||
|
if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) {
|
||||||
|
// search for this attachment point in all other imported scenes, too.
|
||||||
|
for ( unsigned int n = 0; n < src.size();++n ) {
|
||||||
|
if (n != (*it).src_idx) {
|
||||||
|
AttachToGraph(src[n].scene,nodes);
|
||||||
|
if ((*it).resolved)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(*it).resolved) {
|
||||||
|
DefaultLogger::get()->error(std::string("SceneCombiner: Failed to resolve attachment ")
|
||||||
|
+ (*it).node->mName.data + " " + (*it).attachToNode->mName.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now delete all input scenes. Make sure duplicate scenes aren't
|
// now delete all input scenes. Make sure duplicate scenes aren't
|
||||||
// deleted more than one time
|
// deleted more than one time
|
||||||
for ( unsigned int n = 0; n < src.size();++n )
|
for ( unsigned int n = 0; n < src.size();++n ) {
|
||||||
{
|
|
||||||
if (n != duplicates[n]) // duplicate scene?
|
if (n != duplicates[n]) // duplicate scene?
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
|
@ -75,33 +75,60 @@ struct NodeAttachmentInfo
|
||||||
NodeAttachmentInfo()
|
NodeAttachmentInfo()
|
||||||
: node (NULL)
|
: node (NULL)
|
||||||
, attachToNode (NULL)
|
, attachToNode (NULL)
|
||||||
|
, resolved (false)
|
||||||
|
, src_idx (0xffffffff)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
NodeAttachmentInfo(aiNode* _scene, aiNode* _attachToNode)
|
NodeAttachmentInfo(aiNode* _scene, aiNode* _attachToNode,size_t idx)
|
||||||
: node (_scene)
|
: node (_scene)
|
||||||
, attachToNode (_attachToNode)
|
, attachToNode (_attachToNode)
|
||||||
|
, resolved (false)
|
||||||
|
, src_idx (idx)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
aiNode* node;
|
aiNode* node;
|
||||||
aiNode* attachToNode;
|
aiNode* attachToNode;
|
||||||
|
bool resolved;
|
||||||
|
size_t src_idx;
|
||||||
};
|
};
|
||||||
|
|
||||||
// generate unique names for all named scene items
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES
|
||||||
|
* Generate unique names for all named scene items
|
||||||
|
*/
|
||||||
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES 0x1
|
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES 0x1
|
||||||
// generate unique names for materials, too
|
|
||||||
|
/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES
|
||||||
|
* Generate unique names for materials, too.
|
||||||
|
* This is not absolutely required to pass the validation.
|
||||||
|
*/
|
||||||
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES 0x2
|
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES 0x2
|
||||||
// use deep copies of duplicate scenes
|
|
||||||
|
/** @def AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY
|
||||||
|
* Use deep copies of duplicate scenes
|
||||||
|
*/
|
||||||
#define AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY 0x4
|
#define AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY 0x4
|
||||||
|
|
||||||
|
/** @def AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS
|
||||||
|
* If attachment nodes are not found in the given master scene,
|
||||||
|
* search the other imported scenes for them in an any order.
|
||||||
|
*/
|
||||||
|
#define AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS 0x8
|
||||||
|
|
||||||
|
/** @def AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY
|
||||||
|
* Can be combined with AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES.
|
||||||
|
* Unique names are generated, but only if this is absolutely
|
||||||
|
* required (if there would be conflicts otherwuse.)
|
||||||
|
*/
|
||||||
|
#define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10
|
||||||
|
|
||||||
|
|
||||||
typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
|
typedef std::pair<aiBone*,unsigned int> BoneSrcIndex;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** \brief Helper data structure for SceneCombiner::MergeBones.
|
/** @brief Helper data structure for SceneCombiner::MergeBones.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
struct BoneWithHash : public std::pair<uint32_t,aiString*>
|
struct BoneWithHash : public std::pair<uint32_t,aiString*> {
|
||||||
{
|
|
||||||
std::vector<BoneSrcIndex> pSrcBones;
|
std::vector<BoneSrcIndex> pSrcBones;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS "imp.ase.reconn"
|
#define AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS "imp.ase.reconn"
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
/** @brief Configures the M3D loader to process multi-part player models.
|
||||||
|
*
|
||||||
|
* These models usually consist of 3 files, lower.md3, upper.md3 and
|
||||||
|
* head.md3. If this property is set to true, Assimp will try to load and
|
||||||
|
* combine all three files if one of them is loaded.
|
||||||
|
* Property type: integer (0: false; !0: true). Default value: true.
|
||||||
|
*/
|
||||||
|
#define AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART "IMPORT_MD3_HANDLE_MULTIPART"
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
/** @brief Configures the LWO loader to load just one layer from the model.
|
/** @brief Configures the LWO loader to load just one layer from the model.
|
||||||
|
|
Loading…
Reference in New Issue