nuclear@0: /* nuclear@0: Open Asset Import Library (assimp) nuclear@0: ---------------------------------------------------------------------- nuclear@0: nuclear@0: Copyright (c) 2006-2012, assimp team nuclear@0: All rights reserved. nuclear@0: nuclear@0: Redistribution and use of this software in source and binary forms, nuclear@0: with or without modification, are permitted provided that the nuclear@0: following conditions are met: nuclear@0: nuclear@0: * Redistributions of source code must retain the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer. nuclear@0: nuclear@0: * Redistributions in binary form must reproduce the above nuclear@0: copyright notice, this list of conditions and the nuclear@0: following disclaimer in the documentation and/or other nuclear@0: materials provided with the distribution. nuclear@0: nuclear@0: * Neither the name of the assimp team, nor the names of its nuclear@0: contributors may be used to endorse or promote products nuclear@0: derived from this software without specific prior nuclear@0: written permission of the assimp team. nuclear@0: nuclear@0: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS nuclear@0: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT nuclear@0: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR nuclear@0: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT nuclear@0: OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, nuclear@0: SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT nuclear@0: LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, nuclear@0: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY nuclear@0: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT nuclear@0: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE nuclear@0: OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. nuclear@0: nuclear@0: ---------------------------------------------------------------------- nuclear@0: */ nuclear@0: nuclear@0: nuclear@0: // ---------------------------------------------------------------------------- nuclear@0: /** @file Implements Assimp::SceneCombiner. This is a smart utility nuclear@0: * class that combines multiple scenes, meshes, ... into one. Currently nuclear@0: * these utilities are used by the IRR and LWS loaders and the nuclear@0: * OptimizeGraph step. nuclear@0: */ nuclear@0: // ---------------------------------------------------------------------------- nuclear@0: #include "AssimpPCH.h" nuclear@0: #include "SceneCombiner.h" nuclear@0: #include "fast_atof.h" nuclear@0: #include "Hash.h" nuclear@0: #include "time.h" nuclear@0: nuclear@0: namespace Assimp { nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Add a prefix to a string nuclear@0: inline void PrefixString(aiString& string,const char* prefix, unsigned int len) nuclear@0: { nuclear@0: // If the string is already prefixed, we won't prefix it a second time nuclear@0: if (string.length >= 1 && string.data[0] == '$') nuclear@0: return; nuclear@0: nuclear@0: if (len+string.length>=MAXLEN-1) { nuclear@0: DefaultLogger::get()->debug("Can't add an unique prefix because the string is too long"); nuclear@0: ai_assert(false); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // Add the prefix nuclear@0: ::memmove(string.data+len,string.data,string.length+1); nuclear@0: ::memcpy (string.data, prefix, len); nuclear@0: nuclear@0: // And update the string's length nuclear@0: string.length += len; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Add node identifiers to a hashing set nuclear@0: void SceneCombiner::AddNodeHashes(aiNode* node, std::set& hashes) nuclear@0: { nuclear@0: // Add node name to hashing set if it is non-empty - empty nodes are allowed nuclear@0: // and they can't have any anims assigned so its absolutely safe to duplicate them. nuclear@0: if (node->mName.length) { nuclear@0: hashes.insert( SuperFastHash(node->mName.data,node->mName.length) ); nuclear@0: } nuclear@0: nuclear@0: // Process all children recursively nuclear@0: for (unsigned int i = 0; i < node->mNumChildren;++i) nuclear@0: AddNodeHashes(node->mChildren[i],hashes); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Add a name prefix to all nodes in a hierarchy nuclear@0: void SceneCombiner::AddNodePrefixes(aiNode* node, const char* prefix, unsigned int len) nuclear@0: { nuclear@0: ai_assert(NULL != prefix); nuclear@0: PrefixString(node->mName,prefix,len); nuclear@0: nuclear@0: // Process all children recursively nuclear@0: for (unsigned int i = 0; i < node->mNumChildren;++i) nuclear@0: AddNodePrefixes(node->mChildren[i],prefix,len); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Search for matching names nuclear@0: bool SceneCombiner::FindNameMatch(const aiString& name, std::vector& input, unsigned int cur) nuclear@0: { nuclear@0: const unsigned int hash = SuperFastHash(name.data, name.length); nuclear@0: nuclear@0: // Check whether we find a positive match in one of the given sets nuclear@0: for (unsigned int i = 0; i < input.size(); ++i) { nuclear@0: nuclear@0: if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { nuclear@0: return true; nuclear@0: } nuclear@0: } nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Add a name prefix to all nodes in a hierarchy if a hash match is found nuclear@0: void SceneCombiner::AddNodePrefixesChecked(aiNode* node, const char* prefix, unsigned int len, nuclear@0: std::vector& input, unsigned int cur) nuclear@0: { nuclear@0: ai_assert(NULL != prefix); nuclear@0: const unsigned int hash = SuperFastHash(node->mName.data,node->mName.length); nuclear@0: nuclear@0: // Check whether we find a positive match in one of the given sets nuclear@0: for (unsigned int i = 0; i < input.size(); ++i) { nuclear@0: nuclear@0: if (cur != i && input[i].hashes.find(hash) != input[i].hashes.end()) { nuclear@0: PrefixString(node->mName,prefix,len); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Process all children recursively nuclear@0: for (unsigned int i = 0; i < node->mNumChildren;++i) nuclear@0: AddNodePrefixesChecked(node->mChildren[i],prefix,len,input,cur); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Add an offset to all mesh indices in a node graph nuclear@0: void SceneCombiner::OffsetNodeMeshIndices (aiNode* node, unsigned int offset) nuclear@0: { nuclear@0: for (unsigned int i = 0; i < node->mNumMeshes;++i) nuclear@0: node->mMeshes[i] += offset; nuclear@0: nuclear@0: for (unsigned int i = 0; i < node->mNumChildren;++i) nuclear@0: OffsetNodeMeshIndices(node->mChildren[i],offset); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Merges two scenes. Currently only used by the LWS loader. nuclear@0: void SceneCombiner::MergeScenes(aiScene** _dest,std::vector& src, nuclear@0: unsigned int flags) nuclear@0: { nuclear@0: ai_assert(NULL != _dest); nuclear@0: nuclear@0: // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it nuclear@0: if (src.empty()) nuclear@0: { nuclear@0: if (*_dest) nuclear@0: { nuclear@0: (*_dest)->~aiScene(); nuclear@0: SceneCombiner::CopySceneFlat(_dest,src[0]); nuclear@0: } nuclear@0: else *_dest = src[0]; nuclear@0: return; nuclear@0: } nuclear@0: if (*_dest)(*_dest)->~aiScene(); nuclear@0: else *_dest = new aiScene(); nuclear@0: nuclear@0: // Create a dummy scene to serve as master for the others nuclear@0: aiScene* master = new aiScene(); nuclear@0: master->mRootNode = new aiNode(); nuclear@0: master->mRootNode->mName.Set(""); nuclear@0: nuclear@0: std::vector srcList (src.size()); nuclear@0: for (unsigned int i = 0; i < srcList.size();++i) { nuclear@0: srcList[i] = AttachmentInfo(src[i],master->mRootNode); nuclear@0: } nuclear@0: nuclear@0: // 'master' will be deleted afterwards nuclear@0: MergeScenes (_dest, master, srcList, flags); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::AttachToGraph (aiNode* attach, std::vector& srcList) nuclear@0: { nuclear@0: unsigned int cnt; nuclear@0: for (cnt = 0; cnt < attach->mNumChildren;++cnt) nuclear@0: AttachToGraph(attach->mChildren[cnt],srcList); nuclear@0: nuclear@0: cnt = 0; nuclear@0: for (std::vector::iterator it = srcList.begin(); nuclear@0: it != srcList.end(); ++it) nuclear@0: { nuclear@0: if ((*it).attachToNode == attach && !(*it).resolved) nuclear@0: ++cnt; nuclear@0: } nuclear@0: nuclear@0: if (cnt) { nuclear@0: aiNode** n = new aiNode*[cnt+attach->mNumChildren]; nuclear@0: if (attach->mNumChildren) { nuclear@0: ::memcpy(n,attach->mChildren,sizeof(void*)*attach->mNumChildren); nuclear@0: delete[] attach->mChildren; nuclear@0: } nuclear@0: attach->mChildren = n; nuclear@0: nuclear@0: n += attach->mNumChildren; nuclear@0: attach->mNumChildren += cnt; nuclear@0: nuclear@0: for (unsigned int i = 0; i < srcList.size();++i) { nuclear@0: NodeAttachmentInfo& att = srcList[i]; nuclear@0: if (att.attachToNode == attach && !att.resolved) { nuclear@0: *n = att.node; nuclear@0: (**n).mParent = attach; nuclear@0: ++n; nuclear@0: nuclear@0: // mark this attachment as resolved nuclear@0: att.resolved = true; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::AttachToGraph ( aiScene* master, nuclear@0: std::vector& src) nuclear@0: { nuclear@0: ai_assert(NULL != master); nuclear@0: AttachToGraph(master->mRootNode,src); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::MergeScenes(aiScene** _dest, aiScene* master, nuclear@0: std::vector& srcList, nuclear@0: unsigned int flags) nuclear@0: { nuclear@0: ai_assert(NULL != _dest); nuclear@0: nuclear@0: // if _dest points to NULL allocate a new scene. Otherwise clear the old and reuse it nuclear@0: if (srcList.empty()) { nuclear@0: if (*_dest) { nuclear@0: SceneCombiner::CopySceneFlat(_dest,master); nuclear@0: } nuclear@0: else *_dest = master; nuclear@0: return; nuclear@0: } nuclear@0: if (*_dest) { nuclear@0: (*_dest)->~aiScene(); nuclear@0: new (*_dest) aiScene(); nuclear@0: } nuclear@0: else *_dest = new aiScene(); nuclear@0: nuclear@0: aiScene* dest = *_dest; nuclear@0: nuclear@0: std::vector src (srcList.size()+1); nuclear@0: src[0].scene = master; nuclear@0: for (unsigned int i = 0; i < srcList.size();++i) { nuclear@0: src[i+1] = SceneHelper( srcList[i].scene ); nuclear@0: } nuclear@0: nuclear@0: // this helper array specifies which scenes are duplicates of others nuclear@0: std::vector duplicates(src.size(),UINT_MAX); nuclear@0: nuclear@0: // this helper array is used as lookup table several times nuclear@0: std::vector offset(src.size()); nuclear@0: nuclear@0: // Find duplicate scenes nuclear@0: for (unsigned int i = 0; i < src.size();++i) { nuclear@0: if (duplicates[i] != i && duplicates[i] != UINT_MAX) { nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: duplicates[i] = i; nuclear@0: for ( unsigned int a = i+1; a < src.size(); ++a) { nuclear@0: if (src[i].scene == src[a].scene) { nuclear@0: duplicates[a] = i; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Generate unique names for all named stuff? nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) nuclear@0: { nuclear@0: #if 0 nuclear@0: // Construct a proper random number generator nuclear@0: boost::mt19937 rng( ); nuclear@0: boost::uniform_int<> dist(1u,1 << 24u); nuclear@0: boost::variate_generator > rndGen(rng, dist); nuclear@0: #endif nuclear@0: for (unsigned int i = 1; i < src.size();++i) nuclear@0: { nuclear@0: //if (i != duplicates[i]) nuclear@0: //{ nuclear@0: // // duplicate scenes share the same UID nuclear@0: // ::strcpy( src[i].id, src[duplicates[i]].id ); nuclear@0: // src[i].idlen = src[duplicates[i]].idlen; nuclear@0: nuclear@0: // continue; nuclear@0: //} nuclear@0: nuclear@0: src[i].idlen = ::sprintf(src[i].id,"$%.6X$_",i); nuclear@0: nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: nuclear@0: // Compute hashes for all identifiers in this scene and store them nuclear@0: // in a sorted table (for convenience I'm using std::set). We hash nuclear@0: // just the node and animation channel names, all identifiers except nuclear@0: // the material names should be caught by doing this. nuclear@0: AddNodeHashes(src[i]->mRootNode,src[i].hashes); nuclear@0: nuclear@0: for (unsigned int a = 0; a < src[i]->mNumAnimations;++a) { nuclear@0: aiAnimation* anim = src[i]->mAnimations[a]; nuclear@0: src[i].hashes.insert(SuperFastHash(anim->mName.data,anim->mName.length)); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: unsigned int cnt; nuclear@0: nuclear@0: // First find out how large the respective output arrays must be nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) nuclear@0: { nuclear@0: SceneHelper* cur = &src[n]; nuclear@0: nuclear@0: if (n == duplicates[n] || flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { nuclear@0: dest->mNumTextures += (*cur)->mNumTextures; nuclear@0: dest->mNumMaterials += (*cur)->mNumMaterials; nuclear@0: dest->mNumMeshes += (*cur)->mNumMeshes; nuclear@0: } nuclear@0: nuclear@0: dest->mNumLights += (*cur)->mNumLights; nuclear@0: dest->mNumCameras += (*cur)->mNumCameras; nuclear@0: dest->mNumAnimations += (*cur)->mNumAnimations; nuclear@0: nuclear@0: // Combine the flags of all scenes nuclear@0: // We need to process them flag-by-flag here to get correct results nuclear@0: // dest->mFlags ; //|= (*cur)->mFlags; nuclear@0: if ((*cur)->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { nuclear@0: dest->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // generate the output texture list + an offset table for all texture indices nuclear@0: if (dest->mNumTextures) nuclear@0: { nuclear@0: aiTexture** pip = dest->mTextures = new aiTexture*[dest->mNumMaterials]; nuclear@0: cnt = 0; nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) nuclear@0: { nuclear@0: SceneHelper* cur = &src[n]; nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumTextures;++i) nuclear@0: { nuclear@0: if (n != duplicates[n]) nuclear@0: { nuclear@0: if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) nuclear@0: Copy(pip,(*cur)->mTextures[i]); nuclear@0: nuclear@0: else continue; nuclear@0: } nuclear@0: else *pip = (*cur)->mTextures[i]; nuclear@0: ++pip; nuclear@0: } nuclear@0: nuclear@0: offset[n] = cnt; nuclear@0: cnt = (unsigned int)(pip - dest->mTextures); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // generate the output material list + an offset table for all material indices nuclear@0: if (dest->mNumMaterials) nuclear@0: { nuclear@0: aiMaterial** pip = dest->mMaterials = new aiMaterial*[dest->mNumMaterials]; nuclear@0: cnt = 0; nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) { nuclear@0: SceneHelper* cur = &src[n]; nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumMaterials;++i) nuclear@0: { nuclear@0: if (n != duplicates[n]) nuclear@0: { nuclear@0: if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) nuclear@0: Copy(pip,(*cur)->mMaterials[i]); nuclear@0: nuclear@0: else continue; nuclear@0: } nuclear@0: else *pip = (*cur)->mMaterials[i]; nuclear@0: nuclear@0: if ((*cur)->mNumTextures != dest->mNumTextures) { nuclear@0: // We need to update all texture indices of the mesh. So we need to search for nuclear@0: // a material property called '$tex.file' nuclear@0: nuclear@0: for (unsigned int a = 0; a < (*pip)->mNumProperties;++a) nuclear@0: { nuclear@0: aiMaterialProperty* prop = (*pip)->mProperties[a]; nuclear@0: if (!strncmp(prop->mKey.data,"$tex.file",9)) nuclear@0: { nuclear@0: // Check whether this texture is an embedded texture. nuclear@0: // In this case the property looks like this: *, nuclear@0: // where n is the index of the texture. nuclear@0: aiString& s = *((aiString*)prop->mData); nuclear@0: if ('*' == s.data[0]) { nuclear@0: // Offset the index and write it back .. nuclear@0: const unsigned int idx = strtoul10(&s.data[1]) + offset[n]; nuclear@0: ASSIMP_itoa10(&s.data[1],sizeof(s.data)-1,idx); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Need to generate new, unique material names? nuclear@0: else if (!::strcmp( prop->mKey.data,"$mat.name" ) && flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) nuclear@0: { nuclear@0: aiString* pcSrc = (aiString*) prop->mData; nuclear@0: PrefixString(*pcSrc, (*cur).id, (*cur).idlen); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: ++pip; nuclear@0: } nuclear@0: nuclear@0: offset[n] = cnt; nuclear@0: cnt = (unsigned int)(pip - dest->mMaterials); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // generate the output mesh list + again an offset table for all mesh indices nuclear@0: if (dest->mNumMeshes) nuclear@0: { nuclear@0: aiMesh** pip = dest->mMeshes = new aiMesh*[dest->mNumMeshes]; nuclear@0: cnt = 0; nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) nuclear@0: { nuclear@0: SceneHelper* cur = &src[n]; nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) nuclear@0: { nuclear@0: if (n != duplicates[n]) { nuclear@0: if ( flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) nuclear@0: Copy(pip, (*cur)->mMeshes[i]); nuclear@0: nuclear@0: else continue; nuclear@0: } nuclear@0: else *pip = (*cur)->mMeshes[i]; nuclear@0: nuclear@0: // update the material index of the mesh nuclear@0: (*pip)->mMaterialIndex += offset[n]; nuclear@0: ++pip; nuclear@0: } nuclear@0: nuclear@0: // reuse the offset array - store now the mesh offset in it nuclear@0: offset[n] = cnt; nuclear@0: cnt = (unsigned int)(pip - dest->mMeshes); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: std::vector nodes; nuclear@0: nodes.reserve(srcList.size()); nuclear@0: nuclear@0: // ---------------------------------------------------------------------------- nuclear@0: // Now generate the output node graph. We need to make those nuclear@0: // names in the graph that are referenced by anims or lights nuclear@0: // or cameras unique. So we add a prefix to them ... $_ nuclear@0: // We could also use a counter, but using a random value allows us to nuclear@0: // use just one prefix if we are joining multiple scene hierarchies recursively. nuclear@0: // Chances are quite good we don't collide, so we try that ... nuclear@0: // ---------------------------------------------------------------------------- nuclear@0: nuclear@0: // Allocate space for light sources, cameras and animations nuclear@0: aiLight** ppLights = dest->mLights = (dest->mNumLights nuclear@0: ? new aiLight*[dest->mNumLights] : NULL); nuclear@0: nuclear@0: aiCamera** ppCameras = dest->mCameras = (dest->mNumCameras nuclear@0: ? new aiCamera*[dest->mNumCameras] : NULL); nuclear@0: nuclear@0: aiAnimation** ppAnims = dest->mAnimations = (dest->mNumAnimations nuclear@0: ? new aiAnimation*[dest->mNumAnimations] : NULL); nuclear@0: nuclear@0: for ( int n = src.size()-1; n >= 0 ;--n ) /* !!! important !!! */ nuclear@0: { nuclear@0: SceneHelper* cur = &src[n]; nuclear@0: aiNode* node; nuclear@0: nuclear@0: // To offset or not to offset, this is the question nuclear@0: if (n != (int)duplicates[n]) nuclear@0: { nuclear@0: // Get full scenegraph copy nuclear@0: Copy( &node, (*cur)->mRootNode ); nuclear@0: OffsetNodeMeshIndices(node,offset[duplicates[n]]); nuclear@0: nuclear@0: if (flags & AI_INT_MERGE_SCENE_DUPLICATES_DEEP_CPY) { nuclear@0: // (note:) they are already 'offseted' by offset[duplicates[n]] nuclear@0: OffsetNodeMeshIndices(node,offset[n] - offset[duplicates[n]]); nuclear@0: } nuclear@0: } nuclear@0: else // if (n == duplicates[n]) nuclear@0: { nuclear@0: node = (*cur)->mRootNode; nuclear@0: OffsetNodeMeshIndices(node,offset[n]); nuclear@0: } nuclear@0: if (n) // src[0] is the master node nuclear@0: nodes.push_back(NodeAttachmentInfo( node,srcList[n-1].attachToNode,n )); nuclear@0: nuclear@0: // add name prefixes? nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { nuclear@0: nuclear@0: // or the whole scenegraph nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: AddNodePrefixesChecked(node,(*cur).id,(*cur).idlen,src,n); nuclear@0: } nuclear@0: else AddNodePrefixes(node,(*cur).id,(*cur).idlen); nuclear@0: nuclear@0: // meshes nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumMeshes;++i) { nuclear@0: aiMesh* mesh = (*cur)->mMeshes[i]; nuclear@0: nuclear@0: // rename all bones nuclear@0: for (unsigned int a = 0; a < mesh->mNumBones;++a) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: if (!FindNameMatch(mesh->mBones[a]->mName,src,n)) nuclear@0: continue; nuclear@0: } nuclear@0: PrefixString(mesh->mBones[a]->mName,(*cur).id,(*cur).idlen); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // -------------------------------------------------------------------- nuclear@0: // Copy light sources nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumLights;++i,++ppLights) nuclear@0: { nuclear@0: if (n != (int)duplicates[n]) // duplicate scene? nuclear@0: { nuclear@0: Copy(ppLights, (*cur)->mLights[i]); nuclear@0: } nuclear@0: else *ppLights = (*cur)->mLights[i]; nuclear@0: nuclear@0: nuclear@0: // Add name prefixes? nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: if (!FindNameMatch((*ppLights)->mName,src,n)) nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: PrefixString((*ppLights)->mName,(*cur).id,(*cur).idlen); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // -------------------------------------------------------------------- nuclear@0: // Copy cameras nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumCameras;++i,++ppCameras) { nuclear@0: if (n != (int)duplicates[n]) // duplicate scene? nuclear@0: { nuclear@0: Copy(ppCameras, (*cur)->mCameras[i]); nuclear@0: } nuclear@0: else *ppCameras = (*cur)->mCameras[i]; nuclear@0: nuclear@0: // Add name prefixes? nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: if (!FindNameMatch((*ppCameras)->mName,src,n)) nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: PrefixString((*ppCameras)->mName,(*cur).id,(*cur).idlen); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // -------------------------------------------------------------------- nuclear@0: // Copy animations nuclear@0: for (unsigned int i = 0; i < (*cur)->mNumAnimations;++i,++ppAnims) { nuclear@0: if (n != (int)duplicates[n]) // duplicate scene? nuclear@0: { nuclear@0: Copy(ppAnims, (*cur)->mAnimations[i]); nuclear@0: } nuclear@0: else *ppAnims = (*cur)->mAnimations[i]; nuclear@0: nuclear@0: // Add name prefixes? nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: if (!FindNameMatch((*ppAnims)->mName,src,n)) nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: PrefixString((*ppAnims)->mName,(*cur).id,(*cur).idlen); nuclear@0: nuclear@0: // don't forget to update all node animation channels nuclear@0: for (unsigned int a = 0; a < (*ppAnims)->mNumChannels;++a) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY) { nuclear@0: if (!FindNameMatch((*ppAnims)->mChannels[a]->mNodeName,src,n)) nuclear@0: continue; nuclear@0: } nuclear@0: nuclear@0: PrefixString((*ppAnims)->mChannels[a]->mNodeName,(*cur).id,(*cur).idlen); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // Now build the output graph nuclear@0: AttachToGraph ( master, nodes); nuclear@0: dest->mRootNode = master->mRootNode; nuclear@0: nuclear@0: // Check whether we succeeded at building the output graph nuclear@0: for (std::vector ::iterator it = nodes.begin(); nuclear@0: it != nodes.end(); ++it) nuclear@0: { nuclear@0: if (!(*it).resolved) { nuclear@0: if (flags & AI_INT_MERGE_SCENE_RESOLVE_CROSS_ATTACHMENTS) { nuclear@0: // search for this attachment point in all other imported scenes, too. nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) { nuclear@0: if (n != (*it).src_idx) { nuclear@0: AttachToGraph(src[n].scene,nodes); nuclear@0: if ((*it).resolved) nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: if (!(*it).resolved) { nuclear@0: DefaultLogger::get()->error(std::string("SceneCombiner: Failed to resolve attachment ") nuclear@0: + (*it).node->mName.data + " " + (*it).attachToNode->mName.data); nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // now delete all input scenes. Make sure duplicate scenes aren't nuclear@0: // deleted more than one time nuclear@0: for ( unsigned int n = 0; n < src.size();++n ) { nuclear@0: if (n != duplicates[n]) // duplicate scene? nuclear@0: continue; nuclear@0: nuclear@0: aiScene* deleteMe = src[n].scene; nuclear@0: nuclear@0: // We need to delete the arrays before the destructor is called - nuclear@0: // we are reusing the array members nuclear@0: delete[] deleteMe->mMeshes; deleteMe->mMeshes = NULL; nuclear@0: delete[] deleteMe->mCameras; deleteMe->mCameras = NULL; nuclear@0: delete[] deleteMe->mLights; deleteMe->mLights = NULL; nuclear@0: delete[] deleteMe->mMaterials; deleteMe->mMaterials = NULL; nuclear@0: delete[] deleteMe->mAnimations; deleteMe->mAnimations = NULL; nuclear@0: nuclear@0: deleteMe->mRootNode = NULL; nuclear@0: nuclear@0: // Now we can safely delete the scene nuclear@0: delete deleteMe; nuclear@0: } nuclear@0: nuclear@0: // Check flags nuclear@0: if (!dest->mNumMeshes || !dest->mNumMaterials) { nuclear@0: dest->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; nuclear@0: } nuclear@0: nuclear@0: // We're finished nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Build a list of unique bones nuclear@0: void SceneCombiner::BuildUniqueBoneList(std::list& asBones, nuclear@0: std::vector::const_iterator it, nuclear@0: std::vector::const_iterator end) nuclear@0: { nuclear@0: unsigned int iOffset = 0; nuclear@0: for (; it != end;++it) { nuclear@0: for (unsigned int l = 0; l < (*it)->mNumBones;++l) { nuclear@0: aiBone* p = (*it)->mBones[l]; nuclear@0: uint32_t itml = SuperFastHash(p->mName.data,(unsigned int)p->mName.length); nuclear@0: nuclear@0: std::list::iterator it2 = asBones.begin(); nuclear@0: std::list::iterator end2 = asBones.end(); nuclear@0: nuclear@0: for (;it2 != end2;++it2) { nuclear@0: if ((*it2).first == itml) { nuclear@0: (*it2).pSrcBones.push_back(BoneSrcIndex(p,iOffset)); nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: if (end2 == it2) { nuclear@0: // need to begin a new bone entry nuclear@0: asBones.push_back(BoneWithHash()); nuclear@0: BoneWithHash& btz = asBones.back(); nuclear@0: nuclear@0: // setup members nuclear@0: btz.first = itml; nuclear@0: btz.second = &p->mName; nuclear@0: btz.pSrcBones.push_back(BoneSrcIndex(p,iOffset)); nuclear@0: } nuclear@0: } nuclear@0: iOffset += (*it)->mNumVertices; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Merge a list of bones nuclear@0: void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator it, nuclear@0: std::vector::const_iterator end) nuclear@0: { nuclear@0: ai_assert(NULL != out && !out->mNumBones); nuclear@0: nuclear@0: // find we need to build an unique list of all bones. nuclear@0: // we work with hashes to make the comparisons MUCH faster, nuclear@0: // at least if we have many bones. nuclear@0: std::list asBones; nuclear@0: BuildUniqueBoneList(asBones, it,end); nuclear@0: nuclear@0: // now create the output bones nuclear@0: out->mNumBones = 0; nuclear@0: out->mBones = new aiBone*[asBones.size()]; nuclear@0: nuclear@0: for (std::list::const_iterator it = asBones.begin(),end = asBones.end(); it != end;++it) { nuclear@0: // Allocate a bone and setup it's name nuclear@0: aiBone* pc = out->mBones[out->mNumBones++] = new aiBone(); nuclear@0: pc->mName = aiString( *((*it).second )); nuclear@0: nuclear@0: std::vector< BoneSrcIndex >::const_iterator wend = (*it).pSrcBones.end(); nuclear@0: nuclear@0: // Loop through all bones to be joined for this bone nuclear@0: for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit) { nuclear@0: pc->mNumWeights += (*wmit).first->mNumWeights; nuclear@0: nuclear@0: // NOTE: different offset matrices for bones with equal names nuclear@0: // are - at the moment - not handled correctly. nuclear@0: if (wmit != (*it).pSrcBones.begin() && pc->mOffsetMatrix != (*wmit).first->mOffsetMatrix) { nuclear@0: DefaultLogger::get()->warn("Bones with equal names but different offset matrices can't be joined at the moment"); nuclear@0: continue; nuclear@0: } nuclear@0: pc->mOffsetMatrix = (*wmit).first->mOffsetMatrix; nuclear@0: } nuclear@0: nuclear@0: // Allocate the vertex weight array nuclear@0: aiVertexWeight* avw = pc->mWeights = new aiVertexWeight[pc->mNumWeights]; nuclear@0: nuclear@0: // And copy the final weights - adjust the vertex IDs by the nuclear@0: // face index offset of the coresponding mesh. nuclear@0: for (std::vector< BoneSrcIndex >::const_iterator wmit = (*it).pSrcBones.begin(); wmit != wend; ++wmit) { nuclear@0: aiBone* pip = (*wmit).first; nuclear@0: for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) { nuclear@0: const aiVertexWeight& vfi = pip->mWeights[mp]; nuclear@0: avw->mWeight = vfi.mWeight; nuclear@0: avw->mVertexId = vfi.mVertexId + (*wmit).second; nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: // Merge a list of meshes nuclear@0: void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, nuclear@0: std::vector::const_iterator begin, nuclear@0: std::vector::const_iterator end) nuclear@0: { nuclear@0: ai_assert(NULL != _out); nuclear@0: nuclear@0: if (begin == end) { nuclear@0: *_out = NULL; // no meshes ... nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: // Allocate the output mesh nuclear@0: aiMesh* out = *_out = new aiMesh(); nuclear@0: out->mMaterialIndex = (*begin)->mMaterialIndex; nuclear@0: nuclear@0: // Find out how much output storage we'll need nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: out->mNumVertices += (*it)->mNumVertices; nuclear@0: out->mNumFaces += (*it)->mNumFaces; nuclear@0: out->mNumBones += (*it)->mNumBones; nuclear@0: nuclear@0: // combine primitive type flags nuclear@0: out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; nuclear@0: } nuclear@0: nuclear@0: if (out->mNumVertices) { nuclear@0: aiVector3D* pv2; nuclear@0: nuclear@0: // copy vertex positions nuclear@0: if ((**begin).HasPositions()) { nuclear@0: nuclear@0: pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: if ((*it)->mVertices) { nuclear@0: ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D)); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("JoinMeshes: Positions expected but input mesh contains no positions"); nuclear@0: pv2 += (*it)->mNumVertices; nuclear@0: } nuclear@0: } nuclear@0: // copy normals nuclear@0: if ((**begin).HasNormals()) { nuclear@0: nuclear@0: pv2 = out->mNormals = new aiVector3D[out->mNumVertices]; nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: if ((*it)->mNormals) { nuclear@0: ::memcpy(pv2,(*it)->mNormals,(*it)->mNumVertices*sizeof(aiVector3D)); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("JoinMeshes: Normals expected but input mesh contains no normals"); nuclear@0: pv2 += (*it)->mNumVertices; nuclear@0: } nuclear@0: } nuclear@0: // copy tangents and bitangents nuclear@0: if ((**begin).HasTangentsAndBitangents()) { nuclear@0: nuclear@0: pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; nuclear@0: aiVector3D* pv2b = out->mBitangents = new aiVector3D[out->mNumVertices]; nuclear@0: nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: if ((*it)->mTangents) { nuclear@0: ::memcpy(pv2, (*it)->mTangents, (*it)->mNumVertices*sizeof(aiVector3D)); nuclear@0: ::memcpy(pv2b,(*it)->mBitangents,(*it)->mNumVertices*sizeof(aiVector3D)); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("JoinMeshes: Tangents expected but input mesh contains no tangents"); nuclear@0: pv2 += (*it)->mNumVertices; nuclear@0: pv2b += (*it)->mNumVertices; nuclear@0: } nuclear@0: } nuclear@0: // copy texture coordinates nuclear@0: unsigned int n = 0; nuclear@0: while ((**begin).HasTextureCoords(n)) { nuclear@0: out->mNumUVComponents[n] = (*begin)->mNumUVComponents[n]; nuclear@0: nuclear@0: pv2 = out->mTextureCoords[n] = new aiVector3D[out->mNumVertices]; nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: nuclear@0: if ((*it)->mTextureCoords[n]) { nuclear@0: ::memcpy(pv2,(*it)->mTextureCoords[n],(*it)->mNumVertices*sizeof(aiVector3D)); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("JoinMeshes: UVs expected but input mesh contains no UVs"); nuclear@0: pv2 += (*it)->mNumVertices; nuclear@0: } nuclear@0: ++n; nuclear@0: } nuclear@0: // copy vertex colors nuclear@0: n = 0; nuclear@0: while ((**begin).HasVertexColors(n)) { nuclear@0: aiColor4D* pv2 = out->mColors[n] = new aiColor4D[out->mNumVertices]; nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: nuclear@0: if ((*it)->mColors[n]) { nuclear@0: ::memcpy(pv2,(*it)->mColors[n],(*it)->mNumVertices*sizeof(aiColor4D)); nuclear@0: } nuclear@0: else DefaultLogger::get()->warn("JoinMeshes: VCs expected but input mesh contains no VCs"); nuclear@0: pv2 += (*it)->mNumVertices; nuclear@0: } nuclear@0: ++n; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: if (out->mNumFaces) // just for safety nuclear@0: { nuclear@0: // copy faces nuclear@0: out->mFaces = new aiFace[out->mNumFaces]; nuclear@0: aiFace* pf2 = out->mFaces; nuclear@0: nuclear@0: unsigned int ofs = 0; nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) { nuclear@0: for (unsigned int m = 0; m < (*it)->mNumFaces;++m,++pf2) { nuclear@0: aiFace& face = (*it)->mFaces[m]; nuclear@0: pf2->mNumIndices = face.mNumIndices; nuclear@0: pf2->mIndices = face.mIndices; nuclear@0: nuclear@0: if (ofs) { nuclear@0: // add the offset to the vertex nuclear@0: for (unsigned int q = 0; q < face.mNumIndices; ++q) nuclear@0: face.mIndices[q] += ofs; nuclear@0: } nuclear@0: face.mIndices = NULL; nuclear@0: } nuclear@0: ofs += (*it)->mNumVertices; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // bones - as this is quite lengthy, I moved the code to a separate function nuclear@0: if (out->mNumBones) nuclear@0: MergeBones(out,begin,end); nuclear@0: nuclear@0: // delete all source meshes nuclear@0: for (std::vector::const_iterator it = begin; it != end;++it) nuclear@0: delete *it; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: template nuclear@0: inline void CopyPtrArray (Type**& dest, const Type* const * src, unsigned int num) nuclear@0: { nuclear@0: if (!num) nuclear@0: { nuclear@0: dest = NULL; nuclear@0: return; nuclear@0: } nuclear@0: dest = new Type*[num]; nuclear@0: for (unsigned int i = 0; i < num;++i) { nuclear@0: SceneCombiner::Copy(&dest[i],src[i]); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: template nuclear@0: inline void GetArrayCopy (Type*& dest, unsigned int num ) nuclear@0: { nuclear@0: if (!dest)return; nuclear@0: Type* old = dest; nuclear@0: nuclear@0: dest = new Type[num]; nuclear@0: ::memcpy(dest, old, sizeof(Type) * num); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::CopySceneFlat(aiScene** _dest,const aiScene* src) nuclear@0: { nuclear@0: // reuse the old scene or allocate a new? nuclear@0: if (*_dest) { nuclear@0: (*_dest)->~aiScene(); nuclear@0: new (*_dest) aiScene(); nuclear@0: } nuclear@0: else *_dest = new aiScene(); nuclear@0: nuclear@0: ::memcpy(*_dest,src,sizeof(aiScene)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::CopyScene(aiScene** _dest,const aiScene* src,bool allocate) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: if (allocate) { nuclear@0: *_dest = new aiScene(); nuclear@0: } nuclear@0: aiScene* dest = *_dest; nuclear@0: ai_assert(dest); nuclear@0: nuclear@0: // copy animations nuclear@0: dest->mNumAnimations = src->mNumAnimations; nuclear@0: CopyPtrArray(dest->mAnimations,src->mAnimations, nuclear@0: dest->mNumAnimations); nuclear@0: nuclear@0: // copy textures nuclear@0: dest->mNumTextures = src->mNumTextures; nuclear@0: CopyPtrArray(dest->mTextures,src->mTextures, nuclear@0: dest->mNumTextures); nuclear@0: nuclear@0: // copy materials nuclear@0: dest->mNumMaterials = src->mNumMaterials; nuclear@0: CopyPtrArray(dest->mMaterials,src->mMaterials, nuclear@0: dest->mNumMaterials); nuclear@0: nuclear@0: // copy lights nuclear@0: dest->mNumLights = src->mNumLights; nuclear@0: CopyPtrArray(dest->mLights,src->mLights, nuclear@0: dest->mNumLights); nuclear@0: nuclear@0: // copy cameras nuclear@0: dest->mNumCameras = src->mNumCameras; nuclear@0: CopyPtrArray(dest->mCameras,src->mCameras, nuclear@0: dest->mNumCameras); nuclear@0: nuclear@0: // copy meshes nuclear@0: dest->mNumMeshes = src->mNumMeshes; nuclear@0: CopyPtrArray(dest->mMeshes,src->mMeshes, nuclear@0: dest->mNumMeshes); nuclear@0: nuclear@0: // now - copy the root node of the scene (deep copy, too) nuclear@0: Copy( &dest->mRootNode, src->mRootNode); nuclear@0: nuclear@0: // and keep the flags ... nuclear@0: dest->mFlags = src->mFlags; nuclear@0: nuclear@0: // source private data might be NULL if the scene is user-allocated (i.e. for use with the export API) nuclear@0: ScenePriv(dest)->mPPStepsApplied = ScenePriv(src) ? ScenePriv(src)->mPPStepsApplied : 0; nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiMesh** _dest, const aiMesh* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiMesh* dest = *_dest = new aiMesh(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiMesh)); nuclear@0: nuclear@0: // and reallocate all arrays nuclear@0: GetArrayCopy( dest->mVertices, dest->mNumVertices ); nuclear@0: GetArrayCopy( dest->mNormals , dest->mNumVertices ); nuclear@0: GetArrayCopy( dest->mTangents, dest->mNumVertices ); nuclear@0: GetArrayCopy( dest->mBitangents, dest->mNumVertices ); nuclear@0: nuclear@0: unsigned int n = 0; nuclear@0: while (dest->HasTextureCoords(n)) nuclear@0: GetArrayCopy( dest->mTextureCoords[n++], dest->mNumVertices ); nuclear@0: nuclear@0: n = 0; nuclear@0: while (dest->HasVertexColors(n)) nuclear@0: GetArrayCopy( dest->mColors[n++], dest->mNumVertices ); nuclear@0: nuclear@0: // make a deep copy of all bones nuclear@0: CopyPtrArray(dest->mBones,dest->mBones,dest->mNumBones); nuclear@0: nuclear@0: // make a deep copy of all faces nuclear@0: GetArrayCopy(dest->mFaces,dest->mNumFaces); nuclear@0: for (unsigned int i = 0; i < dest->mNumFaces;++i) nuclear@0: { nuclear@0: aiFace& f = dest->mFaces[i]; nuclear@0: GetArrayCopy(f.mIndices,f.mNumIndices); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiMaterial** _dest, const aiMaterial* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiMaterial* dest = (aiMaterial*) ( *_dest = new aiMaterial() ); nuclear@0: dest->mNumAllocated = src->mNumAllocated; nuclear@0: dest->mNumProperties = src->mNumProperties; nuclear@0: dest->mProperties = new aiMaterialProperty* [dest->mNumAllocated]; nuclear@0: nuclear@0: for (unsigned int i = 0; i < dest->mNumProperties;++i) nuclear@0: { nuclear@0: aiMaterialProperty* prop = dest->mProperties[i] = new aiMaterialProperty(); nuclear@0: aiMaterialProperty* sprop = src->mProperties[i]; nuclear@0: nuclear@0: prop->mDataLength = sprop->mDataLength; nuclear@0: prop->mData = new char[prop->mDataLength]; nuclear@0: ::memcpy(prop->mData,sprop->mData,prop->mDataLength); nuclear@0: nuclear@0: prop->mIndex = sprop->mIndex; nuclear@0: prop->mSemantic = sprop->mSemantic; nuclear@0: prop->mKey = sprop->mKey; nuclear@0: prop->mType = sprop->mType; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiTexture** _dest, const aiTexture* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiTexture* dest = *_dest = new aiTexture(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiTexture)); nuclear@0: nuclear@0: // and reallocate all arrays. We must do it manually here nuclear@0: const char* old = (const char*)dest->pcData; nuclear@0: if (old) nuclear@0: { nuclear@0: unsigned int cpy; nuclear@0: if (!dest->mHeight)cpy = dest->mWidth; nuclear@0: else cpy = dest->mHeight * dest->mWidth * sizeof(aiTexel); nuclear@0: nuclear@0: if (!cpy) nuclear@0: { nuclear@0: dest->pcData = NULL; nuclear@0: return; nuclear@0: } nuclear@0: // the cast is legal, the aiTexel c'tor does nothing important nuclear@0: dest->pcData = (aiTexel*) new char[cpy]; nuclear@0: ::memcpy(dest->pcData, old, cpy); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiAnimation** _dest, const aiAnimation* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiAnimation* dest = *_dest = new aiAnimation(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiAnimation)); nuclear@0: nuclear@0: // and reallocate all arrays nuclear@0: CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiNodeAnim** _dest, const aiNodeAnim* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiNodeAnim* dest = *_dest = new aiNodeAnim(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiNodeAnim)); nuclear@0: nuclear@0: // and reallocate all arrays nuclear@0: GetArrayCopy( dest->mPositionKeys, dest->mNumPositionKeys ); nuclear@0: GetArrayCopy( dest->mScalingKeys, dest->mNumScalingKeys ); nuclear@0: GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiCamera** _dest,const aiCamera* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiCamera* dest = *_dest = new aiCamera(); nuclear@0: nuclear@0: // get a flat copy, that's already OK nuclear@0: ::memcpy(dest,src,sizeof(aiCamera)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiLight** _dest, const aiLight* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiLight* dest = *_dest = new aiLight(); nuclear@0: nuclear@0: // get a flat copy, that's already OK nuclear@0: ::memcpy(dest,src,sizeof(aiLight)); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiBone** _dest, const aiBone* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiBone* dest = *_dest = new aiBone(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiBone)); nuclear@0: nuclear@0: // and reallocate all arrays nuclear@0: GetArrayCopy( dest->mWeights, dest->mNumWeights ); nuclear@0: } nuclear@0: nuclear@0: // ------------------------------------------------------------------------------------------------ nuclear@0: void SceneCombiner::Copy (aiNode** _dest, const aiNode* src) nuclear@0: { nuclear@0: ai_assert(NULL != _dest && NULL != src); nuclear@0: nuclear@0: aiNode* dest = *_dest = new aiNode(); nuclear@0: nuclear@0: // get a flat copy nuclear@0: ::memcpy(dest,src,sizeof(aiNode)); nuclear@0: nuclear@0: // and reallocate all arrays nuclear@0: GetArrayCopy( dest->mMeshes, dest->mNumMeshes ); nuclear@0: CopyPtrArray( dest->mChildren, src->mChildren,dest->mNumChildren); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: }