void BlenderSceneExporter::storeSkeletons( TamySkeleton* arrSkeletons, int skeletonsCount ) { ResourcesManager& resMgr = TSingleton< ResourcesManager >::getInstance(); m_exportedSkeletons.clear(); m_exportedSkeletons.resize( skeletonsCount ); Matrix boneLocalMtx; for ( int skeletonIdx = 0; skeletonIdx < skeletonsCount; ++skeletonIdx ) { const TamySkeleton& exportedSkeleton = arrSkeletons[skeletonIdx]; FilePath skeletonPath( m_animationsExportDir + exportedSkeleton.name + "." + Skeleton::getExtension() ); Skeleton* skeleton = resMgr.create< Skeleton >( skeletonPath ); skeleton->clear(); m_exportedSkeletons[skeletonIdx] = skeleton; // set skeleton bones for ( int boneIdx = 0; boneIdx < exportedSkeleton.bonesCount; ++boneIdx ) { const TamyBone& exportedBone = exportedSkeleton.bones[boneIdx]; Matrix boneLocalTransform, invBoneMSTransform; if ( exportedBone.parentBoneIdx >= 0 ) { const TamyBone& parentBone = exportedSkeleton.bones[exportedBone.parentBoneIdx]; parentBone.modelSpaceTransform.applyTo( invBoneMSTransform ); invBoneMSTransform.invert(); Matrix boneMSTransform; exportedBone.modelSpaceTransform.applyTo( boneMSTransform ); boneLocalTransform.setMul( boneMSTransform, invBoneMSTransform ); } else { exportedBone.modelSpaceTransform.applyTo( boneLocalTransform ); } skeleton->addBone( exportedBone.name, boneLocalTransform, exportedBone.parentBoneIdx, exportedBone.boneLength ); } // calculate skeleton's bind pose skeleton->buildSkeleton(); // save the skeleton if ( m_exportSettings.saveAnimations ) { skeleton->saveResource(); } } }
bool Convert(const VfsPath& daeFilename, const VfsPath& pmdFilename, CColladaManager::FileType type) { // To avoid always loading the DLL when it's usually not going to be // used (and to do the same on Linux where delay-loading won't help), // and to avoid compile-time dependencies (because it's a minor pain // to get all the right libraries to build the COLLADA DLL), we load // it dynamically when it is required, instead of using the exported // functions and binding at link-time. if (! dll.IsLoaded()) { if (! dll.LoadDLL()) { LOGERROR(L"Failed to load COLLADA conversion DLL"); return false; } try { dll.LoadSymbol("set_logger", set_logger); dll.LoadSymbol("set_skeleton_definitions", set_skeleton_definitions); dll.LoadSymbol("convert_dae_to_pmd", convert_dae_to_pmd); dll.LoadSymbol("convert_dae_to_psa", convert_dae_to_psa); } catch (PSERROR_DllLoader&) { LOGERROR(L"Failed to load symbols from COLLADA conversion DLL"); dll.Unload(); return false; } VfsPath skeletonPath("art/skeletons/skeletons.xml"); // Set the filename for the logger to report set_logger(ColladaLog, static_cast<void*>(&skeletonPath)); CVFSFile skeletonFile; if (skeletonFile.Load(g_VFS, skeletonPath) != PSRETURN_OK) { LOGERROR(L"Failed to read skeleton definitions"); dll.Unload(); return false; } int ok = set_skeleton_definitions((const char*)skeletonFile.GetBuffer(), (int)skeletonFile.GetBufferSize()); if (ok < 0) { LOGERROR(L"Failed to load skeleton definitions"); dll.Unload(); return false; } // TODO: the cached PMD/PSA files should probably be invalidated when // the skeleton definition file is changed, else people will get confused // as to why it's not picking up their changes } // Set the filename for the logger to report set_logger(ColladaLog, const_cast<void*>(static_cast<const void*>(&daeFilename))); // We need to null-terminate the buffer, so do it (possibly inefficiently) // by converting to a CStr CStr daeData; { CVFSFile daeFile; if (daeFile.Load(g_VFS, daeFilename) != PSRETURN_OK) return false; daeData = daeFile.GetAsString(); } // Do the conversion into a memory buffer WriteBuffer writeBuffer; switch (type) { case CColladaManager::PMD: convert_dae_to_pmd(daeData.c_str(), ColladaOutput, &writeBuffer); break; case CColladaManager::PSA: convert_dae_to_psa(daeData.c_str(), ColladaOutput, &writeBuffer); break; } // don't create zero-length files (as happens in test_invalid_dae when // we deliberately pass invalid XML data) because the VFS caching // logic warns when asked to load such. if (writeBuffer.Size()) { Status ret = g_VFS->CreateFile(pmdFilename, writeBuffer.Data(), writeBuffer.Size()); ENSURE(ret == INFO::OK); } return true; }