void ResourceLoader::loadMeshWork(const String& name, Mesh::MeshdataPtr mesh, const String& skeletonName, LoadedCallback cb) { Ogre::MeshManager& mm = Ogre::MeshManager::getSingleton(); Ogre::MeshPtr mo = mm.getByName(name); if (mo.isNull()) { /// FIXME: set bounds, bounding radius here Ogre::ManualResourceLoader *reload; mo = mm.createManual(name,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,(reload= #ifdef _WIN32 #ifdef NDEBUG OGRE_NEW #else new #endif #else OGRE_NEW #endif ManualMeshLoader(mesh, name))); reload->prepareResource(&*mo); reload->loadResource(&*mo); if (!skeletonName.empty()) { Ogre::SkeletonManager& skel_mgr = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = skel_mgr.getByName(skeletonName); if (!skel.isNull()) mo->_notifySkeleton(skel); } } cb(); }
Ogre::Mesh* EC_Mesh::PrepareMesh(const std::string& mesh_name, bool clone) { if (!ViewEnabled()) return 0; if (renderer_.expired()) return 0; RendererPtr renderer = renderer_.lock(); Ogre::MeshManager& mesh_mgr = Ogre::MeshManager::getSingleton(); Ogre::MeshPtr mesh = mesh_mgr.getByName(SanitateAssetIdForOgre(mesh_name)); // For local meshes, mesh will not get automatically loaded until used in an entity. Load now if necessary if (mesh.isNull()) { try { mesh_mgr.load(mesh_name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mesh = mesh_mgr.getByName(mesh_name); } catch (Ogre::Exception& e) { LogError("Could not load mesh " + mesh_name + ": " + std::string(e.what())); return 0; } } // If mesh is still null, must abort if (mesh.isNull()) { LogError("Mesh " + mesh_name + " does not exist"); return 0; } if (clone) { try { mesh = mesh->clone(renderer->GetUniqueObjectName("EC_Mesh_clone")); mesh->setAutoBuildEdgeLists(false); cloned_mesh_name_ = mesh->getName(); } catch (Ogre::Exception& e) { LogError("Could not clone mesh " + mesh_name + ":" + std::string(e.what())); return 0; } } if (mesh->hasSkeleton()) { Ogre::SkeletonPtr skeleton = Ogre::SkeletonManager::getSingleton().getByName(mesh->getSkeletonName()); if (skeleton.isNull() || skeleton->getNumBones() == 0) { LogDebug("Mesh " + mesh_name + " has a skeleton with 0 bones. Disabling the skeleton."); mesh->setSkeletonName(""); } } return mesh.get(); }
Ogre::Skeleton *ESKOgre::createOgreSkeleton(Ogre::SceneManager *mSceneMgr) { Ogre::SkeletonPtr mSkel = Ogre::SkeletonManager::getSingleton().create(name, XENOVIEWER_RESOURCE_GROUP, true); if (bones.size()) { buildBone(0, mSkel.getPointer(), NULL); } resources_created = true; createFakeEntity(mSceneMgr); skeleton = mSkel.getPointer(); return mSkel.getPointer(); }
void BcxFile::GetSkeleton( std::vector< s16 >& skeleton_length ) { u32 offset_to_model_info = GetU32LE(0x04); u8 number_of_bones = GetU8(offset_to_model_info + 0x02); u16 offset_to_bones = GetU16LE(offset_to_model_info + 0x1C); SkeletonFile file_s(this); Ogre::SkeletonPtr skeleton; skeleton.setNull(); file_s.GetData( skeleton_length, offset_to_bones, number_of_bones, skeleton); }
gkSkeletonLoader::gkSkeletonLoader(gkSkeletonResource* skel) : m_skeleton(skel) { Ogre::SkeletonManager& mgr = Ogre::SkeletonManager::getSingleton(); const gkString& name = m_skeleton->getResourceName().getName(); Ogre::SkeletonPtr oskel = mgr.getByName(name); if (oskel.isNull()) oskel = mgr.create(name, skel->getGroupName(), true, this); //GK_BUILTIN_GROUP }
void ResourceLoader::loadSkeletonWork(const String& name, Mesh::MeshdataPtr mesh, const std::set<String>& animationList, LoadedCallback cb) { Ogre::SkeletonManager& skel_mgr = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = skel_mgr.getByName(name); if (skel.isNull()) { Ogre::ManualResourceLoader *reload; Ogre::SkeletonPtr skel = Ogre::SkeletonPtr(skel_mgr.create(name,Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true, (reload=new ManualSkeletonLoader(mesh, animationList)))); reload->prepareResource(&*skel); reload->loadResource(&*skel); } cb(); }
Ogre::MeshPtr loadMesh(const Ogre::String& meshName, const Ogre::String& groupName, const Ogre::String& baseResourceName, const Ogre::String& baseGroupName) { // Load the mesh Ogre::MeshPtr mesh = loadCorrelativeResource( meshName, groupName, baseResourceName, baseGroupName, Ogre::MeshManager::getSingleton()); if (mesh.isNull()) { OGRE_EXCEPT(Ogre::Exception::ERR_ITEM_NOT_FOUND, "Unable to load mesh " + meshName, "loadMesh"); } // Try to resolve skeleton resource if (mesh->hasSkeleton() && mesh->getSkeleton().isNull()) { // resolve correlative with mesh Ogre::SkeletonPtr skeleton = loadCorrelativeResource( mesh->getSkeletonName(), groupName, mesh->getName(), mesh->getGroup(), Ogre::SkeletonManager::getSingleton()); if (skeleton.isNull()) { // resolve correlative with base resource skeleton = loadCorrelativeResource( mesh->getSkeletonName(), groupName, baseResourceName, baseGroupName, Ogre::SkeletonManager::getSingleton()); } if (skeleton.isNull()) { OGRE_EXCEPT(Ogre::Exception::ERR_ITEM_NOT_FOUND, "Unable to load skeleton " + mesh->getSkeletonName() + " for mesh " + mesh->getName(), "loadMesh"); } // Set to the actual name mesh->setSkeletonName(skeleton->getName()); } return mesh; }
//--------------------------------------------------------------------- void PFile::addGroups( Ogre::Mesh *mesh, const String &bone_name ,const RSDFilePtr &rsd ) const { const Ogre::SkeletonPtr skeleton( mesh->getSkeleton() ); const String material_base_name( rsd->getMaterialBaseName() ); String rsd_base; StringUtil::splitBase( rsd->getName(), rsd_base ); ManualObject mo( mesh ); for( size_t g(0); g < m_groups.size(); ++g ) { const String sub_name( bone_name + "/" + rsd_base + "/" + Ogre::StringConverter::toString(g) ); addGroup( m_groups[g], mo, sub_name, material_base_name, skeleton->getBone( bone_name ) ); } }
Ogre::SkeletonPtr GetLocalSkeleton(const std::string& name) { Ogre::SkeletonManager& manager = Ogre::SkeletonManager::getSingleton(); Ogre::SkeletonPtr skel = manager.getByName(name); if (skel.isNull()) { try { manager.load(name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); skel = manager.getByName(name); } catch(...) {} } return skel; }
const std::string& EC_Mesh::GetSkeletonName() const { static std::string empty_name; if (!entity_) return empty_name; else { Ogre::MeshPtr mesh = entity_->getMesh(); if (!mesh->hasSkeleton()) return empty_name; Ogre::SkeletonPtr skel = mesh->getSkeleton(); if (skel.isNull()) return empty_name; return skel->getName(); } }
//------------------------------------------------------------------------- void AFile::addTo( Ogre::SkeletonPtr skeleton, const String& name ) const { if( skeleton->hasAnimation( name) ) return; Ogre::Real length( ( m_frames.size() - 1 ) * FRAME_DURATION ); Ogre::Animation *anim( skeleton->createAnimation(name, length )); uint16 track_handle( 0 ); Ogre::Bone* bone( skeleton->getBone( "root" ) ); Ogre::NodeAnimationTrack* track; track = anim->createNodeTrack( track_handle++, bone ); Ogre::Real time; size_t index( 0 ); for( FrameList::const_iterator frame( m_frames.begin()) ;frame != m_frames.end(); ++frame ) { time = (index++) * FRAME_DURATION; Ogre::TransformKeyFrame* key_frame( track->createNodeKeyFrame( time ) ); key_frame->setTranslate( frame->root_translation ); setFrameRotation( key_frame, frame->root_rotation ); } for( uint32 i(0); i < m_bone_count; ++i ) { if (i + 1 >= skeleton->getNumBones()) { // TODO: Figure out why this happens/fix it LOG_ERROR("Bone " + std::to_string(i + 1) + " is out of bounds " + std::to_string(skeleton->getNumBones()) + " for: " + name + " in: " + skeleton->getName()); } else { bone = skeleton->getBone(i + 1); track = anim->createNodeTrack(track_handle++, bone); time = 0; for (FrameList::const_iterator frame(m_frames.begin()) ; frame != m_frames.end(); ++frame) { const Ogre::Vector3& rot(frame->bone_rotations[i]); Ogre::TransformKeyFrame* key_frame(track->createNodeKeyFrame(time)); setFrameRotation(key_frame, rot); time += FRAME_DURATION; } } } }
void EC_Mesh::OnSkeletonAssetLoaded(AssetPtr asset) { OgreSkeletonAsset *skeletonAsset = dynamic_cast<OgreSkeletonAsset*>(asset.get()); if (!skeletonAsset) { LogError("OnSkeletonAssetLoaded: Skeleton asset load finished for asset \"" + asset->Name().toStdString() + "\", but downloaded asset was not of type OgreSkeletonAsset!"); return; } Ogre::SkeletonPtr skeleton = skeletonAsset->ogreSkeleton; if (skeleton.isNull()) { LogError("OnSkeletonAssetLoaded: Skeleton asset load finished for asset \"" + asset->Name().toStdString() + "\", but Ogre::Skeleton pointer was null!"); return; } if(!entity_) { LogDebug("Could not set skeleton yet because entity is not yet created"); return; } try { // If old skeleton is same as a new one no need to replace it. if (entity_->getSkeleton() && entity_->getSkeleton()->getName() == skeleton->getName()) return; entity_->getMesh()->_notifySkeleton(skeleton); // LogDebug("Set skeleton " + skeleton->getName() + " to mesh " + entity_->getName()); emit SkeletonChanged(QString::fromStdString(skeleton->getName())); } catch (...) { LogError("Exception while setting skeleton to mesh" + entity_->getName()); } // Now we have to recreate the entity to get proper animations etc. SetMesh(entity_->getMesh()->getName().c_str(), false); }
void CMonster3D::setupSkeleton(std::string skeletonFile) { Ogre::SkeletonPtr pSkeletonBody = Ogre::SkeletonManager::getSingleton().getByName(m_meshName + ".skeleton"); Ogre::Skeleton::BoneHandleMap boneHandleMap; Ogre::SkeletonPtr pNewSkeleton = Ogre::SkeletonManager::getSingleton().load(skeletonFile, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); Ogre::Animation *pSrcAnimation = pNewSkeleton->getAnimation(0); std::string newAnimationName = pSrcAnimation->getName() + "::" + m_pMonsterNode->getName(); Ogre::Animation *pNewAnimation = pNewSkeleton->createAnimation(newAnimationName, pSrcAnimation->getLength()); Ogre::Animation *pCloneAnimation = pNewSkeleton->getAnimation(0)->clone(newAnimationName); *pNewAnimation = *pCloneAnimation; pNewSkeleton->removeAnimation(pSrcAnimation->getName()); pNewSkeleton->_buildMapBoneByHandle(pNewSkeleton.getPointer(), boneHandleMap); pSkeletonBody->_mergeSkeletonAnimations(pNewSkeleton.getPointer(), boneHandleMap); Ogre::SkeletonManager::getSingleton().remove(skeletonFile); m_pBodyEntity->getSkeleton()->_refreshAnimationState(m_pBodyEntity->getAllAnimationStates()); }
std::vector<std::wstring> ManipulatorEffect::GetLocatorNames() const { Ogre::Entity* ent = ManipulatorSystem.GetObject().GetSelection(); assert(ent); std::vector<std::wstring> ret; //M3模型从max导出时locator命名为Ref_xxx形式 Ogre::SkeletonPtr skel = ent->getMesh()->getSkeleton(); Ogre::Skeleton::BoneIterator iter = skel->getBoneIterator(); while (iter.hasMoreElements()) { Ogre::Bone* pBone = iter.peekNext(); if(pBone->getName().find("Ref_") != Ogre::String::npos) ret.push_back(Utility::EngineToUnicode(pBone->getName())); iter.getNext(); } return std::move(ret); }
void AnimationFile::GetData( std::vector< s16 >& skeleton_length, const Unit& unit, const int offset_to_animations, const int number_of_animation, const int start_animation, Ogre::SkeletonPtr skeleton) { for (int i = 0; i < number_of_animation; ++i) { /*LOGGER->Log(LOGGER_INFO, "Animation Header %02x%02x %02x %02x %02x %02x %02x%02x %02x%02x %02x%02x %02x%02x%02x%02x", GetU8(offset_to_animations + i * 0x10 + 0x00), GetU8(offset_to_animations + i * 0x10 + 0x01), GetU8(offset_to_animations + i * 0x10 + 0x02), GetU8(offset_to_animations + i * 0x10 + 0x03), GetU8(offset_to_animations + i * 0x10 + 0x04), GetU8(offset_to_animations + i * 0x10 + 0x05), GetU8(offset_to_animations + i * 0x10 + 0x06), GetU8(offset_to_animations + i * 0x10 + 0x07), GetU8(offset_to_animations + i * 0x10 + 0x08), GetU8(offset_to_animations + i * 0x10 + 0x09), GetU8(offset_to_animations + i * 0x10 + 0x0A), GetU8(offset_to_animations + i * 0x10 + 0x0B), GetU8(offset_to_animations + i * 0x10 + 0x0C), GetU8(offset_to_animations + i * 0x10 + 0x0D), GetU8(offset_to_animations + i * 0x10 + 0x0E), GetU8(offset_to_animations + i * 0x10 + 0x0F)); */ AnimationHeader header; header.number_of_frames = GetU16LE(offset_to_animations + i * 0x10 + 0x00); header.number_of_bones = GetU8(offset_to_animations + i * 0x10 + 0x02); header.number_of_frames_translation = GetU8(offset_to_animations + i * 0x10 + 0x03); header.number_of_static_translation = GetU8(offset_to_animations + i * 0x10 + 0x04); header.number_of_frames_rotation = GetU8(offset_to_animations + i * 0x10 + 0x05); header.offset_to_frames_translation_data = GetU16LE(offset_to_animations + i * 0x10 + 0x06); header.offset_to_static_translation_data = GetU16LE(offset_to_animations + i * 0x10 + 0x08); header.offset_to_frames_rotation_data = GetU16LE(offset_to_animations + i * 0x10 + 0x0A); header.offset_to_animation_data = GetU32LE(offset_to_animations + i * 0x10 + 0x0C) - 0x80000000; m_AnimationHeaders.push_back(header); } for (size_t i = 0; (i < static_cast<size_t>(number_of_animation)) && (start_animation + i < unit.animations.size()); ++i) { if (unit.animations[start_animation + i] == "" || unit.animations[start_animation + i] == " ") { continue; } /* File file(mpBuffer, m_AnimationHeaders[i].offset_to_animation_data, 0x04 + m_AnimationHeaders[i].number_of_bones * 0x08 + m_AnimationHeaders[i].number_of_frames_translation * m_AnimationHeaders[i].number_of_frames * 0x02 + m_AnimationHeaders[i].number_of_static_translation * 0x02 + m_AnimationHeaders[i].number_of_frames_rotation * m_AnimationHeaders[i].number_of_frames); file.WriteFile(RString((Ogre::String("dump/") + Ogre::String("animation_") + Ogre::StringConverter::toString(i) + Ogre::String("_data")).c_str())); */ Ogre::Animation* anim = skeleton->createAnimation(unit.animations[start_animation + i], (float)(m_AnimationHeaders[i].number_of_frames - 1) / 30.0f); for (u32 j = 0; j < m_AnimationHeaders[i].number_of_frames; ++j) { Frame frame; // root bone Ogre::Bone* root = skeleton->getBone(0); Ogre::NodeAnimationTrack* track; if (j == 0) { track = anim->createNodeTrack(0, root); track->removeAllKeyFrames(); } else { track = anim->getNodeTrack(0); } Ogre::TransformKeyFrame* frame_root = track->createNodeKeyFrame((float)j / 30.0f); Ogre::Quaternion rot; Ogre::Matrix3 mat; mat.FromEulerAnglesZXY(Ogre::Radian(Ogre::Degree(180)), Ogre::Radian(Ogre::Degree(0)), Ogre::Radian(Ogre::Degree(0))); rot.FromRotationMatrix(mat); frame_root->setRotation(rot); for (u32 k = 0; k < m_AnimationHeaders[i].number_of_bones; ++k) { BonePosition position; u8 flag = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x00); u8 rx = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x01); u8 ry = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x02); u8 rz = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x03); u8 tx = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x04); u8 ty = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x05); u8 tz = GetU8(m_AnimationHeaders[i].offset_to_animation_data + 0x04 + k * 0x08 + 0x06); // rotation if (flag & 0x01) { position.rotation_x = 360.0f * GetU8(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_rotation_data + rx * m_AnimationHeaders[i].number_of_frames + j) / 255.0f; } else { position.rotation_x = 360.0f * rx / 255.0f; } if (flag & 0x02) { position.rotation_y = 360.0f * GetU8(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_rotation_data + ry * m_AnimationHeaders[i].number_of_frames + j) / 255.0f; } else { position.rotation_y = 360.0f * ry / 255.0f; } if (flag & 0x04) { position.rotation_z = 360.0f * GetU8(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_rotation_data + rz * m_AnimationHeaders[i].number_of_frames + j) / 255.0f; } else { position.rotation_z = 360.0f * rz / 255.0f; } // translation position.translation_x = 0; position.translation_y = 0; position.translation_z = 0; if (flag & 0x10) { position.translation_x = static_cast<float>( -(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_translation_data + tx * m_AnimationHeaders[i].number_of_frames * 2 + j * 2)); } else if (tx != 0xFF) { position.translation_x = static_cast<float>(-(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_static_translation_data + tx * 2)); } if (flag & 0x20) { position.translation_y = static_cast<float>(-(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_translation_data + ty * m_AnimationHeaders[i].number_of_frames * 2 + j * 2)); } else if (ty != 0xFF) { position.translation_y = static_cast<float>(-(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_static_translation_data + ty * 2)); } if (flag & 0x40) { position.translation_z = static_cast<float>(-(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_frames_translation_data + tz * m_AnimationHeaders[i].number_of_frames * 2 + j * 2)); } else if (tz != 0xFF) { position.translation_z = static_cast<float>(-(s16)GetU16LE(m_AnimationHeaders[i].offset_to_animation_data + m_AnimationHeaders[i].offset_to_static_translation_data + tz * 2)); } //LOGGER->Log(LOGGER_INFO, "%d %d", m_AnimationHeaders[i].number_of_frames, j); //LOGGER->Log(LOGGER_INFO, "animation (%f %f %f) (%f %f %f)", position.rotation_x, position.rotation_y, position.rotation_z, position.translation_x, position.translation_y, position.translation_z); frame.bone.push_back(position); Ogre::Bone* bone1 = skeleton->getBone(k * 2 + 1); Ogre::Bone* bone2 = skeleton->getBone(k * 2 + 2); Ogre::NodeAnimationTrack* track1; Ogre::NodeAnimationTrack* track2; if (j == 0) { track1 = anim->createNodeTrack(k * 2 + 1, bone1); track1->removeAllKeyFrames(); track2 = anim->createNodeTrack(k * 2 + 2, bone2); track2->removeAllKeyFrames(); } else { track1 = anim->getNodeTrack(k * 2 + 1); track2 = anim->getNodeTrack(k * 2 + 2); } Ogre::TransformKeyFrame* frame1 = track1->createNodeKeyFrame((float)j / 30.0f); Ogre::TransformKeyFrame* frame2 = track2->createNodeKeyFrame((float)j / 30.0f); float length = skeleton_length[ k ]; frame1->setTranslate(Ogre::Vector3(position.translation_x, position.translation_z - length, position.translation_y) / 1024); Ogre::Quaternion rot; Ogre::Matrix3 mat; mat.FromEulerAnglesZXY(Ogre::Radian(Ogre::Degree(-position.rotation_y)), Ogre::Radian(Ogre::Degree(-position.rotation_x)), Ogre::Radian(Ogre::Degree(-position.rotation_z))); rot.FromRotationMatrix(mat); frame2->setRotation(rot); } } } }
void Barrel::loadAnimation() { Ogre::SkeletonPtr skeleton = Ogre::SkeletonManager::getSingleton().load("jaiqua.skeleton", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); animation = skeleton->getAnimation("Sneak"); }
void NIFMeshLoader::createSubMesh(Ogre::Mesh *mesh, const Nif::NiTriShape *shape) { const Nif::NiTriShapeData *data = shape->data.getPtr(); const Nif::NiSkinInstance *skin = (shape->skin.empty() ? NULL : shape->skin.getPtr()); std::vector<Ogre::Vector3> srcVerts = data->vertices; std::vector<Ogre::Vector3> srcNorms = data->normals; Ogre::HardwareBuffer::Usage vertUsage = Ogre::HardwareBuffer::HBU_STATIC; bool vertShadowBuffer = false; bool geomMorpherController = false; if(!shape->controller.empty()) { Nif::ControllerPtr ctrl = shape->controller; do { if(ctrl->recType == Nif::RC_NiGeomMorpherController) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; vertShadowBuffer = true; geomMorpherController = true; break; } } while(!(ctrl=ctrl->next).empty()); } if(skin != NULL) { vertUsage = Ogre::HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY; vertShadowBuffer = true; // Only set a skeleton when skinning. Unskinned meshes with a skeleton will be // explicitly attached later. mesh->setSkeletonName(mName); // Convert vertices and normals to bone space from bind position. It would be // better to transform the bones into bind position, but there doesn't seem to // be a reliable way to do that. std::vector<Ogre::Vector3> newVerts(srcVerts.size(), Ogre::Vector3(0.0f)); std::vector<Ogre::Vector3> newNorms(srcNorms.size(), Ogre::Vector3(0.0f)); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t b = 0;b < bones.length();b++) { Ogre::Matrix4 mat; mat.makeTransform(data->bones[b].trafo.trans, Ogre::Vector3(data->bones[b].trafo.scale), Ogre::Quaternion(data->bones[b].trafo.rotation)); mat = bones[b]->getWorldTransform() * mat; const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[b].weights; for(size_t i = 0;i < weights.size();i++) { size_t index = weights[i].vertex; float weight = weights[i].weight; newVerts.at(index) += (mat*srcVerts[index]) * weight; if(newNorms.size() > index) { Ogre::Vector4 vec4(srcNorms[index][0], srcNorms[index][1], srcNorms[index][2], 0.0f); vec4 = mat*vec4 * weight; newNorms[index] += Ogre::Vector3(&vec4[0]); } } } srcVerts = newVerts; srcNorms = newNorms; } else { Ogre::SkeletonManager *skelMgr = Ogre::SkeletonManager::getSingletonPtr(); if(skelMgr->getByName(mName).isNull()) { // No skinning and no skeleton, so just transform the vertices and // normals into position. Ogre::Matrix4 mat4 = shape->getWorldTransform(); for(size_t i = 0;i < srcVerts.size();i++) { Ogre::Vector4 vec4(srcVerts[i].x, srcVerts[i].y, srcVerts[i].z, 1.0f); vec4 = mat4*vec4; srcVerts[i] = Ogre::Vector3(&vec4[0]); } for(size_t i = 0;i < srcNorms.size();i++) { Ogre::Vector4 vec4(srcNorms[i].x, srcNorms[i].y, srcNorms[i].z, 0.0f); vec4 = mat4*vec4; srcNorms[i] = Ogre::Vector3(&vec4[0]); } } } // Set the bounding box first BoundsFinder bounds; bounds.add(&srcVerts[0][0], srcVerts.size()); if(!bounds.isValid()) { float v[3] = { 0.0f, 0.0f, 0.0f }; bounds.add(&v[0], 1); } mesh->_setBounds(Ogre::AxisAlignedBox(bounds.minX()-0.5f, bounds.minY()-0.5f, bounds.minZ()-0.5f, bounds.maxX()+0.5f, bounds.maxY()+0.5f, bounds.maxZ()+0.5f)); mesh->_setBoundingSphereRadius(bounds.getRadius()); // This function is just one long stream of Ogre-barf, but it works // great. Ogre::HardwareBufferManager *hwBufMgr = Ogre::HardwareBufferManager::getSingletonPtr(); Ogre::HardwareVertexBufferSharedPtr vbuf; Ogre::HardwareIndexBufferSharedPtr ibuf; Ogre::VertexBufferBinding *bind; Ogre::VertexDeclaration *decl; int nextBuf = 0; Ogre::SubMesh *sub = mesh->createSubMesh(); // Add vertices sub->useSharedVertices = false; sub->vertexData = new Ogre::VertexData(); sub->vertexData->vertexStart = 0; sub->vertexData->vertexCount = srcVerts.size(); decl = sub->vertexData->vertexDeclaration; bind = sub->vertexData->vertexBufferBinding; if(srcVerts.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), srcVerts.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcVerts[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); bind->setBinding(nextBuf++, vbuf); } // Vertex normals if(srcNorms.size()) { vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3), srcNorms.size(), vertUsage, vertShadowBuffer); vbuf->writeData(0, vbuf->getSizeInBytes(), &srcNorms[0][0], true); decl->addElement(nextBuf, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); bind->setBinding(nextBuf++, vbuf); } // Vertex colors const std::vector<Ogre::Vector4> &colors = data->colors; if(colors.size()) { Ogre::RenderSystem *rs = Ogre::Root::getSingleton().getRenderSystem(); std::vector<Ogre::RGBA> colorsRGB(colors.size()); for(size_t i = 0;i < colorsRGB.size();i++) { Ogre::ColourValue clr(colors[i][0], colors[i][1], colors[i][2], colors[i][3]); rs->convertColourValue(clr, &colorsRGB[i]); } vbuf = hwBufMgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_COLOUR), colorsRGB.size(), Ogre::HardwareBuffer::HBU_STATIC); vbuf->writeData(0, vbuf->getSizeInBytes(), &colorsRGB[0], true); decl->addElement(nextBuf, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE); bind->setBinding(nextBuf++, vbuf); } // Texture UV coordinates size_t numUVs = data->uvlist.size(); if (numUVs) { size_t elemSize = Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2); for(size_t i = 0; i < numUVs; i++) decl->addElement(nextBuf, elemSize*i, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES, i); vbuf = hwBufMgr->createVertexBuffer(decl->getVertexSize(nextBuf), srcVerts.size(), Ogre::HardwareBuffer::HBU_STATIC); std::vector<Ogre::Vector2> allUVs; allUVs.reserve(srcVerts.size()*numUVs); for (size_t vert = 0; vert<srcVerts.size(); ++vert) for(size_t i = 0; i < numUVs; i++) allUVs.push_back(data->uvlist[i][vert]); vbuf->writeData(0, elemSize*srcVerts.size()*numUVs, &allUVs[0], true); bind->setBinding(nextBuf++, vbuf); } // Triangle faces const std::vector<short> &srcIdx = data->triangles; if(srcIdx.size()) { ibuf = hwBufMgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, srcIdx.size(), Ogre::HardwareBuffer::HBU_STATIC); ibuf->writeData(0, ibuf->getSizeInBytes(), &srcIdx[0], true); sub->indexData->indexBuffer = ibuf; sub->indexData->indexCount = srcIdx.size(); sub->indexData->indexStart = 0; } // Assign bone weights for this TriShape if(skin != NULL) { Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(mName); const Nif::NiSkinData *data = skin->data.getPtr(); const Nif::NodeList &bones = skin->bones; for(size_t i = 0;i < bones.length();i++) { Ogre::VertexBoneAssignment boneInf; boneInf.boneIndex = skel->getBone(bones[i]->name)->getHandle(); const std::vector<Nif::NiSkinData::VertWeight> &weights = data->bones[i].weights; for(size_t j = 0;j < weights.size();j++) { boneInf.vertexIndex = weights[j].vertex; boneInf.weight = weights[j].weight; sub->addBoneAssignment(boneInf); } } } const Nif::NiTexturingProperty *texprop = NULL; const Nif::NiMaterialProperty *matprop = NULL; const Nif::NiAlphaProperty *alphaprop = NULL; const Nif::NiVertexColorProperty *vertprop = NULL; const Nif::NiZBufferProperty *zprop = NULL; const Nif::NiSpecularProperty *specprop = NULL; const Nif::NiWireframeProperty *wireprop = NULL; bool needTangents = false; shape->getProperties(texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop); std::string matname = NIFMaterialLoader::getMaterial(data, mesh->getName(), mGroup, texprop, matprop, alphaprop, vertprop, zprop, specprop, wireprop, needTangents); if(matname.length() > 0) sub->setMaterialName(matname); // build tangents if the material needs them if (needTangents) { unsigned short src,dest; if (!mesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src,dest)) mesh->buildTangentVectors(Ogre::VES_TANGENT, src,dest); } // Create a dummy vertex animation track if there's a geom morpher controller // This is required to make Ogre create the buffers we will use for software vertex animation if (srcVerts.size() && geomMorpherController) mesh->createAnimation("dummy", 0)->createVertexTrack(1, sub->vertexData, Ogre::VAT_MORPH); }
Ogre::Entity* ModelFile::GetModel( const ModelInfo& info ) { VectorTexForGen textures; Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().create( info.data.name + "export", "General" ); Ogre::SkeletonPtr skeleton = Ogre::SkeletonManager::getSingleton().create( info.data.name + "export", "General" ); int number_of_bones = GetU8( 0x02 ); int number_of_parts = GetU8( 0x03 ); int offset_to_bones = GetU32LE( 0x0c ); int offset_to_parts = GetU32LE( 0x10 ); Ogre::Bone* root1 = skeleton->createBone( "0", 0 ); Ogre::Bone* root2 = skeleton->createBone( "1", 1 ); root1->addChild( root2 ); for( int i = 0; i < number_of_bones; ++i ) { Bone bone; bone.parent_id = ( i != 0 ) ? ( s8 )GetU8( offset_to_bones + i * 0x04 + 0x03 ) : -1; bone.length = ( s16 )GetU16LE( offset_to_bones + i * 0x04 + 0x00 ); m_Skeleton.push_back(bone); Ogre::Bone* bone1 = skeleton->createBone( Ogre::StringConverter::toString( i * 2 + 2 ), i * 2 + 2 ); Ogre::Bone* bone2 = skeleton->createBone( Ogre::StringConverter::toString( i * 2 + 3 ), i * 2 + 3 ); LOGGER->Log( "Add skeleton bone: bone_id = " + Ogre::StringConverter::toString( i ) + ", length = " + Ogre::StringConverter::toString( bone.length ) + ", parent = " + Ogre::StringConverter::toString( bone.parent_id ) + ".\n" ); if( bone.parent_id == -1 ) { skeleton->getBone( 1 )->addChild( bone1 ); } else { skeleton->getBone( bone.parent_id * 2 + 3 )->addChild( bone1 ); } bone1->addChild( bone2 ); } AnimationExtractor( skeleton, info, m_Skeleton ); // draw skeleton { //DrawSkeleton( m_Skeleton, mesh ); } for( int i = 0; i < number_of_parts; ++i ) { MeshExtractor( info.data, "ffix/field_model/" + info.data.name, this, offset_to_parts + i * 0x28, textures, mesh ); } // <OGRE> /////////////////////////////// skeleton->optimiseAllAnimations(); Ogre::SkeletonSerializer skeleton_serializer; skeleton_serializer.exportSkeleton( skeleton.getPointer(), "exported/models/field/units/" + info.data.name + ".skeleton" ); // Update bounds Ogre::AxisAlignedBox aabb( -999, -999, -999, 999, 999, 999 ); mesh->_setBounds( aabb, false ); mesh->_setBoundingSphereRadius( 999 ); mesh->setSkeletonName( "models/field/units/" + info.data.name + ".skeleton" ); Ogre::MeshSerializer ser; ser.exportMesh( mesh.getPointer(), "exported/models/field/units/" + info.data.name + ".mesh" ); // create and export textures for model //if (textures.size() > 0) { Vram* vram = new Vram(); File* tex = new File( "./data/field/5/1b/2/4/1.tim" ); LoadTimFileToVram( tex, 0, vram ); delete tex; tex = new File( "./data/field/5/1b/2/4/2.tim" ); LoadTimFileToVram( tex, 0, vram ); delete tex; vram->Save( "1.jpg" ); CreateTexture( vram, info.data, "exported/models/field/units/" + info.data.name + ".png", textures ); delete vram; } CreateMaterial( "ffix/field_model/" + info.data.name, "exported/models/field/units/" + info.data.name + ".material", ( textures.size() > 0 ) ? "models/field/units/" + info.data.name + ".png" : "", "", "" ); Ogre::SceneManager* scene_manager = Ogre::Root::getSingleton().getSceneManager( "Scene" ); Ogre::Entity* thisEntity = scene_manager->createEntity( info.data.name, "models/field/units/" + info.data.name + ".mesh" ); //thisEntity->setDisplaySkeleton(true); //thisEntity->setDebugDisplayEnabled(true); thisEntity->setVisible( false ); thisEntity->getAnimationState( info.animations_name[ 0 ] )->setEnabled(true); thisEntity->getAnimationState( info.animations_name[ 0 ] )->setLoop(true); Ogre::SceneNode* thisSceneNode = scene_manager->getRootSceneNode()->createChildSceneNode(); thisSceneNode->setPosition( 0, 0, 0 ); thisSceneNode->roll( Ogre::Radian( Ogre::Degree( 180.0f ) ) ); thisSceneNode->yaw( Ogre::Radian( Ogre::Degree( 120.0f ) ) ); thisSceneNode->pitch( Ogre::Radian( Ogre::Degree(90.0f ) ) ); thisSceneNode->attachObject( thisEntity ); return thisEntity; }
void MilkshapePlugin::doExportAnimations(msModel* pModel, Ogre::SkeletonPtr& ogreskel) { Ogre::LogManager& logMgr = Ogre::LogManager::getSingleton(); std::vector<SplitAnimationStruct> splitInfo; Ogre::String msg; int numFrames = msModel_GetTotalFrames(pModel); msg = "Number of frames: " + Ogre::StringConverter::toString(numFrames); logMgr.logMessage(msg); if (splitAnimations) { // Explain msg = "You have chosen to create multiple discrete animations by splitting up the frames in " "the animation sequence. In order to do this, you must supply a simple text file " "describing the separate animations, which has a single line per animation in the format: \n\n" "startFrame,endFrame,animationName\n\nFor example: \n\n" "1,20,Walk\n21,35,Run\n36,40,Shoot\n\n" "..creates 3 separate animations (the frame numbers are inclusive)." "You must browse to this file in the next dialog."; MessageBox(0,msg.c_str(), "Splitting Animations",MB_ICONINFORMATION | MB_OK); // Prompt for a file which contains animation splitting info OPENFILENAME ofn; memset (&ofn, 0, sizeof (OPENFILENAME)); char szFile[MS_MAX_PATH]; char szFileTitle[MS_MAX_PATH]; char szDefExt[32] = "skeleton"; char szFilter[128] = "All Files (*.*)\0*.*\0\0"; szFile[0] = '\0'; szFileTitle[0] = '\0'; ofn.lStructSize = sizeof (OPENFILENAME); ofn.lpstrDefExt = szDefExt; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFile; ofn.nMaxFile = MS_MAX_PATH; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = MS_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; ofn.lpstrTitle = "Open animation split configuration file"; if (!::GetOpenFileName (&ofn)) { msg = "Splitting aborted, generating a single animation called 'Default'"; MessageBox(0, msg.c_str(), "Info", MB_OK | MB_ICONWARNING); SplitAnimationStruct split; split.start = 1; split.end = numFrames; split.name = "Default"; splitInfo.push_back(split); } else { // Read file Ogre::String sline; char line[256]; SplitAnimationStruct newSplit; std::ifstream istr; istr.open(szFile); while (!istr.eof()) { istr.getline(line, 256); sline = line; // Ignore blanks & comments if (sline == "" || sline.substr(0,2) == "//") continue; // Split on ',' std::vector<Ogre::String> svec = Ogre::StringUtil::split(line, ",\n"); // Basic validation on number of elements if (svec.size() != 3) { MessageBox(0, "Warning: corrupt animation details in file. You should look into this. ", "Corrupt animations file", MB_ICONWARNING | MB_OK); continue; } // Remove any embedded spaces Ogre::StringUtil::trim(svec[0]); Ogre::StringUtil::trim(svec[1]); Ogre::StringUtil::trim(svec[2]); // Create split info newSplit.start = atoi(svec[0].c_str()); newSplit.end = atoi(svec[1].c_str()); newSplit.name = svec[2]; splitInfo.push_back(newSplit); } } } else { // No splitting SplitAnimationStruct split; split.start = 1; split.end = numFrames; split.name = "Default"; splitInfo.push_back(split); } // Get animation length // Map frames -> seconds, this can be changed in speed of animation anyway int numBones = msModel_GetBoneCount(pModel); unsigned int frameTime; float realTime; std::vector<SplitAnimationStruct>::iterator animsIt; for (animsIt = splitInfo.begin(); animsIt != splitInfo.end(); ++animsIt) { SplitAnimationStruct& currSplit = *animsIt; // Create animation frameTime = currSplit.end - currSplit.start; realTime = frameTime / fps; Ogre::LogManager::getSingleton().stream() << "Trying to create Animation object for animation " << currSplit.name << " For Frames " << currSplit.start << " to " << currSplit.end << " inclusive. "; Ogre::LogManager::getSingleton().stream() << "Frame time = " << frameTime << ", Seconds = " << realTime; Ogre::Animation *ogreanim = ogreskel->createAnimation(currSplit.name, realTime); logMgr.logMessage("Animation object created."); int i; // Create all the animation tracks for (i = 0; i < numBones; ++i) { msBone* bone = msModel_GetBoneAt(pModel, i); Ogre::Bone* ogrebone = ogreskel->getBone(bone->szName); // Create animation tracks msg = "Creating AnimationTrack for bone " + Ogre::StringConverter::toString(i); logMgr.logMessage(msg); Ogre::NodeAnimationTrack *ogretrack = ogreanim->createNodeTrack(i, ogrebone); logMgr.logMessage("Animation track created."); // OGRE uses keyframes which are both position and rotation // Milkshape separates them, but never seems to use the ability to // have a different # of pos & rot keys int numKeys = msBone_GetRotationKeyCount(bone); msg = "Number of keyframes: " + Ogre::StringConverter::toString(numKeys); logMgr.logMessage(msg); int currKeyIdx; msPositionKey* currPosKey; msRotationKey* currRotKey; for (currKeyIdx = 0; currKeyIdx < numKeys; ++currKeyIdx ) { currPosKey = msBone_GetPositionKeyAt(bone, currKeyIdx); currRotKey = msBone_GetRotationKeyAt(bone, currKeyIdx); // Make sure keyframe is in current time frame (for splitting) if (currRotKey->fTime >= currSplit.start && currRotKey->fTime <= currSplit.end) { msg = "Creating KeyFrame #" + Ogre::StringConverter::toString(currKeyIdx) + " for bone #" + Ogre::StringConverter::toString(i); logMgr.logMessage(msg); // Create keyframe // Adjust for start time, and for the fact that frames are numbered from 1 frameTime = currRotKey->fTime - currSplit.start; realTime = frameTime / fps; Ogre::TransformKeyFrame *ogrekey = ogretrack->createNodeKeyFrame(realTime); logMgr.logMessage("KeyFrame created"); Ogre::Vector3 kfPos; // Imported milkshape animations may not have positions // for all rotation keys if ( currKeyIdx < bone->nNumPositionKeys ) { kfPos.x = currPosKey->Position[0]; kfPos.y = currPosKey->Position[1]; kfPos.z = currPosKey->Position[2]; } else { kfPos.x = bone->Position[0]; kfPos.y = bone->Position[1]; kfPos.z = bone->Position[2]; } Ogre::Quaternion qx, qy, qz, kfQ; // Milkshape translations are local to own orientation, not parent kfPos = ogrebone->getOrientation() * kfPos; ogrekey->setTranslate(kfPos); qx.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[0]), Ogre::Vector3::UNIT_X); qy.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[1]), Ogre::Vector3::UNIT_Y); qz.FromAngleAxis(Ogre::Radian(currRotKey->Rotation[2]), Ogre::Vector3::UNIT_Z); kfQ = qz * qy * qx; ogrekey->setRotation(kfQ); Ogre::LogManager::getSingleton().stream() << "KeyFrame details: Adjusted Frame Time=" << frameTime << " Seconds: " << realTime << " Position=" << kfPos << " " << "Ms3d Rotation= {" << currRotKey->Rotation[0] << ", " << currRotKey->Rotation[1] << ", " << currRotKey->Rotation[2] << "} " << "Orientation=" << kfQ; } // keyframe creation } // keys } //Bones } // Animations }
Ogre::SkeletonPtr MilkshapePlugin::doExportSkeleton(msModel* pModel, Ogre::MeshPtr& mesh) { Ogre::LogManager &logMgr = Ogre::LogManager::getSingleton(); Ogre::String msg; // // choose filename // OPENFILENAME ofn; memset (&ofn, 0, sizeof (OPENFILENAME)); char szFile[MS_MAX_PATH]; char szFileTitle[MS_MAX_PATH]; char szDefExt[32] = "skeleton"; char szFilter[128] = "OGRE .skeleton Files (*.skeleton)\0*.skeleton\0All Files (*.*)\0*.*\0\0"; szFile[0] = '\0'; szFileTitle[0] = '\0'; ofn.lStructSize = sizeof (OPENFILENAME); ofn.lpstrDefExt = szDefExt; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFile; ofn.nMaxFile = MS_MAX_PATH; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = MS_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; ofn.lpstrTitle = "Export to OGRE Skeleton"; if (!::GetSaveFileName (&ofn)) return Ogre::SkeletonPtr(); // Strip off the path Ogre::String skelName = szFile; size_t lastSlash = skelName.find_last_of("\\"); skelName = skelName.substr(lastSlash+1); // Set up logMgr.logMessage("Trying to create Skeleton object"); Ogre::SkeletonPtr ogreskel = Ogre::SkeletonManager::getSingleton().create(skelName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); logMgr.logMessage("Skeleton object created"); // Complete the details // Do the bones int numBones = msModel_GetBoneCount(pModel); msg = "Number of bones: " + Ogre::StringConverter::toString(numBones); logMgr.logMessage(msg); int i; // Create all the bones in turn for (i = 0; i < numBones; ++i) { msBone* bone = msModel_GetBoneAt(pModel, i); Ogre::Bone* ogrebone = ogreskel->createBone(bone->szName); msVec3 msBonePos, msBoneRot; msBone_GetPosition(bone, msBonePos); msBone_GetRotation(bone, msBoneRot); Ogre::Vector3 bonePos(msBonePos[0], msBonePos[1], msBonePos[2]); ogrebone->setPosition(bonePos); // Hmm, Milkshape has chosen a Euler angle representation of orientation which is not smart // Rotation Matrix or Quaternion would have been the smarter choice // Might we have Gimbal lock here? What order are these 3 angles supposed to be applied? // Grr, we'll try our best anyway... Ogre::Quaternion qx, qy, qz, qfinal; qx.FromAngleAxis(Ogre::Radian(msBoneRot[0]), Ogre::Vector3::UNIT_X); qy.FromAngleAxis(Ogre::Radian(msBoneRot[1]), Ogre::Vector3::UNIT_Y); qz.FromAngleAxis(Ogre::Radian(msBoneRot[2]), Ogre::Vector3::UNIT_Z); // Assume rotate by x then y then z qfinal = qz * qy * qx; ogrebone->setOrientation(qfinal); Ogre::LogManager::getSingleton().stream() << "Bone #" << i << ": " << "Name='" << bone->szName << "' " << "Position: " << bonePos << " " << "Ms3d Rotation: {" << msBoneRot[0] << ", " << msBoneRot[1] << ", " << msBoneRot[2] << "} " << "Orientation: " << qfinal; } // Now we've created all the bones, link them up logMgr.logMessage("Establishing bone hierarchy.."); for (i = 0; i < numBones; ++i) { msBone* bone = msModel_GetBoneAt(pModel, i); if (strlen(bone->szParentName) == 0) { // Root bone msg = "Root bone detected: Name='" + Ogre::String(bone->szName) + "' Index=" + Ogre::StringConverter::toString(i); logMgr.logMessage(msg); } else { Ogre::Bone* ogrechild = ogreskel->getBone(bone->szName); Ogre::Bone* ogreparent = ogreskel->getBone(bone->szParentName); if (ogrechild == 0) { msg = "Error: could not locate child bone '" + Ogre::String(bone->szName) + "'"; logMgr.logMessage(msg); continue; } if (ogreparent == 0) { msg = "Error: could not locate parent bone '" + Ogre::String(bone->szParentName) + "'"; logMgr.logMessage(msg); continue; } // Make child ogreparent->addChild(ogrechild); } } logMgr.logMessage("Bone hierarchy established."); // Create the Animation(s) doExportAnimations(pModel, ogreskel); // Create skeleton serializer & export Ogre::SkeletonSerializer serializer; msg = "Exporting skeleton to " + Ogre::String(szFile); logMgr.logMessage(msg); serializer.exportSkeleton(ogreskel.getPointer(), szFile); logMgr.logMessage("Skeleton exported"); msg = "Linking mesh to skeleton file '" + skelName + "'"; Ogre::LogManager::getSingleton().logMessage(msg); mesh->_notifySkeleton(ogreskel); return ogreskel; }
void MilkshapePlugin::doExportMesh(msModel* pModel) { // Create singletons Ogre::SkeletonManager skelMgr; Ogre::DefaultHardwareBufferManager defHWBufMgr; Ogre::LogManager& logMgr = Ogre::LogManager::getSingleton(); Ogre::MeshManager meshMgr; // // choose filename // OPENFILENAME ofn; memset (&ofn, 0, sizeof (OPENFILENAME)); char szFile[MS_MAX_PATH]; char szFileTitle[MS_MAX_PATH]; char szDefExt[32] = "mesh"; char szFilter[128] = "OGRE .mesh Files (*.mesh)\0*.mesh\0All Files (*.*)\0*.*\0\0"; szFile[0] = '\0'; szFileTitle[0] = '\0'; ofn.lStructSize = sizeof (OPENFILENAME); ofn.lpstrDefExt = szDefExt; ofn.lpstrFilter = szFilter; ofn.lpstrFile = szFile; ofn.nMaxFile = MS_MAX_PATH; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = MS_MAX_PATH; ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; ofn.lpstrTitle = "Export to OGRE Mesh"; if (!::GetSaveFileName (&ofn)) return /*0*/; logMgr.logMessage("Creating Mesh object..."); Ogre::MeshPtr ogreMesh = Ogre::MeshManager::getSingleton().create("export", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); logMgr.logMessage("Mesh object created."); bool foundBoneAssignment = false; // No shared geometry int i; int wh, numbones; int intweight[3], intbones[3]; size_t j; Ogre::Vector3 min, max, currpos; Ogre::Real maxSquaredRadius; bool first = true; for (i = 0; i < msModel_GetMeshCount (pModel); i++) { msMesh *pMesh = msModel_GetMeshAt (pModel, i); logMgr.logMessage("Creating SubMesh object..."); Ogre::SubMesh* ogreSubMesh = ogreMesh->createSubMesh(); logMgr.logMessage("SubMesh object created."); // Set material logMgr.logMessage("Getting SubMesh Material..."); int matIdx = msMesh_GetMaterialIndex(pMesh); if (matIdx == -1) { // No material, use blank ogreSubMesh->setMaterialName("BaseWhite"); logMgr.logMessage("No Material, using default 'BaseWhite'."); } else { msMaterial *pMat = msModel_GetMaterialAt(pModel, matIdx); ogreSubMesh->setMaterialName(pMat->szName); logMgr.logMessage("SubMesh Material Done."); } logMgr.logMessage("Setting up geometry..."); // Set up mesh geometry ogreSubMesh->vertexData = new Ogre::VertexData(); ogreSubMesh->vertexData->vertexCount = msMesh_GetVertexCount (pMesh); ogreSubMesh->vertexData->vertexStart = 0; Ogre::VertexBufferBinding* bind = ogreSubMesh->vertexData->vertexBufferBinding; Ogre::VertexDeclaration* decl = ogreSubMesh->vertexData->vertexDeclaration; // Always 1 texture layer, 2D coords #define POSITION_BINDING 0 #define NORMAL_BINDING 1 #define TEXCOORD_BINDING 2 decl->addElement(POSITION_BINDING, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION); decl->addElement(NORMAL_BINDING, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL); decl->addElement(TEXCOORD_BINDING, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES); // Create buffers Ogre::HardwareVertexBufferSharedPtr pbuf = Ogre::HardwareBufferManager::getSingleton(). createVertexBuffer(decl->getVertexSize(POSITION_BINDING), ogreSubMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC, false); Ogre::HardwareVertexBufferSharedPtr nbuf = Ogre::HardwareBufferManager::getSingleton(). createVertexBuffer(decl->getVertexSize(NORMAL_BINDING), ogreSubMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC, false); Ogre::HardwareVertexBufferSharedPtr tbuf = Ogre::HardwareBufferManager::getSingleton(). createVertexBuffer(decl->getVertexSize(TEXCOORD_BINDING), ogreSubMesh->vertexData->vertexCount, Ogre::HardwareBuffer::HBU_DYNAMIC, false); bind->setBinding(POSITION_BINDING, pbuf); bind->setBinding(NORMAL_BINDING, nbuf); bind->setBinding(TEXCOORD_BINDING, tbuf); ogreSubMesh->useSharedVertices = false; float* pPos = static_cast<float*>( pbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); logMgr.logMessage("Doing positions and texture coords..."); for (j = 0; j < ogreSubMesh->vertexData->vertexCount; ++j) { logMgr.logMessage("Doing vertex " + Ogre::StringConverter::toString(j)); msVertex *pVertex = msMesh_GetVertexAt (pMesh, (int)j); msVertexEx *pVertexEx=msMesh_GetVertexExAt(pMesh, (int)j); msVec3 Vertex; msVertex_GetVertex (pVertex, Vertex); *pPos++ = Vertex[0]; *pPos++ = Vertex[1]; *pPos++ = Vertex[2]; // Deal with bounds currpos = Ogre::Vector3(Vertex[0], Vertex[1], Vertex[2]); if (first) { min = max = currpos; maxSquaredRadius = currpos.squaredLength(); first = false; } else { min.makeFloor(currpos); max.makeCeil(currpos); maxSquaredRadius = std::max(maxSquaredRadius, currpos.squaredLength()); } int boneIdx = msVertex_GetBoneIndex(pVertex); if (boneIdx != -1) { foundBoneAssignment = true; numbones = 1; intbones[0] = intbones[1] = intbones[2] = -1; intweight[0] = intweight[1] = intweight[2] = 0; for(wh = 0; wh < 3; ++wh) { intbones[wh] = msVertexEx_GetBoneIndices(pVertexEx, wh); if(intbones[wh] == -1) break; ++numbones; intweight[wh] = msVertexEx_GetBoneWeights(pVertexEx, wh); } // for(k) Ogre::VertexBoneAssignment vertAssign; vertAssign.boneIndex = boneIdx; vertAssign.vertexIndex = (unsigned int)j; if(numbones == 1) { vertAssign.weight = 1.0; } // single assignment else { vertAssign.weight=(Ogre::Real)intweight[0]/100.0; } ogreSubMesh->addBoneAssignment(vertAssign); if(numbones > 1) { // this somewhat contorted logic is because the first weight [0] matches to the bone assignment // located with pVertex. The next two weights [1][2] match up to the first two bones found // with pVertexEx [0][1]. The weight for the fourth bone, if present, is the unassigned weight for(wh = 0; wh < 3; wh++) { boneIdx = intbones[wh]; if(boneIdx == -1) break; vertAssign.boneIndex = boneIdx; vertAssign.vertexIndex = (unsigned int)j; if(wh == 2) { // fourth weight is 1.0-(sumoffirstthreeweights) vertAssign.weight = 1.0-(((Ogre::Real)intweight[0]/100.0)+ ((Ogre::Real)intweight[1]/100.0)+((Ogre::Real)intweight[2]/100.0)); } else { vertAssign.weight=(Ogre::Real)intweight[wh+1]; } ogreSubMesh->addBoneAssignment(vertAssign); } // for(k) } // if(numbones) } } pbuf->unlock(); float* pTex = static_cast<float*>( tbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); logMgr.logMessage("Doing uvs, normals and indexes (v2)..."); // Aargh, Milkshape uses stupid separate normal indexes for the same vertex like 3DS // Normals aren't described per vertex but per triangle vertex index // Pain in the arse, we have to do vertex duplication again if normals differ at a vertex (non smooth) // WHY don't people realise this format is a pain for passing to 3D APIs in vertex buffers? float* pNorm = static_cast<float*>( nbuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); ogreSubMesh->indexData->indexCount = msMesh_GetTriangleCount (pMesh) * 3; // Always use 16-bit buffers, Milkshape can't handle more anyway Ogre::HardwareIndexBufferSharedPtr ibuf = Ogre::HardwareBufferManager::getSingleton(). createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT, ogreSubMesh->indexData->indexCount, Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); ogreSubMesh->indexData->indexBuffer = ibuf; unsigned short *pIdx = static_cast<unsigned short*>( ibuf->lock(Ogre::HardwareBuffer::HBL_DISCARD)); for (j = 0; j < ogreSubMesh->indexData->indexCount; j+=3) { msTriangle *pTriangle = msMesh_GetTriangleAt (pMesh, (int)j/3); msTriangleEx *pTriangleEx=msMesh_GetTriangleExAt(pMesh, (int)j/3); word nIndices[3]; msTriangle_GetVertexIndices (pTriangle, nIndices); msVec3 Normal; msVec2 uv; int k, vertIdx; for (k = 0; k < 3; ++k) { vertIdx = nIndices[k]; // Face index pIdx[j+k] = vertIdx; // Vertex normals // For the moment, ignore any discrepancies per vertex msTriangleEx_GetNormal(pTriangleEx, k, &Normal[0]); msTriangleEx_GetTexCoord(pTriangleEx, k, &uv[0]); pTex[(vertIdx*2)]=uv[0]; pTex[(vertIdx*2)+1]=uv[1]; pNorm[(vertIdx*3)] = Normal[0]; pNorm[(vertIdx*3)+1] = Normal[1]; pNorm[(vertIdx*3)+2] = Normal[2]; } } // Faces nbuf->unlock(); ibuf->unlock(); tbuf->unlock(); // Now use Ogre's ability to reorganise the vertex buffers the best way Ogre::VertexDeclaration* newDecl = ogreSubMesh->vertexData->vertexDeclaration->getAutoOrganisedDeclaration( foundBoneAssignment, false); Ogre::BufferUsageList bufferUsages; for (size_t u = 0; u <= newDecl->getMaxSource(); ++u) bufferUsages.push_back(Ogre::HardwareBuffer::HBU_STATIC_WRITE_ONLY); ogreSubMesh->vertexData->reorganiseBuffers(newDecl, bufferUsages); logMgr.logMessage("Geometry done."); } // SubMesh // Set bounds ogreMesh->_setBoundingSphereRadius(Ogre::Math::Sqrt(maxSquaredRadius)); ogreMesh->_setBounds(Ogre::AxisAlignedBox(min, max), false); // Keep hold of a Skeleton pointer for deletion later // Mesh uses Skeleton pointer for skeleton name Ogre::SkeletonPtr pSkel; if (exportSkeleton && foundBoneAssignment) { // export skeleton, also update mesh to point to it pSkel = doExportSkeleton(pModel, ogreMesh); } else if (!exportSkeleton && foundBoneAssignment) { // We've found bone assignments, but skeleton is not to be exported // Prompt the user to find the skeleton if (!locateSkeleton(ogreMesh)) return; } // Export logMgr.logMessage("Creating MeshSerializer.."); Ogre::MeshSerializer serializer; logMgr.logMessage("MeshSerializer created."); // Generate LODs if required if (generateLods) { // Build LOD depth list Ogre::Mesh::LodDistanceList distList; float depth = 0; for (unsigned short depthidx = 0; depthidx < numLods; ++depthidx) { depth += lodDepthIncrement; distList.push_back(depth); } ogreMesh->generateLodLevels(distList, lodReductionMethod, lodReductionAmount); } if (generateEdgeLists) { ogreMesh->buildEdgeList(); } if (generateTangents) { unsigned short src, dest; ogreMesh->suggestTangentVectorBuildParams(tangentSemantic, src, dest); ogreMesh->buildTangentVectors(tangentSemantic, src, dest, tangentsSplitMirrored, tangentsSplitRotated, tangentsUseParity); } // Export Ogre::String msg; msg = "Exporting mesh data to file '" + Ogre::String(szFile) + "'"; logMgr.logMessage(msg); serializer.exportMesh(ogreMesh.getPointer(), szFile); logMgr.logMessage("Export successful"); Ogre::MeshManager::getSingleton().remove(ogreMesh->getHandle()); if (!pSkel.isNull()) Ogre::SkeletonManager::getSingleton().remove(pSkel->getHandle()); if (exportMaterials && msModel_GetMaterialCount(pModel) > 0) { doExportMaterials(pModel); } }
//--------------------------------------------------------------------- void OptimiseTool::processSkeleton(Ogre::SkeletonPtr skeleton) { skeleton->optimiseAllAnimations(mKeepIdentityTracks); }
bool EC_Mesh::SetMeshWithSkeleton(const std::string& mesh_name, const std::string& skeleton_name, bool clone) { if (!ViewEnabled()) return false; OgreWorldPtr world = world_.lock(); Ogre::SkeletonPtr skel = Ogre::SkeletonManager::getSingleton().getByName(AssetAPI::SanitateAssetRef(skeleton_name)); if (skel.isNull()) { LogError("EC_Mesh::SetMeshWithSkeleton: Could not set skeleton " + skeleton_name + " to mesh " + mesh_name + ": not found"); return false; } RemoveMesh(); Ogre::SceneManager* sceneMgr = world->OgreSceneManager(); Ogre::Mesh* mesh = PrepareMesh(mesh_name, clone); if (!mesh) return false; try { mesh->_notifySkeleton(skel); // LogDebug("Set skeleton " + skeleton_name + " to mesh " + mesh_name); } catch(Ogre::Exception& e) { LogError("EC_Mesh::SetMeshWithSkeleton: Could not set skeleton " + skeleton_name + " to mesh " + mesh_name + ": " + std::string(e.what())); return false; } try { entity_ = sceneMgr->createEntity(world->GetUniqueObjectName("EC_Mesh_entwithskel"), mesh->getName()); if (!entity_) { LogError("EC_Mesh::SetMeshWithSkeleton: Could not set mesh " + mesh_name); return false; } entity_->setRenderingDistance(drawDistance.Get()); entity_->setCastShadows(castShadows.Get()); entity_->setUserAny(Ogre::Any(static_cast<IComponent *>(this))); // Set UserAny also on subentities for(uint i = 0; i < entity_->getNumSubEntities(); ++i) entity_->getSubEntity(i)->setUserAny(entity_->getUserAny()); if (entity_->hasSkeleton()) { Ogre::SkeletonInstance* skel = entity_->getSkeleton(); // Enable cumulative mode on skeletal animations if (skel) skel->setBlendMode(Ogre::ANIMBLEND_CUMULATIVE); } } catch(Ogre::Exception& e) { LogError("EC_Mesh::SetMeshWithSkeleton: Could not set mesh " + mesh_name + ": " + std::string(e.what())); return false; } AttachEntity(); emit MeshChanged(); return true; }
void CSceletalAnimationView::EngineSetup(void) { Ogre::Root *Root = ((CSceletalAnimationApp*)AfxGetApp())->m_Engine->GetRoot(); Ogre::SceneManager *SceneManager = NULL; SceneManager = Root->createSceneManager(Ogre::ST_GENERIC, "Animation"); // // Create a render window // This window should be the current ChildView window using the externalWindowHandle // value pair option. // Ogre::NameValuePairList parms; parms["externalWindowHandle"] = Ogre::StringConverter::toString((long)m_hWnd); parms["vsync"] = "true"; CRect rect; GetClientRect(&rect); Ogre::RenderTarget *RenderWindow = Root->getRenderTarget("Mouse Input"); if (RenderWindow == NULL) { try { m_RenderWindow = Root->createRenderWindow("Mouse Input", rect.Width(), rect.Height(), false, &parms); } catch(...) { MessageBox("Cannot initialize\nCheck that graphic-card driver is up-to-date", "Initialize Render System", MB_OK | MB_ICONSTOP); exit(EXIT_SUCCESS); } } // Load resources Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); // Create the camera m_Camera = SceneManager->createCamera("Camera"); m_Camera->setNearClipDistance(0.5); m_Camera->setFarClipDistance(5000); m_Camera->setCastShadows(false); m_Camera->setUseRenderingDistance(true); m_Camera->setPosition(Ogre::Vector3(5.0, 5.0, 10.0)); Ogre::SceneNode *CameraNode = NULL; CameraNode = SceneManager->getRootSceneNode()->createChildSceneNode("CameraNode"); Ogre::Viewport* Viewport = NULL; if (0 == m_RenderWindow->getNumViewports()) { Viewport = m_RenderWindow->addViewport(m_Camera); Viewport->setBackgroundColour(Ogre::ColourValue(0.8f, 0.8f, 0.8f)); } // Alter the camera aspect ratio to match the viewport m_Camera->setAspectRatio(Ogre::Real(rect.Width()) / Ogre::Real(rect.Height())); m_Camera->lookAt(Ogre::Vector3(0.5, 0.5, 0.5)); m_Camera->setPolygonMode(Ogre::PolygonMode::PM_WIREFRAME); Ogre::ManualObject* ManualObject = NULL; ManualObject = SceneManager->createManualObject("Animation"); ManualObject->setDynamic(false); ManualObject->begin("BaseWhiteNoLighting", Ogre::RenderOperation::OT_TRIANGLE_LIST); //face 1 ManualObject->position(0, 0, 0);//0 ManualObject->position(1, 0, 0);//1 ManualObject->position(1, 1, 0);//2 ManualObject->triangle(0, 1, 2);//3 ManualObject->position(0, 0, 0);//4 ManualObject->position(1, 1, 0);//5 ManualObject->position(0, 1, 0);//6 ManualObject->triangle(3, 4, 5);//7 //face 2 ManualObject->position(0, 0, 1);//8 ManualObject->position(1, 0, 1);//9 ManualObject->position(1, 1, 1);//10 ManualObject->triangle(6, 7, 8);//11 ManualObject->position(0, 0, 1);//12 ManualObject->position(1, 1, 1);//13 ManualObject->position(0, 1, 1);//14 ManualObject->triangle(9, 10, 11);//15 //face 3 ManualObject->position(0, 0, 0);//16 ManualObject->position(1, 0, 0);//17 ManualObject->position(1, 0, 1);//18 ManualObject->triangle(12, 13, 14);//19 ManualObject->position(0, 0, 0); ManualObject->position(1, 0, 1); ManualObject->position(0, 1, 1); ManualObject->triangle(15, 16, 17); //face 4 ManualObject->position(1, 0, 0); ManualObject->position(1, 1, 0); ManualObject->position(1, 1, 1); ManualObject->triangle(18, 19, 20); ManualObject->position(1, 0, 0); ManualObject->position(1, 1, 1); ManualObject->position(1, 0, 1); ManualObject->triangle(21, 22, 23); //face 5 ManualObject->position(0, 1, 0); ManualObject->position(1, 1, 0); ManualObject->position(0, 1, 1); ManualObject->triangle(24, 25, 26); ManualObject->position(1, 1, 0); ManualObject->position(1, 1, 1); ManualObject->position(0, 1, 1); ManualObject->triangle(27, 28, 29); //face 6 ManualObject->position(0, 0, 0); ManualObject->position(0, 1, 1); ManualObject->position(0, 0, 1); ManualObject->triangle(30, 31, 32); ManualObject->position(0, 0, 0); ManualObject->position(0, 1, 0); ManualObject->position(0, 1, 1); ManualObject->triangle(33, 34, 35); ManualObject->end(); Ogre::MeshPtr MeshPtr = ManualObject->convertToMesh("Animation"); Ogre::SubMesh* sub = MeshPtr->getSubMesh(0); Ogre::SkeletonPtr Skeleton = Ogre::SkeletonManager::getSingleton().create("Skeleton", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); MeshPtr.getPointer()->_notifySkeleton(Skeleton); Ogre::Bone *Root1 = NULL; Ogre::Bone *Child1 = NULL; Ogre::Bone *Child2 = NULL; Root1 = Skeleton.getPointer()->createBone("Root"); Root1->setPosition(Ogre::Vector3(0.0, 0.0, 0.0)); Root1->setOrientation(Ogre::Quaternion::IDENTITY); Child1 = Root1->createChild(1); Child1->setPosition(Ogre::Vector3(4.0, 0.0, 0.0)); Child1->setOrientation(Ogre::Quaternion::IDENTITY); Child2 = Root1->createChild(2); Child2->setPosition(Ogre::Vector3(5.0, 0.0, 0.0)); Child2->setOrientation(Ogre::Quaternion::IDENTITY); Ogre::VertexBoneAssignment Assignment; Assignment.boneIndex = 0; Assignment.vertexIndex = 0; Assignment.weight = 1.0; Skeleton->setBindingPose(); sub->addBoneAssignment(Assignment); Assignment.vertexIndex = 1; sub->addBoneAssignment(Assignment); Assignment.vertexIndex = 2; sub->addBoneAssignment(Assignment); Ogre::Animation *Animation = MeshPtr->createAnimation("HandAnimation", 100.0); Ogre::NodeAnimationTrack *Track = Animation->createNodeTrack(0, Root1); Ogre::TransformKeyFrame *KeyFrame = NULL; for (float FrameTime = 0.0; FrameTime < 100.0; FrameTime += 0.1) { KeyFrame = Track->createNodeKeyFrame(FrameTime); KeyFrame->setTranslate(Ogre::Vector3(10.0, 0.0, 0.0)); } Root1->setManuallyControlled(true); Child1->setManuallyControlled(true); Child2->setManuallyControlled(true); MeshPtr->load(); MeshPtr.getPointer()->_notifySkeleton(Skeleton); // Ogre::SkeletonSerializer skeletonSerializer; // skeletonSerializer.exportSkeleton(Skeleton.get(), "C:\\Users\\Ilya\\Documents\\Visual Studio 2010\\Projects\\Recipes\\media\\models\\testskeleton.skeleton"); // Ogre::MeshSerializer ser; // ser.exportMesh(MeshPtr.get(), "C:\\Users\\Ilya\\Documents\\Visual Studio 2010\\Projects\\Recipes\\media\\models\\testskeleton.mesh"); Ogre::Entity *Entity = SceneManager->createEntity("Animation", "Animation"/*"testskeleton.mesh"*/); Ogre::SceneNode *SceneNode = SceneManager->getRootSceneNode()->createChildSceneNode(); SceneNode->attachObject(Entity); Entity->setDisplaySkeleton(true); m_AnimationState = Entity->getAnimationState("HandAnimation"); m_AnimationState->setEnabled(true); m_AnimationState->setLoop(true); m_Camera->setPolygonMode(Ogre::PolygonMode::PM_WIREFRAME); Root->renderOneFrame(); }
Ogre::Entity* StageFile::GetModel( const StageInfo& info ) { //DumpSettings("exported/" + info.data.name + ".lua"); VectorTexForGen textures; Ogre::MeshPtr mesh = Ogre::MeshManager::getSingleton().create(info.data.name + "export", "General"); Ogre::SkeletonPtr skeleton = Ogre::SkeletonManager::getSingleton().create(info.data.name + "export", "General"); u32 number_of_files = GetU32LE(0); LOGGER->Log("Number of file " + IntToString(number_of_files) + "\n"); Ogre::Bone* root1 = skeleton->createBone( "0", 0 ); Ogre::Bone* root2 = skeleton->createBone( "1", 1 ); root1->addChild( root2 ); Ogre::Animation* anim = skeleton->createAnimation( "Idle", 1 ); Ogre::NodeAnimationTrack* track1 = anim->createNodeTrack( 0, root1 ); track1->removeAllKeyFrames(); Ogre::TransformKeyFrame* frame1 = track1->createNodeKeyFrame( 0 ); Ogre::Matrix3 matrix; matrix.FromEulerAnglesYXZ( Ogre::Radian( Ogre::Degree( 0 ) ), Ogre::Radian( Ogre::Degree( -90 ) ), Ogre::Radian( Ogre::Degree( 0 ) ) ); Ogre::Quaternion rot; rot.FromRotationMatrix( matrix ); frame1->setRotation( rot ); for (u32 i = 1; i < number_of_files - 1; ++i) { int offset_to_vertex = GetU32LE(0x04 + i * 0x04); MeshExtractor(info.data, "ffvii/battle_stage/" + info.data.name, this, offset_to_vertex, textures, mesh, Ogre::StringConverter::toString(i), 1); } // <OGRE> /////////////////////////////// skeleton->optimiseAllAnimations(); Ogre::SkeletonSerializer skeleton_serializer; skeleton_serializer.exportSkeleton(skeleton.getPointer(), "exported/models/ffvii/battle/stages/" + info.data.name + ".skeleton"); // Update bounds Ogre::AxisAlignedBox aabb(-999, -999, -999, 999, 999, 999); mesh->_setBounds(aabb, false); mesh->_setBoundingSphereRadius(999); mesh->setSkeletonName( "models/ffvii/battle/stages/" + info.data.name + ".skeleton" ); Ogre::MeshSerializer ser; ser.exportMesh(mesh.getPointer(), "exported/models/ffvii/battle/stages/" + info.data.name + ".mesh"); // create and export textures for model if( textures.size() > 0 ) { int number_of_files = GetU32LE( 0x00 ); int offset_to_texture = GetU32LE( number_of_files * 0x04 ); Vram* vram = Vram::MakeInstance().release(); LoadTimFileToVram( this, offset_to_texture, vram ); //vram->Save( "qqq" ); CreateTexture( vram, info.data, "exported/models/ffvii/battle/stages/" + info.data.name + ".png", textures ); delete vram; } CreateMaterial("ffvii/battle_stage/" + info.data.name, "exported/models/ffvii/battle/stages/" + info.data.name + ".material", "models/ffvii/battle/stages/" + info.data.name + ".png", "", ""); Ogre::SceneManager* scene_manager = Ogre::Root::getSingleton().getSceneManager( "Scene" ); Ogre::Entity* thisEntity = scene_manager->createEntity( info.data.name, "models/ffvii/battle/stages/" + info.data.name + ".mesh" ); //thisEntity->setDisplaySkeleton(true); //thisEntity->setDebugDisplayEnabled(true); thisEntity->setVisible(false); thisEntity->getAnimationState( "Idle" )->setEnabled( true ); thisEntity->getAnimationState( "Idle" )->setLoop( true ); Ogre::SceneNode* thisSceneNode = scene_manager->getRootSceneNode()->createChildSceneNode(); thisSceneNode->setPosition( 0, 0, 0 ); thisSceneNode->roll( Ogre::Radian( Ogre::Degree( 180.0f ) ) ); thisSceneNode->yaw( Ogre::Radian( Ogre::Degree( 120.0f ) ) ); thisSceneNode->pitch( Ogre::Radian( Ogre::Degree( 90.0f ) ) ); thisSceneNode->attachObject( thisEntity ); return thisEntity; }