第一部分都是做些准备,这一部分就是主力了: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;
}