《Pro Ogre 3D Programming》 读书笔记 之 第七章 资源管理(转)
资源组
命名组可以作为一个整体加载与卸载。在加载,卸载,初始化时把把组中的所有资源作为一个执行单位来
看待,而不是逐个进行处理。资源组管理纯粹是了为了管理上的方便,是否使用组的方式与性能无关。假
如向资源组管理器中加入了资源位置而没有指定组名,那么这些资源位置被放入"General"组中。
资源组与世界几何
缺省情况下,ogre把加载的世界几何放入"General"组。也可以覆盖(override)这种方式,使得对世界几何的管理像其他资源的管理方式一样。统一的场景管理器可以提供关于装载世界总步骤的线索,这样就可以在关卡加载时,提供精确的以进度条显示的反馈信息。
资源位置(location)
资源位置是ogre去查找资源进行索引的地方。索引指的是在某个位置的所有资源通过它们的名字被映射,这样可以方便进行更快的查找资源。可以在程序的任何时候添加或删除资源位置,不必事先对所以可能用到的进行定义。资源位置在ogre中实际上是个archive,它的意思就是“文件的集合”。磁盘上的文件系统是
archive的一种类型。另外一种是zip archive。可以自定义archive格式。这通过改写archive类实现来完成,必须支持对命名的leaf文件进行枚举操作,必须支持通配符,支持结点递归,给ogre提供一个流访问archive中文件的数据。ogre中的archive是只读的。ogre资源管理器利用archive枚举特性来索引archive的内容,当ogre对archive进行索引时,不会实际加载任何资源。
资源生命周期
资源有四种状态,各状态之间的转换关系如下图:
Undefined:这是程序开始时,所有资源的缺省状态。除非它们被声明,ogre对程序用到的资源一无所知,手工调用代码 ResourceGroupManager::declareResource()或在脚本中被解析之后,资源的状态变为Declared
Declared:声明就是告诉ogre想要加载某些资源。ResourceGroupManager::declareResource()总是有效的,包括在渲染系统初始之前,这与ResourceManager::create()不同,因为后者依赖于渲染系统。
Unloaded:通过调用ResourceGroupManager::initialiseAllResourceGroup(), ResourceGroupManager::
initialiseResourceGroup(),或Root::initialise()(它会初始化在此调用之前所有声明的资源),资源状态进入到Unloaded,资源会占用一点内存来保存它的定义的实例,但是资源本身还没有加载到内存。从另一角度看(从Loaded到Unloaded),引起状态变化的调用有:ResourceManager::unload(),ResourceManager::unloadAll(), ResourceManager::unloadAllUnreferencedResources(),ResourceGroupManager::unloadResourceGroup(), or Resource::unload().所有这些调用仍会保存资源实例,但真正的资源数据会从内存中卸载。
Loaded: 这种状态下,所有数据都变得有效。与此状态有关的调用有Resource::load(), Resource::reload(),
ResourceManager::load(), ResourceManager::reload(), ResourceManager::reloadAll(),
ResourceManager::reloadAllUnreferencedResources(), and ResourceGroupManager::
loadResourceGroup().
逻辑资源管理
资源以命名组的形式组织,每组可以包括任何类型的资源,每种资源都有自己的资源管理器,后者负责加载与卸载特定类型的资源。ogre对它的资源没有实现特定的内存管理方案,如果你需要对某种资源实“最近最少使用算法”方案来进行管理,那么需要自己的代码来实现。值的一提的是,现在的大多数显卡驱动,对于大多数重要的资源已经实现了这种LRU算法管理。
资源加载
假如没有预加载,当资源被访问时会进行加载。实际的加载,卸载是资源自己的责任。
手动加载资源
资源管理层不负责实际的加载与卸载。通常,不必担心资源是否存在于易失性媒介。然而,手工方式时需要考虑。手工资源加载器必须在任何时候准备好重新加载资源。假如某个资源是通过程序生成的,那么手工资源加载器必须内存中缓冲这些资源,或者是当资源管理加载时重新创建它。ogre认为手工加载与自动加载没有区别。
后台资源管理
缺省,ogre不是线程安全的。假如在OgreConfig.h中 #define OGRE_THREAD_SUPPORT 1 ,那么资源管理
代码的线程同步功能变得有效,我们就可以在包含Root实例的线程之外,开启新的线程对资源管理类与方法进行操作,从而实现灵活的资源加载方案。
非后台资源管理
Ogre中大量使用了Observer模式,资源管理系统也不例外。ResourceGroupListene 回调接口包含了几个方法
允许对资源加载过程进行细粒度的监听。
资源卸载
资源被加载后总存在于内存中,直到被应用程序强行卸载(通过资源组管理器或是被资源直接释放)。资源管理组管理会把组中所有的资源都卸载掉。在资源被引用时不能强行卸载。
Resource Locations
// 配置文件方式
ConfigFile cf;
cf.load("resources.cfg");
// Go through all sections & settings in the file
ConfigFile::SectionIterator seci = cf.getSectionIterator();
String secName, typeName, archName;
while (seci.hasMoreElements())
{
secName = seci.peekNextKey();
ConfigFile::SettingsMultiMap *settings = seci.getNext();
ConfigFile::SettingsMultiMap::iterator i;
for (i = settings->begin(); i != settings->end(); ++i)
{
typeName = i->first;
archName = i->second;
ResourceGroupManager::getSingleton().addResourceLocation(
archName, typeName, secName);
}
}
//硬编码方式
ResourceGroupManager *rgm = ResourceGroupManager::getSingletonPtr();
rgm->addResourceLocation("../../media/packs/OgreCore.zip", "Zip", "Bootstrap");
rgm->addResourceLocation("../../media", "FileSystem", "General");
rgm->addResourceLocation("../../media/fonts", "FileSystem", "General");
初始化
在初始化之前,必须创建至少一个渲染窗口。因为在分析脚本时可能会创建GPU资源,而后者需要渲染
上下文。
// initialize all of the previously defined resource groups
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
// or, alternately, initialize the defined resource groups one at a time
ResourceGroupManager::getSingleton().initialiseResourceGroup("General");
ResourceGroupManager::getSingleton().initialiseResourceGroup("Bootstrap");
卸载
可以在任何时候卸载资源(以组或单个的方式),正在使用的资源不会被卸载。
以组的方式卸载
ResourceGroupManager::getSingleton().unloadResourceGroup("Bootstrap", true);
ResourceGroupManager::getSingleton().
unloadUnreferencedResourcesInGroup("Bootstrap", true);
true表示只卸载资源数据,不删除资源实例,它可以被reloaded。有些资源在创建时被标为
"nonreloadable",这种类型的资源不能使用上述方法卸载。
清理或销毁资源组
清理仅是卸载资源与分离资源索引,销毁不仅做清理的工作,还包括从资源组中把自己移除。
ResourceGroupManager::geSingleton().clearResourceGroup("Bootstrap");
ResourceGroupManager::geSingleton().destroyResourceGroup("Bootstrap");
以个体方式卸载
// assume that pEntity is a valid pointer to an instance of Entity
MeshPtr meshPtr = pEntity->getMesh();
meshPtr->unload();
加载/重载资源组
ResourceGroupManager::getSingleton().loadResourceGroup("Bootstrap", false, true)
二个布尔变量不同资源类型资源加载开关,一针对"Normal"资源,二针对"World geometry"
资源组加载通知
class LoadingProgressListener : public ResourceGroupListener
{
public:
// fired when a group begins parsing scripts
void resourceGroupScriptingStarted(const String& groupName,
size_t scriptCount) {}
// fired when a script is about to be parsed
void scriptParseStarted(const String& scriptName) {}
// fired when the script has been parsed
void scriptParseEnded() {}
// fired when all scripts in the group have been parsed
void resourceGroupScriptingEnded(const String& groupName) {}
//还有一些接口
}
//实现之后,进行注册
LoadingProgressListener listener(m_progressMeter);
ResourceGroupManager::getSingleton().addResourceGroupListener(&listener);