标签:blog http io ar os 使用 sp for 文件
Ogre的许多外部资源数据都有着相应的脚本格式,现例举如下:
Ogre的资源管理器都是从ResourceManager派生出来的,而ResourceManager又以ScriptLoader为基类。有相应脚本的的资源管理器,在其构造函数中会调用ResourceGroupManager::_registerScriptLoader()函数,将资源管理器对象指针保存到ResourceGroupManager的mScriptLoaderOrderMap容器中。在之后的资源初始化过程中(见前面相关文章的讨论),ResourceGroupManager::initialiseResourceGroup()会调用ResourceGroupManager::parseResourceGroupScripts()函数,对相应ResourceGroup中的脚本文件进行解析。新版本的Ogre引入了ScriptCompilerManager类后,以“.material”、“.program”、“.particle”和“.compositor”为后缀的文件都统一由ScriptCompilerManager类型对象统一进行管理和解析(而原来各自对应的资源管理器不再注册到mScriptLoaderOrderMap中)。ScriptCompilerManager自身也是以ScriptLoader为基类的,Oger在初始化Root对象时,会创建一个ScriptCompilerManager对象,并通过ResourceGroupManager::_registerScriptLoader()函数,将它的指针保存到ResourceGroupManager的mScriptLoaderOrderMap容器中。因此,新版本的ResourceGroupManager的mScriptLoaderOrderMap中保存的第一个ScriptLoader对象,实际上就是ScriptCompilerManager的对象指针。
ResourceGroupManager::parseResourceGroupScripts()函数的代码如下:
1 void ResourceGroupManager::parseResourceGroupScripts(ResourceGroup* grp) 2 { 3 4 LogManager::getSingleton().logMessage( 5 "Parsing scripts for resource group " + grp->name); 6 7 // Count up the number of scripts we have to parse 8 typedef list<FileInfoListPtr>::type FileListList; 9 typedef SharedPtr<FileListList> FileListListPtr; 10 typedef std::pair<ScriptLoader*, FileListListPtr> LoaderFileListPair; 11 typedef list<LoaderFileListPair>::type ScriptLoaderFileList; 12 ScriptLoaderFileList scriptLoaderFileList; 13 size_t scriptCount = 0; 14 // Iterate over script users in loading order and get streams 15 ScriptLoaderOrderMap::iterator oi; 16 for (oi = mScriptLoaderOrderMap.begin(); 17 oi != mScriptLoaderOrderMap.end(); ++oi) 18 { 19 ScriptLoader* su = oi->second; 20 // MEMCATEGORY_GENERAL is the only category supported for SharedPtr 21 FileListListPtr fileListList(OGRE_NEW_T(FileListList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 22 23 // Get all the patterns and search them 24 const StringVector& patterns = su->getScriptPatterns(); 25 for (StringVector::const_iterator p = patterns.begin(); p != patterns.end(); ++p) 26 { 27 FileInfoListPtr fileList = findResourceFileInfo(grp->name, *p); 28 scriptCount += fileList->size(); 29 fileListList->push_back(fileList); 30 } 31 scriptLoaderFileList.push_back( 32 LoaderFileListPair(su, fileListList)); 33 } 34 // Fire scripting event 35 fireResourceGroupScriptingStarted(grp->name, scriptCount); 36 37 // Iterate over scripts and parse 38 // Note we respect original ordering 39 for (ScriptLoaderFileList::iterator slfli = scriptLoaderFileList.begin(); 40 slfli != scriptLoaderFileList.end(); ++slfli) 41 { 42 ScriptLoader* su = slfli->first; 43 // Iterate over each list 44 for (FileListList::iterator flli = slfli->second->begin(); flli != slfli->second->end(); ++flli) 45 { 46 // Iterate over each item in the list 47 for (FileInfoList::iterator fii = (*flli)->begin(); fii != (*flli)->end(); ++fii) 48 { 49 bool skipScript = false; 50 fireScriptStarted(fii->filename, skipScript); 51 if(skipScript) 52 { 53 LogManager::getSingleton().logMessage( 54 "Skipping script " + fii->filename); 55 } 56 else 57 { 58 LogManager::getSingleton().logMessage( 59 "Parsing script " + fii->filename); 60 DataStreamPtr stream = fii->archive->open(fii->filename); 61 if (!stream.isNull()) 62 { 63 if (mLoadingListener) 64 mLoadingListener->resourceStreamOpened(fii->filename, grp->name, 0, stream); 65 66 if(fii->archive->getType() == "FileSystem" && stream->size() <= 1024 * 1024) 67 { 68 DataStreamPtr cachedCopy; 69 cachedCopy.bind(OGRE_NEW MemoryDataStream(stream->getName(), stream)); 70 su->parseScript(cachedCopy, grp->name); 71 } 72 else 73 su->parseScript(stream, grp->name); 74 } 75 } 76 fireScriptEnded(fii->filename, skipScript); 77 } 78 } 79 } 80 81 fireResourceGroupScriptingEnded(grp->name); 82 LogManager::getSingleton().logMessage( 83 "Finished parsing scripts for resource group " + grp->name); 84 }
ScriptCompilerManager对象有一个StringVector mScriptPatterns成员,它里面主要保存着待解析的脚本文件类型信息,在ScriptCompilerManager被创建时,“.material”、“.program”、“.particle”、“.compositor”四个字符串会被保存在内。第27行的findResourceFileInfo()函数的代码展开如下:
1 FileInfoListPtr ResourceGroupManager::findResourceFileInfo(const String& groupName, 2 const String& pattern, bool dirs) 3 { 4 OGRE_LOCK_AUTO_MUTEX 5 // MEMCATEGORY_GENERAL is the only category supported for SharedPtr 6 FileInfoListPtr vec(OGRE_NEW_T(FileInfoList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T); 7 8 // Try to find in resource index first 9 ResourceGroup* grp = getResourceGroup(groupName); 10 if (!grp) 11 { 12 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 13 "Cannot locate a resource group called ‘" + groupName + "‘", 14 "ResourceGroupManager::findResourceFileInfo"); 15 } 16 17 OGRE_LOCK_MUTEX(grp->OGRE_AUTO_MUTEX_NAME) // lock group mutex 18 19 // Iterate over the archives 20 LocationList::iterator i, iend; 21 iend = grp->locationList.end(); 22 for (i = grp->locationList.begin(); i != iend; ++i) 23 { 24 FileInfoListPtr lst = (*i)->archive->findFileInfo(pattern, (*i)->recursive, dirs); 25 vec->insert(vec->end(), lst->begin(), lst->end()); 26 } 27 28 return vec; 29 }
以FileSystemArchive为例,在findResourceFileInfo()函数中的第24行将会形成如下调用链:
1. FileSystemArchive::findFileInfo || \/ 2. FileSystemArchive::findFiles(const String& pattern, bool recursive, bool dirs, StringVector* simpleList, FileInfoList* detailList)
其中的调用“结点2”——findFiles()函数展开后为:
1 void FileSystemArchive::findFiles(const String& pattern, bool recursive, 2 bool dirs, StringVector* simpleList, FileInfoList* detailList) const 3 { 4 intptr_t lHandle, res; 5 struct _finddata_t tagData; 6 7 // pattern can contain a directory name, separate it from mask 8 size_t pos1 = pattern.rfind (‘/‘); 9 size_t pos2 = pattern.rfind (‘\\‘); 10 if (pos1 == pattern.npos || ((pos2 != pattern.npos) && (pos1 < pos2))) 11 pos1 = pos2; 12 String directory; 13 if (pos1 != pattern.npos) 14 directory = pattern.substr (0, pos1 + 1); 15 16 String full_pattern = concatenate_path(mName, pattern); 17 18 lHandle = _findfirst(full_pattern.c_str(), &tagData); 19 res = 0; 20 while (lHandle != -1 && res != -1) 21 { 22 if ((dirs == ((tagData.attrib & _A_SUBDIR) != 0)) && 23 ( !msIgnoreHidden || (tagData.attrib & _A_HIDDEN) == 0 ) && 24 (!dirs || !is_reserved_dir (tagData.name))) 25 { 26 if (simpleList) 27 { 28 simpleList->push_back(directory + tagData.name); 29 } 30 else if (detailList) 31 { 32 FileInfo fi; 33 fi.archive = this; 34 fi.filename = directory + tagData.name; 35 fi.basename = tagData.name; 36 fi.path = directory; 37 fi.compressedSize = tagData.size; 38 fi.uncompressedSize = tagData.size; 39 detailList->push_back(fi); 40 } 41 } 42 res = _findnext( lHandle, &tagData ); 43 } 44 // Close if we found any files 45 if(lHandle != -1) 46 _findclose(lHandle); 47 48 // Now find directories 49 if (recursive) 50 { 51 String base_dir = mName; 52 if (!directory.empty ()) 53 { 54 base_dir = concatenate_path(mName, directory); 55 // Remove the last ‘/‘ 56 base_dir.erase (base_dir.length () - 1); 57 } 58 base_dir.append ("/*"); 59 60 // Remove directory name from pattern 61 String mask ("/"); 62 if (pos1 != pattern.npos) 63 mask.append (pattern.substr (pos1 + 1)); 64 else 65 mask.append (pattern); 66 67 lHandle = _findfirst(base_dir.c_str (), &tagData); 68 res = 0; 69 while (lHandle != -1 && res != -1) 70 { 71 if ((tagData.attrib & _A_SUBDIR) && 72 ( !msIgnoreHidden || (tagData.attrib & _A_HIDDEN) == 0 ) && 73 !is_reserved_dir (tagData.name)) 74 { 75 // recurse 76 base_dir = directory; 77 base_dir.append (tagData.name).append (mask); 78 findFiles(base_dir, recursive, dirs, simpleList, detailList); 79 } 80 res = _findnext( lHandle, &tagData ); 81 } 82 // Close if we found any files 83 if(lHandle != -1) 84 _findclose(lHandle); 85 } 86 }
其作用是在本Archive指定的目录下搜索以pattern(findFiles的第一个参数)为后缀名的文件,并将满足条件的所有文件的相关信息(包括文件名、相应Archive对象指针、路径名及是否为压缩文件等)添加到名为detailList的FileInfoList中去并返回给调用函数。而ResourceGroupManager::findResourceFileInfo()函数会对保存在本group的locationList中的所有Archive对象进行如上操作(findResourceFileInfo()函数22-26行)。
因此,回到最开始的ResourceGroupManager::parseResourceGroupScripts()函数,可以知道第16-33行的作用是:对指定的resourceGroup进行搜索,并将保存在locationList中的所有Archive对象对应目录下,后缀名为资源管理器指定的文件类型(由mScriptPatterns来指定,对ScriptCompilerManager来说mScriptPattern中的值为:“.material”、“.program”、“.particle”、“.compositor”)的文件的相关信息,以文件为单位保存到scriptLoaderFileList(在第12行中定义)列表中。
ResourceGroupManager::parseResourceGroupScripts()函数的第39-79行,则实现了对保存在scriptLoaderFileList列表中对应的脚本文件的解析。其中最核心的逻辑是DataStreamPtr stream = fii->archive->open(fii->filename)(60行)和su->parseScript()(70、73行)。第60行用于打开待解析的脚本文件,而su->parseScript()函数则会调用相应资源管理器的parseScript(DataStreamPtr& stream, const String& groupName)函数。以ScriptCompilerManager为例,其代码为:
1 void ScriptCompilerManager::parseScript(DataStreamPtr& stream, const String& groupName) 2 { 3 #if OGRE_THREAD_SUPPORT 4 // check we have an instance for this thread (should always have one for main thread) 5 if (!OGRE_THREAD_POINTER_GET(mScriptCompiler)) 6 { 7 // create a new instance for this thread - will get deleted when 8 // the thread dies 9 OGRE_THREAD_POINTER_SET(mScriptCompiler, OGRE_NEW ScriptCompiler()); 10 } 11 #endif 12 // Set the listener on the compiler before we continue 13 { 14 OGRE_LOCK_AUTO_MUTEX 15 OGRE_THREAD_POINTER_GET(mScriptCompiler)->setListener(mListener); 16 } 17 OGRE_THREAD_POINTER_GET(mScriptCompiler)->compile(stream->getAsString(), stream->getName(), groupName); 18 }
其中,stream->getAsString()用来将脚本文件中的内容以字符串的形式加载到内存;stream->getName()用来返回待解析脚本文件的文件名。
标签:blog http io ar os 使用 sp for 文件
原文地址:http://www.cnblogs.com/skyofbitbit/p/4089013.html