设置材质
void Entity::setMaterialName( const String& name, const String& groupName )
{
SubEntityList::iterator i;
for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
{
(*i)->setMaterialName(name, groupName);
}
}
void SubEntity::setMaterialName( const String& name, const String& groupName )
{
MaterialPtr material = MaterialManager::getSingleton().getByName(name, groupName);
if( !material )
{
}
setMaterial( material );
}
void SubEntity::setMaterial( const MaterialPtr& material )
{
mMaterialPtr = material;
if (!mMaterialPtr)
{
}
mMaterialPtr->load();
mParentEntity->reevaluateVertexProcessing();
}
想起了之前对SampleBrowser代码的分析,在SampleBorwser里有一个 StartupSample 的配置
Ogre::String startupSampleTitle = cfg.getSetting("StartupSample");
找到并打开 samples.cfg, 加入
StartupSample=Bump Mapping
直接启动BumpMapping.
那么问题来了,通过一个材质名称是怎么找到材质文件的呢?有可能跟samples.cfg一样。调试看看。
一路追踪,发现进入到
ResourcePtr ResourceManager::getResourceByName(const String& name, const String& groupName) const
通过名称获取材质。
ResourcePtr ResourceManager::getResourceByName(const String& name, const String& groupName) const
{
OGRE_LOCK_AUTO_MUTEX;
bool isGlobal = ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(groupName);
if(isGlobal)
{
auto it = mResources.find(name);
if( it != mResources.end())
{
return it->second;
}
}
if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
{
auto iter = mResourcesWithGroup.begin();
auto iterE = mResourcesWithGroup.end();
for ( ; iter != iterE ; ++iter )
{
auto resMapIt = iter->second.find(name);
if( resMapIt != iter->second.end())
{
return resMapIt->second;
}
}
}
else if (!isGlobal)
{
auto itGroup = mResourcesWithGroup.find(groupName);
if( itGroup != mResourcesWithGroup.end())
{
auto it = itGroup->second.find(name);
if( it != itGroup->second.end())
{
return it->second;
}
}
#if !OGRE_RESOURCEMANAGER_STRICT
auto it = mResources.find(name);
if( it != mResources.end())
{
return it->second;
}
#endif
}
return ResourcePtr();
}
bool ResourceGroupManager::isResourceGroupInGlobalPool(const String& name) const
{
ResourceGroup* grp = getResourceGroup(name);
if (!grp)
{
}
return grp->inGlobalPool;
}
ResourceGroupManager::ResourceGroup* ResourceGroupManager::getResourceGroup(const String& name) const
{
OGRE_LOCK_AUTO_MUTEX;
ResourceGroupMap::const_iterator i = mResourceGroupMap.find(name);
return i != mResourceGroupMap.end() ? i->second : NULL;
}
先通过group name 判断是否是global group,通过 mResourceGroupMap 来判断组。找找 mResourceGroupMap 如何初始化的。
void ResourceGroupManager::createResourceGroup(const String& name, bool inGlobalPool)
{
ResourceGroup* grp = OGRE_NEW_T(ResourceGroup, MEMCATEGORY_RESOURCE)();
grp->groupStatus = ResourceGroup::UNINITIALSED;
grp->name = name;
grp->inGlobalPool = inGlobalPool;
grp->customStageCount = 0;
mResourceGroupMap.emplace(name, grp);
}
mResourceGroupMap.emplace(name, grp); 处下断点。调试
ResourceGroupManager::ResourceGroupManager()
: mLoadingListener(0), mCurrentGroup(0)
{
createResourceGroup(DEFAULT_RESOURCE_GROUP_NAME, true);
createResourceGroup(INTERNAL_RESOURCE_GROUP_NAME, true);
createResourceGroup(AUTODETECT_RESOURCE_GROUP_NAME, true);
mWorldGroupName = DEFAULT_RESOURCE_GROUP_NAME;
}
在 ResourceGroupManager 的构造函数里,创建了3个全局资源组。
- General
- OgreInternal
- OgreAutodetect
const char* const RGN_DEFAULT = "General";
const char* const RGN_INTERNAL = "OgreInternal";
const char* const RGN_AUTODETECT = "OgreAutodetect";
const String ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME = RGN_DEFAULT;
const String ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME = RGN_INTERNAL;
const String ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME = RGN_AUTODETECT;
继续调试
void ResourceGroupManager::addResourceLocation(const String& name,
const String& locType, const String& resGroup, bool recursive, bool readOnly)
{
ResourceGroup* grp = getResourceGroup(resGroup);
if (!grp)
{
createResourceGroup(resGroup);
grp = getResourceGroup(resGroup);
}
}
void ApplicationContextBase::locateResources()
{
Ogre::ConfigFile cf;
Ogre::String resourcesPath = mFSLayer->getConfigFilePath("resources.cfg");
cf.load(resourcesPath);
rgm.addResourceLocation(arch, type, sec);
}
void ApplicationContextBase::setup()
{
locateResources();
loadResources();
}
在ApplicationContextBase::locateResources 里又添加了三个
在locateResources(定位资源)里使用了 “resources.cfg”,与"samples.cfg"相同,应该与samples.cfg在同一位置。
Ogre::String resourcesPath = mFSLayer->getConfigFilePath("resources.cfg");
打开 resources.cfg 文件,与samples.cfg 格式相同,ini 文件格式。
key有两种,FileSystem / Zip,通过value 找到对应的位置,很明显,FileSystem是指文件夹,Zip是压缩文件.
打开一个zip文件,里面的格式与FileSystem相同,只是一个压缩,一个未压缩。明显,zip更省内存。
在 resources.cfg 文件里,指定了很多文件路径。那么,通过文件名加载资源时,就会遍历这些文件夹去查找资源。同时,提供了一个资源组,指定资源组,可以避免不需要的搜索。
同样的,如果存在同名文件该怎么办?
通过ConfigFile::load加载 resources.cfg,分析文件。分析完,通过
rgm.addResourceLocation(arch, type, sec); 加入资源。完成资源定位。
以上的操作只做了创建资源组,未初始化。
void SampleBrowser::loadResources()
{
Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Essential");
}
// 初始化资源组
void ResourceGroupManager::initialiseResourceGroup(const String& name)
{
LogManager::getSingleton().logMessage("Initialising resource group " + name);
ResourceGroup* grp = getResourceGroup(name);
if (grp->groupStatus == ResourceGroup::UNINITIALSED)
{
grp->groupStatus = ResourceGroup::INITIALISING;
parseResourceGroupScripts(grp);
mCurrentGroup = grp;
LogManager::getSingleton().logMessage("Creating resources for group " + name);
createDeclaredResources(grp);
grp->groupStatus = ResourceGroup::INITIALISED;
LogManager::getSingleton().logMessage("All done");
mCurrentGroup = 0;
}
}
void ResourceGroupManager::parseResourceGroupScripts(ResourceGroup* grp) const
从代码来看,把资源文件定义为了script。分析文件,加载脚本。
ScriptLoader / ScriptCompiler, 大概就是导入/加载脚本的。至于如何做的,暂时就不深入了。
到这里,知道了如何通过 group name获取相关资源。回到 ResourceManager::getResourceByName
资源存储在 mResources / mResourcesWithGroup里。
从已获取的信息不知道这两个值是初始化的。找吧。>_<
void ResourceManager::addImpl( ResourcePtr& res )
{
result = mResources.emplace(res->getName(), res);
auto resgroup = mResourcesWithGroup.emplace(res->getGroup(), ResourceMap()).first;
}
ResourcePtr ResourceManager::createResource(const String& name, const String& group,
bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)
{
ResourcePtr ret = ResourcePtr(
createImpl(name, getNextHandle(), group, isManual, loader, params));
if (params)
ret->setParameterList(*params);
addImpl(ret);
}
MaterialPtr MaterialManager::create (const String& name, const String& group,
bool isManual, ManualResourceLoader* loader,
const NameValuePairList* createParams)
{
return static_pointer_cast<Material>(createResource(name,group,isManual,loader,createParams));
}
void MaterialManager::initialise(void)
{
mDefaultSettings = create("DefaultSettings", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
}
void Root::oneTimePostWindowInit(void)
{
mMaterialManager->initialise();
}
RenderWindow* Root::createRenderWindow(const String &name, unsigned int width, unsigned int height,
bool fullScreen, const NameValuePairList *miscParams)
{
oneTimePostWindowInit();
}
竟然是在 createRenderWindow 的时候创建的资源。
大致的结果就是资源加载后,存放在mResourcs / mResourcesWithGroup里。
mResoures 是全局资源,mResourcesWithGroup 是组资源。
到这里就知道了,如何通过名称获取材质资源。