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; }
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(); }
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(); }
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(); }
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(); } }
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; }
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); }
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 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); } }