第一部分都是做些准备,这一部分就是主力了:int COgitorsSceneSerializer::Import(Ogre::String importfile)
采用代码加注释的方式结合具体的函数探索它。
int COgitorsSceneSerializer::Import(Ogre::String importfile)
{
OgitorsRoot *ogRoot = OgitorsRoot::getSingletonPtr();
OgitorsSystem *mSystem = OgitorsSystem::getSingletonPtr();
if(importfile == "")
{
UTFStringVector extlist;
//#define OTR(a) mSystem->Translate(a) 以后记住这个宏
extlist.push_back(OTR("Ogitor Scene File"));
extlist.push_back("*.ogscene"); //相当于过滤器
//就是显示打开场景文件对话框,见下面 1
importfile = mSystem->DisplayOpenDialog(OTR("Open"),extlist);
if(importfile == "")
return SCF_CANCEL;
}
Ogre::String filePath = OgitorsUtils::ExtractFilePath(importfile);
Ogre::String fileName = OgitorsUtils::ExtractFileName(importfile);
PROJECTOPTIONS *pOpt = ogRoot->GetProjectOptions();
pOpt->CreatedIn = "";
if(filePath.find(".") == 0)
{
filePath = OgitorsUtils::GetExePath() + filePath;
filePath = OgitorsUtils::QualifyPath(filePath);
}
pOpt->ProjectDir = filePath;
int typepos = fileName.find_last_of(".");
pOpt->ProjectName = fileName;
if(typepos != -1)
pOpt->ProjectName.erase(typepos,pOpt->ProjectName.length() - typepos);
bool testpassed = false; //这里进行目录文件测试,防止只读目录
try
{
std::ofstream test((filePath + "test.dat").c_str());
if(test.is_open())
testpassed = true;
test.close();
mSystem->DeleteFile(filePath + "test.dat");
}
catch(...)
{
testpassed = false;
}
if(!testpassed)
{
mSystem->DisplayMessageDialog("The path is Read-Only. Ogitor can not work with Read-Only Project Paths!", DLGTYPE_OK);
return SCF_CANCEL;
}
//真正开始解析项目文件XML了,采用tinyXml
TiXmlDocument docImport((filePath + fileName).c_str());
Ogre::UTFString loadmsg = mSystem->Translate("Parsing Scene File");
mSystem->UpdateLoadProgress(1, loadmsg);
if(!docImport.LoadFile())
return SCF_ERRFILE;
TiXmlNode* node = 0;
TiXmlElement* element = 0;
node = docImport.FirstChild("OGITORSCENE");
if(!node)
return SCF_ERRPARSE;
element = node->ToElement();
int version = Ogre::StringConverter::parseInt(ValidAttr(element->Attribute("version"),"1"));
if(version == 1)
return ImportV1(element); //这种版本实际OGITOR并不支持,费码
node = node->FirstChild("PROJECT");
if(node)
{
loadmsg = mSystem->Translate("Parsing project options");
mSystem->UpdateLoadProgress(5, loadmsg);
ogRoot->LoadProjectOptions(node->ToElement()); //项目设置数据
ogRoot->PrepareProjectResources(); // 资源的准备
}
//这里开始解析Viewport Light Entity等信息
//只是这里从头开始——OGITORSCENE,根据object_id parentnode name typename解析
//只是object_id parentnode 是可选项,name typename 是必选项,必选项如果没有就continue
node = docImport.FirstChild("OGITORSCENE");
if(!node)
return SCF_ERRPARSE;
element = node->FirstChildElement();
loadmsg = mSystem->Translate("Creating scene objects");
mSystem->UpdateLoadProgress(10, loadmsg);
unsigned int obj_count = 0;
Ogre::String objecttype;
OgitorsPropertyValueMap params;
OgitorsPropertyValue tmpPropVal;
do
{
// Make sure its NON-ZERO
if(pOpt->ObjectCount)
{
++obj_count;
mSystem->UpdateLoadProgress(10 + ((obj_count * 70) / pOpt->ObjectCount), loadmsg);
}
params.clear();
Ogre::String objAttValue;
objAttValue = ValidAttr(element->Attribute("object_id"), "");
if(objAttValue != "")
{
tmpPropVal.propType = PROP_UNSIGNED_INT;
tmpPropVal.val = Ogre::Any(Ogre::StringConverter::parseUnsignedInt(objAttValue));
params.insert(OgitorsPropertyValueMap::value_type("object_id", tmpPropVal));
}
objAttValue = ValidAttr(element->Attribute("parentnode"),"");
if(objAttValue != "")
{
tmpPropVal.propType = PROP_STRING;
tmpPropVal.val = Ogre::Any(objAttValue);
params.insert(OgitorsPropertyValueMap::value_type("parentnode", tmpPropVal));
}
objAttValue = ValidAttr(element->Attribute("name"),"");
if(objAttValue != "")
{
tmpPropVal.propType = PROP_STRING;
tmpPropVal.val = Ogre::Any(objAttValue);
params.insert(OgitorsPropertyValueMap::value_type("name", tmpPropVal));
}
else
continue;
objAttValue = ValidAttr(element->Attribute("typename"),"");
if(objAttValue != "")
{
tmpPropVal.propType = PROP_STRING;
tmpPropVal.val = Ogre::Any(objAttValue);
params.insert(OgitorsPropertyValueMap::value_type("typename", tmpPropVal));
}
else
continue;
TiXmlElement *properties = element->FirstChildElement();
if(properties)
{
Ogre::String elementName;
do
{
elementName = properties->Value();
if(elementName != "PROPERTY")
continue;
Ogre::String attID = ValidAttr(properties->Attribute("id"),"");
int attType = Ogre::StringConverter::parseInt(ValidAttr(properties->Attribute("type"),""));
Ogre::String attValue = ValidAttr(properties->Attribute("value"),"");
params.insert(OgitorsPropertyValueMap::value_type(attID, OgitorsPropertyValue::createFromString((OgitorsPropertyType)attType, attValue)));
} while(properties = properties->NextSiblingElement());
}
objecttype = Ogre::any_cast<Ogre::String>(params["typename"].val);
//这里创建相关的属性,还不是太明白,探索之 见 2
CBaseEditor *result = ogRoot->CreateEditorObject(0, objecttype, params, false, false);
if(result)
{
TiXmlElement *customprop = element->FirstChildElement("CUSTOMPROPERTIES");
if(customprop)
{
OgitorsUtils::ReadCustomPropertySet(customprop, result->getCustomProperties());
}
}
} while(element = element->NextSiblingElement());
ogRoot->AfterLoadScene();
return SCF_OK;
}
1、 importfile = mSystem->DisplayOpenDialog(OTR("Open"),extlist); 设置打开文件对话框过滤器,并设置注册表中保存路径文件名。
并把完整路径名保存在注册表,以备下次取出。
Ogre::String QtOgitorSystem::DisplayOpenDialog(Ogre::UTFString title, Ogitors::UTFStringVector ExtensionList) { QSettings settings; QString theList; QString selectedFilter; QString oldOpenPath; for(unsigned int i = 0; i < ExtensionList.size(); i+=2) { if(i) theList += QString(";;"); theList += ConvertToQString(ExtensionList[i]) + QString(" (") + ConvertToQString(ExtensionList[i + 1]) + QString(")"); } settings.beginGroup("OgitorSystem"); if( theList.contains("xml", Qt::CaseInsensitive) || theList.contains(".scene", Qt::CaseInsensitive) ) { oldOpenPath = settings.value("oldDotsceneOpenPath", mProjectsDirectory).toString(); selectedFilter = settings.value("selectedDotsceneOpenFilter", "").toString(); } else { oldOpenPath = settings.value("oldOpenPath", mProjectsDirectory).toString(); } settings.endGroup(); //oldOpenPath: 是路径,但是实际上是完整的目录文件名。如:F:/ogre173/ogitorTest/second/test2.ogscene //QT帮助文档:The file dialog's working directory will be set to dir. //If dir includes a file name, the file will be selected //theList:是输入的选择过滤器,例如:Ogitor场景文件 (*.ogscene) //selectedFilter: 是输出的过滤器,在此例中和 theList 一样,应该是在多选过滤器之后返回的选择过滤器(估计) QString path = QFileDialog::getOpenFileName(QApplication::activeWindow(), ConvertToQString(title), oldOpenPath, theList , &selectedFilter #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX , QFileDialog::DontUseNativeDialog ); #else ); #endif if(path != "") { settings.beginGroup("OgitorSystem"); if((theList.contains("xml", Qt::CaseInsensitive))&&(theList.contains(".scene", Qt::CaseInsensitive))) { settings.setValue("oldDotsceneOpenPath", path); settings.setValue("selectedDotsceneOpenFilter", selectedFilter); } else { settings.setValue("oldOpenPath", path); } settings.endGroup(); } return path.toStdString(); }
2、原始注释 Creates an editor object using registered factory,不明白,探索之
CBaseEditor *OgitorsRoot::CreateEditorObject(CBaseEditor *parent, const Ogre::String objecttypestring, OgitorsPropertyValueMap ¶ms,bool addtotreelist, bool display) { if(parent == 0) { OgitorsPropertyValueMap::const_iterator ni; if ((ni = params.find("parentnode")) != params.end()) { parent = FindObject(Ogre::any_cast<Ogre::String>(ni->second.val)); } if(!parent) { if(GetSceneManager() == 0) parent = mRootEditor; //第一次打开文件的时候, CBaseEditor是SceneManager的parent else parent = GetSceneManagerEditor(); } } //这里应该是工厂模式了,获取相应的EditorFactory CBaseEditorFactory *factory = GetEditorObjectFactory(objecttypestring); if(!factory) return 0; //对应的工厂创建需要的Editor。见下面2.1 CBaseEditor *object = factory->CreateObject(&parent, params); if(!object) return 0; if(object->getObjectID() == 0) object->setObjectID(GetUniqueObjectID(object)); else AddObjectID(object->getObjectID(), object); RegisterObjectName(object->getName(), object); parent->_addChild(object); if(addtotreelist) { mSystem->InsertTreeItem(parent,object,object->getTypeID(),object->getTextColourInt()); } if(parent->getLocked()) object->setLocked(true); if(display) { object->load(); mMultiSelection->setSelection(object); } object->getProperties()->addListener(&GlobalOgitorsRootPropertySetListener); object->getCustomProperties()->addListener(&GlobalOgitorsRootPropertySetListener); object->getProperties()->addListener(mUndoManager); object->getCustomProperties()->addListener(mUndoManager); if(mLoadState == LS_LOADED) mUndoManager->AddUndo(OGRE_NEW ObjectCreationUndo(object)); SetSceneModified(true); if(mPagingEditor) mPagingEditor->addObject(object); return object; }
2.1 CreateObject(CBaseEditor **parent, OgitorsPropertyValueMap ¶ms)
CBaseEditor *CSceneManagerEditorFactory::CreateObject(CBaseEditor **parent, OgitorsPropertyValueMap ¶ms) CSceneManagerEditor *object = OGRE_NEW CSceneManagerEditor(this); object->createProperties(params); //似乎是创建编辑器的参量 object->mParentEditor->init(*parent); object->load(); //见2.1.1 mInstanceCount++; return object; }
2.1.1 bool CSceneManagerEditor::load(bool async) 这里创建相关的OGRE量,比如创建场景管理器,并设置相关的参量等。
bool CSceneManagerEditor::load(bool async) { if(mLoaded->get()) //是否已经load. return true; if(!getParent()->load()) return false; //转了千山万水,在这里创建了场景管理器。注意createSceneManager有2种创建方法 //第一种方法输入字符串,需要提前在插件中输入(是吗?不确定)。第二种输入一个SceneTypeMask类型,比较保险 mHandle = Ogre::Root::getSingletonPtr()->createSceneManager(mSceneManagerType->get(),mName->get()); if(mSkyBoxActive->get()) { if(Ogre::MaterialManager::getSingletonPtr()->getByName(mSkyBoxMaterial->get()).isNull()) mSkyBoxActive->set(false); else mHandle->setSkyBox(mSkyBoxActive->get(),mSkyBoxMaterial->get(),mSkyBoxDistance->get()); } else if(mSkyDomeActive->get()) { if(Ogre::MaterialManager::getSingletonPtr()->getByName(mSkyDomeMaterial->get()).isNull()) mSkyDomeActive->set(false); else mHandle->setSkyDome(mSkyDomeActive->get(),mSkyDomeMaterial->get()); } mHandle->setFog((Ogre::FogMode)mFogMode->get(),mFogColour->get(),mFogDensity->get(),mFogStart->get(),mFogEnd->get()); mHandle->setAmbientLight(mAmbient->get()); mRaySceneQuery = mHandle->createRayQuery(Ogre::Ray()); //创建查询体,注意在 unload 中进行了释放:destroyQuery mSphereSceneQuery = mHandle->createSphereQuery(Ogre::Sphere()); configureShadows(); //配置阴影参数 registerForUpdates(); //这里把场景管理器在ROOT进行注册,这样以后每帧就可以调用。 mLoaded->set(true); //设置已经加载标志 return true; }