ogre 引擎 框架追踪 第四章 资源加载之资源组初始化

ogre 引擎 框架追踪 第三章 资源加载之虚加载
前面写到的,资源的操作过程如下:
创建资源管理器->继承不同资源管理器的创建->向资源管理器添加路径->初始化已添加路径的资源->初始化资源->加载资源->渲染资源。
第二章的虚加载,已经将资源的路径添加到group并且保存好文件名与archive对象的对应关系。

接下来跟一下资源的初始化。
以笨蛋化的初始化为例

Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups();

初始化所有资源,获取资源组的map,然后一个一个的初始化

//资源操作时,一般都先上锁
OGRE_LOCK_AUTO_MUTEX

        // Intialise all declared resource groups
        ResourceGroupMap::iterator i, iend;
        iend = mResourceGroupMap.end();
        for (i = mResourceGroupMap.begin(); i != iend; ++i)
        {
            ResourceGroup* grp = i->second;
            OGRE_LOCK_MUTEX(grp->OGRE_AUTO_MUTEX_NAME) // lock group mutex
            if (grp->groupStatus == ResourceGroup::UNINITIALSED)//只初始化未初始化过的
            {
                // in the process of initialising
                grp->groupStatus = ResourceGroup::INITIALISING;//标记为正在初始化
                // Set current group
                mCurrentGroup = grp;
                parseResourceGroupScripts(grp);//解析资源组中所有脚本
                LogManager::getSingleton().logMessage("Creating resources for group " + i->first);
                createDeclaredResources(grp);//创建声明了的资源。
                grp->groupStatus = ResourceGroup::INITIALISED;//标记为已初始化

                mCurrentGroup = 0;
            }
        }

资源初始化之脚本解析

先解析资源组中所有脚本parseResourceGroupScripts

