• Ogre的资源管理以及资源冲突


    Ogre资源管理

     

    1.Ogre资源的载入、卸载和销毁的过程

    http://ogre3d.cn/wiki/index.php?title=%E6%96%87%E6%A1%A3:%E6%95%99%E7%A8%8B:%E4%B8%AD%E7%BA%A7%E6%95%99%E7%A8%8B:%E4%B8%AD%E7%BA%A7%E6%95%99%E7%A8%8B%E4%B8%83

     

    http://blog.csdn.net/pizi0475/article/details/6264467

     

    2.跟踪material的资源载入过程。

     

    ResourceGroupManager::initialiseAllResourceGroups()是可以初始化ogre中资源列表中所有的资源。

     

    主要通过两个函数来解析和声明一个组的资源。

    parseResourceGroupScripts(grp);

    createDeclaredResources(grp);

     

    在 parseResourceGroupScripts函数中,

    // Iterate over script users in loading order and get streams

    ScriptLoaderOrderMap::iterator oi;

    for (oi = mScriptLoaderOrderMap.begin();

           oi != mScriptLoaderOrderMap.end(); ++oi)

    {

    。。。

    }

    根据加载器的顺序将他们一个个取出来做操作。这样保证了加载的优先级,因为有些资源的加载是有依赖关系的。

     

    这个map里的东西从哪来呢?全解决方案搜索,就会发现在下面这个函数里。

    void ResourceGroupManager::_registerScriptLoader(ScriptLoader* su)

           {

                 OGRE_LOCK_AUTO_MUTEX

     

                 mScriptLoaderOrderMap.insert(

                        ScriptLoaderOrderMap::value_type(su->getLoadingOrder(), su));

           }

       而当每一种类型的ResourceManager被创建时,都会调用这个函数把自己注册进来,这样就能解析属于他们管理的资源类型的脚本了。可以到MaterialManager的构造函数中看到。

    // Loading order

            mLoadOrder = 100.0f;

                 // Scripting is supported by this manager

    #if OGRE_USE_NEW_COMPILERS == 0

                 mScriptPatterns.push_back("*.program");

                 mScriptPatterns.push_back("*.material");

                  ResourceGroupManager::getSingleton()._registerScriptLoader(this);

    #endif

     

     

     

    // 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);

           scriptCount += fileList->size();

           fileListList->push_back(fileList);

    }

    scriptLoaderFileList.push_back(

    LoaderFileListPair(su, fileListList));

     

    得到一个加载器所能加载的资源类型,找出这个资源组中所有的这种资源类型的文件,把他们的文件信息存入列表中,并把这两者配对存储,放入了 scriptLoaderFileList 。

     

    // Fire scripting event

    fireResourceGroupScriptingStarted(grp->name, scriptCount);

     

    发送一条信息,通知所有的 ResourceGroupListener,开始解析组里的脚本了。

     

    // 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);

                        if(skipScript)

                        {

                               LogManager::getSingleton().logMessage(

                                     "Skipping script " + fii->filename);

                        }

                        else

                        {

                               LogManager::getSingleton().logMessage(

                                     "Parsing script " + fii->filename);

                               DataStreamPtr stream = fii->archive->open(fii->filename);

                               if (!stream.isNull())

                               {

                                     if (mLoadingListener)

                                            mLoadingListener->resourceStreamOpened(fii->filename, grp->name, 0, stream);

                                     su->parseScript(stream, grp->name);

                               }

                        }

                        fireScriptEnded(fii->filename, skipScript);

                 }

           }

    }

     

     

    这段代码的作用,从加载器列表中取出每一个加载器,对加载器所要解析的脚本进行一一解析。

     

    fireScriptStarted(fii->filename, skipScript);

     

    通知所有的 ResourceGroupListener,开始加载脚本了。

    这边传入了一个bool型的skipScript的引用,这样应该就能在Listener里边对特定名称的文件进行过滤,让其不被加载。

     

     

    DataStreamPtr stream = fii->archive->open(fii->filename);

    打开当前文件名的文件,存为数据流。

     

    if (mLoadingListener)

           mLoadingListener->resourceStreamOpened(fii->filename, grp->name, 0, stream);

     

     

    如果有 ResourceLoadingListener,就可以对资源的打开进行监听了,在这边可又得到打开的资源文件的名字。第三个参数传入的是0,所以在这还得不到资源的名字,因为还没有解析脚本。

     

    su->parseScript(stream, grp->name);

    这里开始解析脚本了

    跟踪跳转到

    ScriptCompilerManager::parseScript(DataStreamPtr& stream, const String& groupName)

     

    不知道是不是ogre默认是用这个scriptLoader来解析脚本的。

     

    具体的解析过程,由

    mScriptCompiler->compile(stream->getAsString(), stream->getName(), groupName);

     

    即:

    bool ScriptCompiler::compile(const String &str, const String &source, const String &group)

    {

           ScriptLexer lexer;

           ScriptParser parser;

           ConcreteNodeListPtr nodes = parser.parse(lexer.tokenize(str, source));

           return compile(nodes, group);

    }

    上面的代码就将文件解析为一堆的ConcreteNode了,没具体细看,按照我的理解,在不知道文件具体是干嘛用的情况下,应该只是存最顶层的每一个名字,再存上大括号里的内容吧。

     

    在OgreScriptCompiler.cpp中可以看到:

    bool ScriptCompiler::compile(const ConcreteNodeListPtr &nodes, const String &group)

    {

    // Translate the nodes

    for(AbstractNodeList::iterator i = ast->begin(); i != ast->end(); ++i)

    {

           //logAST(0, *i);

           if((*i)->type == ANT_OBJECT && reinterpret_cast<ObjectAbstractNode*>((*i).get())->abstract)

                               continue;

           ScriptTranslator *translator = ScriptCompilerManager::getSingleton().getTranslator(*i);

           if(translator)

              translator->translate(this, *i);

    }

    }

    这边将Node一个个取出来然后找出对应的ScriptTranslator来进行解析。

     

    ScriptTranslator *ScriptCompilerManager::getTranslator(const AbstractNodePtr &node)

    {

           ScriptTranslator *translator = 0;

           {

                 OGRE_LOCK_AUTO_MUTEX

                       

                 // Start looking from the back

                        for(std::vector<ScriptTranslatorManager*>::reverse_iterator i = mManagers.rbegin(); i != mManagers.rend(); ++i)

           {

                 translator = (*i)->getTranslator(node);

                 if(translator != 0)

                        break;

           }

           }

           return translator;

    }

     

    具体的translator就要根据Node的ID来判断了:

    ScriptTranslator *BuiltinScriptTranslatorManager::getTranslator(const AbstractNodePtr &node)

    {

           ScriptTranslator *translator = 0;

     

           if(node->type == ANT_OBJECT)

           {

                 ObjectAbstractNode *obj = reinterpret_cast<ObjectAbstractNode*>(node.get());

                 ObjectAbstractNode *parent = obj->parent ? reinterpret_cast<ObjectAbstractNode*>(obj->parent) : 0;

                 if(obj->id == ID_MATERIAL)

                        translator = &mMaterialTranslator;

                 else if(obj->id == ID_TECHNIQUE && parent && parent->id == ID_MATERIAL)

                        translator = &mTechniqueTranslator;

                 else if(obj->id == ID_PASS && parent && parent->id == ID_TECHNIQUE)

                        translator = &mPassTranslator;

                 else if(obj->id == ID_TEXTURE_UNIT && parent && parent->id == ID_PASS)

                        translator = &mTextureUnitTranslator;

                 else if(obj->id == ID_TEXTURE_SOURCE && parent && parent->id == ID_TEXTURE_UNIT)

                        translator = &mTextureSourceTranslator;

                 else if(obj->id == ID_FRAGMENT_PROGRAM || obj->id == ID_VERTEX_PROGRAM || obj->id == ID_GEOMETRY_PROGRAM)

                        translator = &mGpuProgramTranslator;

                 else if(obj->id == ID_PARTICLE_SYSTEM)

                        translator = &mParticleSystemTranslator;

                 else if(obj->id == ID_EMITTER)

                        translator = &mParticleEmitterTranslator;

                 else if(obj->id == ID_AFFECTOR)

                        translator = &mParticleAffectorTranslator;

                 else if(obj->id == ID_COMPOSITOR)

                        translator = &mCompositorTranslator;

                 else if(obj->id == ID_TECHNIQUE && parent && parent->id == ID_COMPOSITOR)

                        translator = &mCompositionTechniqueTranslator;

                 else if((obj->id == ID_TARGET || obj->id == ID_TARGET_OUTPUT) && parent && parent->id == ID_TECHNIQUE)

                        translator = &mCompositionTargetPassTranslator;

                 else if(obj->id == ID_PASS && parent && (parent->id == ID_TARGET || parent->id == ID_TARGET_OUTPUT))

                        translator = &mCompositionPassTranslator;

                 else if(obj->id == ID_CLEAR && parent && parent->id == ID_PASS)

                        translator = &mCompositionPassClearTranslator;

                 else if(obj->id == ID_STENCIL && parent && parent->id == ID_PASS)

                        translator = &mCompositionPassStencilTranslator;

           }

     

           return translator;

    }

     

    下面以mMaterialTranslator为例,依然是在OgreScriptTranslator.cpp:

    void MaterialTranslator::translate(ScriptCompiler *compiler, const AbstractNodePtr &node)

    {

           ObjectAbstractNode *obj = reinterpret_cast<ObjectAbstractNode*>(node.get());

           if(obj->name.empty())

                 compiler->addError(ScriptCompiler::CE_OBJECTNAMEEXPECTED, obj->file, obj->line);

     

           // Create a material with the given name

           std::vector<Ogre::Any> args;

           args.push_back(Any(obj->file));

           args.push_back(Any(obj->name));

           args.push_back(Any(compiler->getResourceGroup()));

           Ogre::Any retval = compiler->_fireCreateObject("Material", args);

           if(retval.isEmpty())

           {

                 mMaterial = reinterpret_cast<Ogre::Material*>(MaterialManager::getSingleton().create(obj->name, compiler->getResourceGroup()).get());

           }

           else

           {

                 try{

                        mMaterial = Ogre::any_cast<Ogre::Material*>(retval);

                 }catch(...){

                        compiler->addError(ScriptCompiler::CE_OBJECTALLOCATIONERROR, obj->file, obj->line,

                               "failed to find or create material \"" + obj->name + "\"");

                        return;

                 }

           }

     

           mMaterial->removeAllTechniques();

           obj->context = Any(mMaterial);

           mMaterial->_notifyOrigin(obj->file);

     

    //以下略

    ……

     

    }

     

    Ogre::Any retval = compiler->_fireCreateObject("Material", args);

    像compiler发送一个创建的消息,这其实是给compiler的监听器发送的消息,可以里边进行一些操作,如果没有创建东西,就让底下的MaterialManager来进行创建工作。

     

    if(retval.isEmpty())

    {

           mMaterial = reinterpret_cast<Ogre::Material*>(MaterialManager::getSingleton().create(obj->name, compiler->getResourceGroup()).get());

    }

     

     

    这里就到了create Material的地方了:

     

    ResourcePtr ResourceManager::create(const String& name, const String& group,

                                                                bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)

    {

           // Call creation implementation

           ResourcePtr ret = ResourcePtr(

                 createImpl(name, getNextHandle(), group, isManual, loader, params));

           if (params)

                 ret->setParameterList(*params);

     

           addImpl(ret);

           // Tell resource group manager

           ResourceGroupManager::getSingleton()._notifyResourceCreated(ret);

           return ret;

     

    }

     

    createImpl会根据不同的ResurceManager进行重载,会new出不同的资源。

    addImpl则是将新的资源加入到资源的map里。在这里边可以进里资源名字的冲突问题。

  • 相关阅读:
    【2017中国大学生程序设计竞赛
    【hdu 4333】Revolving Digits
    【hihocoder 1554】最短的 Nore0061
    【2017中国大学生程序设计竞赛
    【Codeforces Beta Round #88 C】Cycle
    【2017 Multi-University Training Contest
    【Codeforces Round #429 (Div. 2) C】Leha and Function
    【Codeforces Round #429 (Div. 2) B】 Godsend
    【Codeforces Round #429 (Div. 2) A】Generous Kefa
    Single-stack real-time operating system for embedded systems
  • 原文地址:https://www.cnblogs.com/gameprogram/p/2256858.html
Copyright © 2020-2023  润新知