void LodManager::loadLod(Ogre::MeshPtr mesh, const LodDefinition& def) { if (def.getUseAutomaticLod()) { loadAutomaticLod(mesh); } else if (def.getLodDistanceCount() == 0) { mesh->removeLodLevels(); return; } else { Ogre::LodStrategy* strategy; if (def.getStrategy() == LodDefinition::LS_DISTANCE) { strategy = &Ogre::DistanceLodStrategy::getSingleton(); } else { strategy = &Ogre::PixelCountLodStrategy::getSingleton(); } mesh->setLodStrategy(strategy); if (def.getType() == LodDefinition::LT_AUTOMATIC_VERTEX_REDUCTION) { // Automatic vertex reduction LodConfig lodConfig; lodConfig.mesh = mesh; const LodDefinition::LodDistanceMap& data = def.getManualLodData(); if (def.getStrategy() == LodDefinition::LS_DISTANCE) { // TODO: Use C++11 lambda, instead of template. loadAutomaticLodImpl(data.begin(), data.end(), lodConfig); } else { loadAutomaticLodImpl(data.rbegin(), data.rend(), lodConfig); } // Uncomment the ProgressiveMesh of your choice. // NOTE: OgreProgressiveMeshExt doesn't support collapse cost based reduction. // OgreProgressiveMeshExt pm; // ProgressiveMeshGenerator pm; QueuedProgressiveMeshGenerator pm; pm.build(lodConfig); } else { // User created Lod mesh->removeLodLevels(); const LodDefinition::LodDistanceMap& data = def.getManualLodData(); if (def.getStrategy() == LodDefinition::LS_DISTANCE) { // TODO: Use C++11 lambda, instead of template. loadUserLodImpl(data.begin(), data.end(), mesh.get()); } else { loadUserLodImpl(data.rbegin(), data.rend(), mesh.get()); } } } }
void XMLLodDefinitionSerializer::importLodDefinition(const Ogre::DataStreamPtr& stream, LodDefinition& lodDef) const { TiXmlDocument xmlDoc; XMLHelper xmlHelper; if (!xmlHelper.Load(xmlDoc, stream)) { return; } // <lod>...</lod> TiXmlElement* rootElem = xmlDoc.RootElement(); if (rootElem) { // <automatic enabled="true|false" /> TiXmlElement* autElem = rootElem->FirstChildElement("automatic"); if (autElem) { const char* tmp = autElem->Attribute("enabled"); if (tmp) { lodDef.setUseAutomaticLod(Ogre::StringConverter::parseBool(tmp, true)); } } // <manual>...</manual> TiXmlElement* manElem = rootElem->FirstChildElement("manual"); if (manElem) { // <type>user|automatic</type> TiXmlElement* elem = manElem->FirstChildElement("type"); if (elem) { const char* tmp = elem->GetText(); if (tmp && strcmp(tmp, "automatic") == 0) { lodDef.setType(LodDefinition::LT_AUTOMATIC_VERTEX_REDUCTION); } else { lodDef.setType(LodDefinition::LT_USER_CREATED_MESH); } } // <strategy>distance|pixelcount</strategy> elem = manElem->FirstChildElement("strategy"); if (elem) { const char* tmp = elem->GetText(); if (tmp && strcmp(tmp, "distance") == 0) { lodDef.setStrategy(LodDefinition::LS_DISTANCE); } else { lodDef.setStrategy(LodDefinition::LS_PIXEL_COUNT); } } // <level>...</level> <level>...</level> <level>...</level> for (TiXmlElement* distElem = manElem->FirstChildElement("level"); distElem != 0; distElem = distElem->NextSiblingElement("level")) { LodDistance dist; if (lodDef.getType() == LodDefinition::LT_USER_CREATED_MESH) { // <meshName>.../test.mesh</meshName> elem = distElem->FirstChildElement("meshName"); if (elem) { const char* tmp = elem->GetText(); bool isValidMeshName = Ogre::ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(tmp); if (tmp && isValidMeshName) { dist.setMeshName(tmp); } else { S_LOG_FAILURE( lodDef.getName() << " contains invalid mesh name for user created lod level. Skipping lod level for distance " << distElem->Attribute("distance")); continue; } } } else { // <method>constant|proportional</method> elem = distElem->FirstChildElement("method"); if (elem) { const char* tmp = elem->GetText(); if (tmp) { if (strcmp(tmp, "constant") == 0) { dist.setReductionMethod(Ogre::LodLevel::VRM_CONSTANT); } else if (strcmp(tmp, "proportional") == 0) { dist.setReductionMethod(Ogre::LodLevel::VRM_PROPORTIONAL); } else { dist.setReductionMethod(Ogre::LodLevel::VRM_COLLAPSE_COST); } } else { dist.setReductionMethod(Ogre::LodLevel::VRM_PROPORTIONAL); } } // <value>0.5</value> elem = distElem->FirstChildElement("value"); if (elem) { const char* tmp = elem->GetText(); if (tmp) { dist.setReductionValue(Ogre::StringConverter::parseReal(tmp)); } } } // <level distance="10">...</level> const char* distVal = distElem->Attribute("distance"); if (distVal) { lodDef.addLodDistance(Ogre::StringConverter::parseReal(distVal), dist); } } } } }