// Count up the number of scripts we have to parse
typedef list<FileInfoListPtr>::type FileListList;
typedef SharedPtr<FileListList> FileListListPtr;
typedef std::pair<ScriptLoader*, FileListListPtr> LoaderFileListPair;
typedef list<LoaderFileListPair>::type ScriptLoaderFileList;
ScriptLoaderFileList scriptLoaderFileList;
size_t scriptCount = 0;
// Iterate over script users in loading order and get streams
ScriptLoaderOrderMap::iterator oi;
for (oi = mScriptLoaderOrderMap.begin();oi != mScriptLoaderOrderMap.end(); ++oi)//脚本加载map是在各个有脚本资源管理器创建时注册到map中的,有FontManager(*.fontdef)、ScriptCompilerManager(它解析的格式*.program、*.material、*.particle、*.compositor、*.os)、OverlayManager(*.overlay)、MaterialManager、ParticleSystemManager,后面两个的解析交给脚本编译管理器了
{
    ScriptLoader* su = oi->second;
    // MEMCATEGORY_GENERAL is the only category supported for SharedPtr
    FileListListPtr fileListList(OGRE_NEW_T(FileListList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

    // Get all the patterns and search them
    const StringVector& patterns = su->getScriptPatterns();//获取该脚本加载器里所有的格式
    for (StringVector::const_iterator p = patterns.begin(); p != patterns.end(); ++p)
    {
        FileInfoListPtr fileList = findResourceFileInfo(grp->name, *p);//获取该格式的所有文件列表。包含archive对象指针(包含了文件的名称、绝对位置、文件类型)
        scriptCount += fileList->size();
        fileListList->push_back(fileList);
    }
    scriptLoaderFileList.push_back(
    LoaderFileListPair(su, fileListList));//将脚本加载器跟他所有的文件列表保存
}
// Fire scripting event
fireResourceGroupScriptingStarted(grp->name, scriptCount);//通知下开始解析,有进度条的就开始显示了 start parse 。。。

// Iterate over scripts and parse
// Note we respect original ordering
for (ScriptLoaderFileList::iterator slfli = scriptLoaderFileList.begin();slfli != scriptLoaderFileList.end(); ++slfli)
{
    ScriptLoader* su = slfli->first;
    // Iterate over each list
    for (FileListList::iterator flli = slfli->second->begin(); flli != slfli->second->end(); ++flli)
    {
        // Iterate over each item in the list
        for (FileInfoList::iterator fii = (*flli)->begin(); fii != (*flli)->end(); ++fii)
         {
            bool skipScript = false;
            fireScriptStarted(fii->filename, skipScript);//告知sdktray,输出下开始解析的文件名称,获取下是否文件被过滤掉
            if(skipScript)
            {
                LogManager::getSingleton().logMessage("Skipping script " + fii->filename);
            }
            else
            {
                LogManager::getSingleton().logMessage("Parsing script " + fii->filename);
               DataStreamPtr stream = fii->archive->open(fii->filename);//通过自己的archive打开文件,返回数据
               if (!stream.isNull())
               {
                    if (mLoadingListener)//若添加了资源加载的监听者,就会告诉它文件打开
                        mLoadingListener->resourceStreamOpened(fii->filename, grp->name, 0, stream);

                    if(fii->archive->getType() == "FileSystem" && stream->size() <= 1024 * 1024)
                    {
                        DataStreamPtr cachedCopy;
                        cachedCopy.bind(OGRE_NEW MemoryDataStream(stream->getName(), stream));
                        su->parseScript(cachedCopy, grp->name);//解析文件夹中的脚本
                    }
                    else
                       su->parseScript(stream, grp->name);
              }
            }
                    fireScriptEnded(fii->filename, skipScript);//解析结束告知
    }
}
}

fireResourceGroupScriptingEnded(grp->name);
LogManager::getSingleton().logMessage("Finished parsing scripts for resource group " + grp->name);

以*.program文件为例,在解析的底层调用了ScriptParser::parse,解析成ConcreteNodeListPtr(包含了命令及参数等);解析之后就编译ScriptCompiler::compile。不同的脚本不同的解析、编译方法,后面再细说。尤其是材质、program、cg、hlgl等。其实就是解析完了后,就创建对应的对象,比如材质(包括tecnique、pass等)、overlay等。创建完之后,就告诉资源管理器,这个资源我们已经创建了。

资源初始化之创建声明了的资源

createDeclaredResources
跟进代码

for (ResourceDeclarationList::iterator i = grp->resourceDeclarations.begin();
    i != grp->resourceDeclarations.end(); ++i)//resourceDeclarations里面一般为空,除非通过ResourceGroupManager::declareResource调用,以添加声明。声明了的资源提前于其他资源非ogre自建资源而创建了。
{
    ResourceDeclaration& dcl = *i;
    // Retrieve the appropriate manager
    ResourceManager* mgr = _getResourceManager(dcl.resourceType);
    // Create the resource
    ResourcePtr res = mgr->create(dcl.resourceName, grp->name,
        dcl.loader != 0, dcl.loader, &dcl.parameters);//创建资源,记着,是创建,不是加载
    // Add resource to load list
    ResourceGroup::LoadResourceOrderMap::iterator li = 
        grp->loadResourceOrderMap.find(mgr->getLoadingOrder());
    LoadUnloadResourceList* loadList;
    if (li == grp->loadResourceOrderMap.end())
    {
        loadList = OGRE_NEW_T(LoadUnloadResourceList, MEMCATEGORY_RESOURCE)();
        grp->loadResourceOrderMap[mgr->getLoadingOrder()] = loadList;//向加载顺序map中添加
    }
    else
    {
        loadList = li->second;
    }
    loadList->push_back(res);//资源组的加载列表中存入资源指针

}

资源的创建、加载操作一般分布在三个时期:
第一个时期是root初始化时,材质、mesh的管理器也做了初始化,在他们初始化时创建了ogre系统默认的材质(default)和mesh(cube、sphere),不仅仅创建了,还加载了;这个时期的创建是为了不至于不加载外部资源而不能使用。
第二个时期就是当前的时期,资源初始化时,(1)在脚本解析过程中,解析了的脚本对象就创建了(材质、overlay等),(2)先把声明了的资源创建了。这个时期的就是创建,没有加载。
第三个时期就是在资源初始化完成,在外部创建entity、material(等)的时候。而且加载主要集中在这个时期。也就是下章的 实加载。

总结资源初始化干的事儿,就是在前期资源文件、文件类型、archive读取并对应之后,把资源组中所有脚本文件解析并创建对应的对象;创建资源组中已声明了的资源。

本章引出的扩展文章为(1)关于不同的脚本不同的解析、编译方法(2)关于资源组管理器、资源管理器、资源的关系及ogre中关于资源的继承关系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

思依_xuni

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值