资源的生命周期
OGRE的API文档里介绍了一个资源的基本生命周期,但其中一些概念比较乏味。希望在这里,事情会更清楚。
术语
以下术语被用来区分一个资源载入时可能处于的不同阶段:
未知的(Unknown):OGRE不知道有这么一个资源。资源组里面保存有它的文件名,但OGRE还不知道它用来干什么的。
声明的(Declared):直接地,或其它动作引起的,资源已经被标记为可创建的。Ogre知道它是什么类型的资源,以及当创建它时,需要做些什么。
已创建(Created):OGRE已经为这个资源创建了一个空的实例,并添加到了相应的资源管理器。
已载入(Loaded):创建的实例被完全载入,资源的所有数据都驻留在内存里。这是资源文件能被实际访问的典型阶段。你不能在创建阶段访问这些文件。
从头开始创建资源
1. OGRE的原生资源管理器是在Root::Root里创建的。
2. 首先要做的是指定一个资源位置,它是通过调用ResourceGroupManager::addResourceLocation来完成的。这个方法做了一些事情:
1. 创建指定的资源组(ResourceGroup),如果还没有创建的话。 2. 创建新的指定类型的存档(Archive)实例。 3. 创建新的资源位置(ResourceLocation),并把存档(Archive)添加给它,然后把这个资源位置(ResourceLocation)添加到资源管理组(ResourceGroup)。 4. 最后一步,获取Archive里所有文件的列表,并把它们添加到ResourceGroup的列表中。这一步完成之后,资源就处于Unknown状态了。
3. 下一步是手动声明资源。虽然当ResourceManager开始解析脚本时,许多资源会被声明,但目前它们还没有被声明。如果你打算手动声明资源,调用ResourceGroupManager::declareResource方法。这样,所有手动声明了的资源,都处于Declared状态。其它仍然是Unkown。
4. 接下面初始化ResourceGroup,通过ResourceGroupManager::initialiseResourceGroup或者ResourceGroupManager::initialiseAllResourceGroups,后者只是对于所有的ResourceGroup来调用前者。它干了这么一些事情:
1. 解析ResourceGroup里的所有脚本。脚本继承ScriptLoader,是由ResourceManager定义的。这可导致一些资源成为Declared。 2. 创建所有的Declared资源。 3. 相关的ResourceManager创建资源的一个新实例,并把它添加给自己。所有的资源都保存在ResourceManager里。 4. 这个资源同样也被插入到“有序载入列表(ordered loading list)”里。这样使资源按照指定的顺序载入,如果你想要一次性载入整个资源组的话。一个资源的载入顺序在它的ResourceManager中指定。 5. 目前,所有的Declared进入了Created阶段。
5. 我们完成初始化了。仍然没有资源被载入,但这是正常的,因为我们现在不使用。最后一步,从Created到Loaded,通过如下几种途径:
1. 使用资源。比如,创建一个需要指定mesh的实体。显然,一旦一个资源以这种方式载入,如果另一个实体也需要它则不必再次载入。如果这个资源目前还是Unknown状态的,则它将被创建并且完全载入。 2. 调用ResourceGroupManager::loadResourceGroup,所有Created资源将被载入。 3. 相应的ResourceManager的load方法被调用。这可以用在载入那些还没有创建的资源,因为如果需要的话,它会自动地为你创建。 4. 通过获取资源的指针,然后调用它的load方法,则资源将直接载入。当然,只有资源处于Created状态下,你才能这么做。 5. 好了,被载入的资源可以直接使用了。
注意:如果你创建了自定义的资源管理器,你必须在手动声明资源之前初始化它们,否则可能会找不到它们的当中一些。
在你的程序里,这通常表现为如下的事件:
1. 创建Root对象。 2. 重复调用ResourceGroupManager::addResourceLocation,直到你已经添加了所有的资源位置。 3. 创建所有自定义的ResourceManager对象,并通过调用ResourceGroupManager::_registerResourceManager注册它们。你可能还要注册ScriptLoader对象,通过调用ResourceGroupManager::_registerScriptLoader方法。 4. 手动声明你要的任何资源,通过ResourceGroupManager::declareResource函数。 5. 为你的资源组调用适当的初始化方法。对于单个组,调用ResourceGroupManager::initialiseResourceGroup,或者ResourceGroupManager::initialiseAllResourceGroups一口气初始化所有的。
资源卸载和销毁
ResourceManager::unload将一个资源从Loaded状态返回到Created。
想要完全移除资源,调用ResourceManager::remove。这样不论资源处于何种状态,都将打回Unknown状态。你可以通过ResourceManager::getByName来获取资源的指针,卸载或者移动它,如果你想这样做的话。
当一个资源管理器销毁时,所有存在的资源都会被移除。
重新载入资源(reload)
重新载入资源在编辑器里是非常有用的。本质上来说,资源先被卸载,然后再被载入。它从Loaded状态转到Created,然后再回到Loaded状态。资源必须处于Loaded状态,才能重新载入。
ResourceManager::reloadAll重新载入某一类型的所有资源。 单个资源可以通过Resource::reload重新载入。