如果不坐在那里并逐步通过调试器查看所有动态内存分配和对象的释放,仅通过阅读源代码就很难判断。这是一项相当繁琐的任务。给出一个决定性的答案可能相当困难。我可以在这里做的一件事是为您提供一些建议,因为我过去已经构建了 3D 图形引擎。
您已经提到了消除或减少使用new 和delete 的事实,这是一个非常好的开始。我要提出的是一种设计模式,主要是结构的伪代码。您可以在这里做的是创建一个类,该类负责管理您的内存的所有 3D 引擎资产。这不是一项容易完成的任务,但是一旦您的框架到位并正常工作,它将有助于使您的代码库和代码管理更加容易。
您可以创建一个类来存储您的所有资产。但是,要这样做,您将需要不同对象的通用结构或类。它可能看起来像这样:
class AssetStorageManager {
private:
std::vector<std::shared_ptr<Texture>> textures_;
std::vector<std::shared_ptr<Font>> fonts_;
std::vector<std::shared_ptr<Model>> models_;
std::vector<std::shard_ptr<GUI>> guiObjects_; // Text Boxes, Buttons etc.
// other possible containers: Music(BGM), SoundEffects etc.
// shaders (Vertex, Fragment, Geometry & OpenGL Programs)...
public:
AssetStorageManager() = default;
~AssetStorageManager() = default;
void addTexture( const Texture& texture ) { /* ... ; */ }
void removeTexture( unsigned int textureID ) { /* ... ; */ }
void clearTextures() { /* remove all textures in container; */ }
Texture* getTexture( unsigned int texureID );
// basically the same 4 for all of your individual containers.
};
有时vector 可能不够用,您可能需要map、unordered map、multimap、list、queue(有优先级)等。这完全取决于需要哪个你需要的容器。
这个类将负责管理内存。要考虑的另一件事是;当应用程序运行时,您将只需要此类对象的单个实例,这就是 Singleton 类型对象可能有用的地方。如果您将此类设为Singleton 对象,则需要在从文件加载任何类型的对象以存储它们之前创建并初始化它。
在我的引擎中,这些是我拥有的单例类型,但是,它们继承自 Singleton 基类:
-Singleton.h-
namespace /* namespace name here*/ {
#ifndef SINGELTON_H
#define SINGLETON_H
class Singleton {
public:
enum SingletonType {
LOGGER = 0, // Must be first!
SETTINGS,
ENGINE,
ANIMATION_MANAGER,
SHADER_MANGER,
ASSET_STORAGE,
AUDIO_MANAGER,
FONT_MANAGER,
BATCH_MANAGER
};
private:
SingletonType type_;
public:
virtual ~Singleton();
protected:
explicit Singleton( SingletonType eType );
void logMemoryAllocation( bool isAllocated ) const;
private:
Singleton( const Singleton& c ); // not implemented
Singleton& operator=( const Singleton& c ); // not implemented
};
} // /*namespace name here */
#endif // SINGLETON_H
-Singelton.cpp-
#include "stdafx.h"
#include "Singleton.h"
#include "Logger.h"
#include "Settings.h"
namespace /* namespace name here*/ {
struct SingletonInfo {
const std::string strSingletonName;
bool isConstructed;
SingletonInfo( const std::string& strSingletonNameIn ) :
strSingletonName( strSingletonNameIn ),
isConstructed( false )
{}
};
// Order Must Match Types Defined In Singleton::SingeltonType enum
static std::array<SingletonInfo, 9> s_aSingletons = { SingletonInfo( "Logger" ),
SingletonInfo( "Settings" ),
SingletonInfo( "Engine" ),
SingletonInfo( "AnimationManager" ),
SingletonInfo( "ShaderManager" ),
SingletonInfo( "AssetStorage" ),
SingletonInfo( "AudioManager" ),
SingletonInfo( "FontManager" ),
SingletonInfo( "BatchManager" ) };
Singleton::Singleton( SingletonType eType ) :
m_eType( eType ) {
bool bSaveInLog = s_aSingletons.at( TYPE_LOGGER ).isConstructed;
try {
if ( !s_aSingletons.at( eType ).isConstructed ) {
// Test Initialization Order
for ( int i = 0; i < eType; ++i ) {
if ( !s_aSingletons.at( i ).isConstructed ) {
throw ExceptionHandler( s_aSingletons.at( i ).strSingletonName + " must be constructued before constructing " + s_aSingletons.at( eType ).strSingletonName, bSaveInLog );
}
}
s_aSingletons.at( eType ).isConstructed = true;
if ( s_aSingletons.at( TYPE_ENGINE ).isConstructed &&
Settings::get()->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
logMemoryAllocation( true );
}
} else {
throw ExceptionHandler( s_aSingletons.at( eType ).strSingletonName + " can only be constructed once.", bSaveInLog );
}
} catch ( std::exception& ) {
// eType Is Out Of Range
std::ostringstream strStream;
strStream << __FUNCTION__ << " Invalid Singelton Type sepcified: " << eType;
throw ExceptionHandler( strStream, bSaveInLog );
}
}
Singleton::~Singleton() {
if ( s_aSingletons.at( TYPE_ENGINE ).isConstructed &&
Settings::get()->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
logMemoryAllocation( false );
}
s_aSingletons.at( m_eType ).isConstructed = false;
}
void Singleton::logMemoryAllocation( bool isAllocated ) const {
if ( isAllocated ) {
Logger::log( "Created " + s_aSingletons.at( m_eType ).strSingletonName );
} else {
Logger::log( "Destroyed " + s_aSingletons.at( m_eType ).strSingletonName );
}
}
} // /*namespace name here */
这是我的所有 Singleton 对象的基类,用于管理我的引擎的不同组件。还涉及到其他类如Logger、Settings、BatchManager等,这些都是Singletons本身,这里我就不展示了。这不会在您的机器上编译。
我的 AssetStorage 继承自它的类如下所示:
-AssetStorage.h-
#ifndef ASSET_STORAGE_H
#define ASSET_STORAGE_H
#include "Singleton.h"
#include "CommonStructs.h"
namespace /*namespace name here*/ {
class BaseMko;
class GuiElement;
enum GuiType;
struct Texture {
bool hasAlphaChannel;
bool generateMipMap;
bool wrapRepeat;
unsigned uWidth;
unsigned uHeight;
TextureInfo::FilterQuality filterQuality;
std::vector<unsigned char> vPixelData;
Texture( TextureInfo::FilterQuality filterQualityIn, bool generateMipMapIn, bool wrapRepeatIn ) :
hasAlphaChannel( false ),
generateMipMap( generateMipMapIn ),
wrapRepeat( wrapRepeatIn ),
uWidth( 0 ),
uHeight( 0 ),
filterQuality( filterQualityIn )
{}
}; // Texture
class AssetStorage sealed : public Singleton {
private:
typedef std::unordered_map<std::string, std::shared_ptr<BaseMko>> MapMkoAssets;
typedef std::unordered_map<std::string, TextureInfo> MapTextureInfos;
typedef std::unordered_map<std::string, std::shared_ptr<GuiElement>> MapGuiAssets;
MapMkoAssets m_mkoAssets;
MapTextureInfos m_textureInfos;
MapGuiAssets m_guiScreenAssets;
MapGuiAssets m_guiRenderableAssets;
std::vector<std::string> m_vGuiForRemoval;
public:
AssetStorage();
virtual ~AssetStorage();
static AssetStorage* const get();
// Mko Objects
BaseMko* getMko( const std::string& strId ) const;
void add( BaseMko* pMko );
bool removeMko( const std::string& strId, bool removeTexture = false );
void showLoadedMkoObjects() const;
// Texture Objects
TextureInfo getTextureInfo( const std::string& strFilename ) const;
TextureInfo add( const Texture& texture, const std::string& strFilename );
bool removeTextureInfo( const std::string& strFilename );
bool removeTextureInfo( unsigned uTextureId );
void showLoadedTextureInfo() const;
// Gui Objects
GuiElement* getGuiElement( const std::string& strId, GuiType type ) const;
void add( GuiElement* pGui, GuiType type );
bool removeGuiElement( const std::string& strId, bool removeTextures = false );
template<typename T>
bool removeGuiElement( T* pGui, bool removeTextures = false );
void markGuiForRemoval( const std::string& strId );
void cleanOrphanedGuiObjects();
void showLoadedGuiObjects() const;
private:
AssetStorage( const AssetStorage& c ) = delete; // Not Implemented
AssetStorage& operator=( const AssetStorage& c ) = delete; // Not Implemented
// Gui Objects
GuiElement* getGuiElement( const std::string& strId, const MapGuiAssets& guiMap ) const;
void add( GuiElement* pGui, MapGuiAssets& guiMap );
bool removeGuiElement( const std::string& strId, MapGuiAssets& guiMap, bool removeTextures );
}; // AssetStorage
template<typename T>
inline bool AssetStorage::removeGuiElement( T * pGui, bool removeTextures ) {
return false;
}
} // /*namespace name here*/
#endif // ASSET_STORAGE_H
-AssetStorage.cpp-
#include "stdafx.h"
#include "AssetStorage.h"
#include "BaseMko.h"
#include "BlockThread.h"
#include "Logger.h"
#include "Settings.h"
#include "GuiScreen.h"
#include "GuiRenderable.h"
namespace /*namespace name here*/ {
// Core OpenGL API Found In Opengl32.lib
#ifdef __cplusplus
extern "C" {
#endif
GLAPI void APIENTRY glBindTexture( GLenum target, GLuint texture );
GLAPI void APIENTRY glDeleteTextures( GLsizei n, const GLuint *textures );
GLAPI void APIENTRY glGenTextures( GLsizei n, GLuint *textures );
GLAPI void APIENTRY glTexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels );
GLAPI void APIENTRY glTexParameteri( GLenum target, GLenum pname, GLint param );
#ifdef __cplusplus
}
#endif
// OpenGl Texture API
static PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr;
static Settings* s_pSettings = nullptr;
static AssetStorage* s_pAssetStorage = nullptr;
static CRITICAL_SECTION s_criticalSection;
static void defineOpenglApi() {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Can not initialize function pointer named: ";
std::string strApiName;
if ( Settings::get()->getOpenglVersion().x >= 3 ) {
strApiName = "glGenerateMipmap";
if ( ( glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)wglGetProcAddress( strApiName.c_str() ) ) == nullptr ) {
strStream << strApiName;
throw ExceptionHandler( strStream );
}
}
}
AssetStorage::AssetStorage() :
Singleton( TYPE_ASSET_STORAGE ) {
InitializeCriticalSection( &s_criticalSection );
defineOpenglApi();
s_pSettings = Settings::get();
s_pAssetStorage = this;
}
AssetStorage::~AssetStorage() {
s_pAssetStorage = nullptr;
m_mkoAssets.clear();
m_guiRenderableAssets.clear();
m_guiScreenAssets.clear();
for( MapTextureInfos::iterator itTexture = m_textureInfos.begin(); itTexture != m_textureInfos.end(); ++itTexture ) {
if ( s_pSettings->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
Logger::log( std::string( "Destroyed " ) + itTexture->first );
}
glDeleteTextures( 1, &(itTexture->second.uTextureId ) );
}
m_textureInfos.clear();
DeleteCriticalSection( &s_criticalSection );
}
AssetStorage* const AssetStorage::get() {
if ( nullptr == s_pAssetStorage ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " failed, AssetStorage has not been constructed yet" ) );
}
return s_pAssetStorage;
}
BaseMko* AssetStorage::getMko( const std::string& strId ) const {
BlockThread blockThread( s_criticalSection );
MapMkoAssets::const_iterator itMkoAssets = m_mkoAssets.find( strId );
if ( itMkoAssets == m_mkoAssets.cend() ) {
return nullptr;
}
return itMkoAssets->second.get();
}
void AssetStorage::add( BaseMko* pMko ) {
if ( nullptr == pMko ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " pMko==nullptr passed in" ) );
}
if ( nullptr != getMko( pMko->getId() ) ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " attempting to store " << pMko->getId() << " multiple times";
throw ExceptionHandler( strStream );
}
BlockThread blockThread( s_criticalSection );
m_mkoAssets.insert( MapMkoAssets::value_type( pMko->getId(), std::shared_ptr<BaseMko>( pMko ) ) );
}
bool AssetStorage::removeMko( const std::string& strId, bool removeTexture ) {
BlockThread blockThread( s_criticalSection );
MapMkoAssets::iterator itMkoAsset = m_mkoAssets.find( strId );
if ( itMkoAsset == m_mkoAssets.end() ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed. " << strId << " was not found in Asset Storage";
Logger::log( strStream );
return false;
}
if ( removeTexture ) {
itMkoAsset->second->clearTextureInfos();
}
m_mkoAssets.erase( itMkoAsset );
return true;
}
void AssetStorage::showLoadedMkoObjects() const {
BlockThread blockThread( s_criticalSection );
if ( m_mkoAssets.size() > 0 ) {
Logger::log( "Loaded mko objects listed below: ", Logger::TYPE_CONSOLE );
for each( const std::pair<std::string, std::shared_ptr<BaseMko>>& mko in m_mkoAssets ) {
std::ostringstream strStream;
strStream << "mkoId(" << mko.first << ") ";
Logger::log( strStream, Logger::TYPE_CONSOLE );
}
} else {
Logger::log( "There are no loaded mko objects.", Logger::TYPE_CONSOLE );
}
Logger::log( " ", Logger::TYPE_CONSOLE );
}
TextureInfo AssetStorage::getTextureInfo( const std::string& strFilename ) const {
BlockThread blockThread( s_criticalSection );
MapTextureInfos::const_iterator itTexture = m_textureInfos.find( strFilename );
if ( itTexture == m_textureInfos.cend() ) {
return TextureInfo();
}
return itTexture->second;
}
// This Can Only Be Called From The Main OpenGL Thread
TextureInfo AssetStorage::add( const Texture& texture, const std::string& strFilename ) {
if ( INVALID_UNSIGNED != getTextureInfo( strFilename ).uTextureId ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " can not store " << strFilename << " multiple times";
throw ExceptionHandler( strStream );
}
TextureInfo textureInfo;
textureInfo.hasTransparency = texture.hasAlphaChannel;
textureInfo.size = glm::uvec2( texture.uWidth, texture.uHeight );
glGetError(); // Clear Errors
glGenTextures( 1, &textureInfo.uTextureId );
GLenum err = glGetError();
if ( err != GL_NO_ERROR ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed glGenTextures with error code 0x" << std::hex << err;
throw ExceptionHandler( strStream );
}
glBindTexture( GL_TEXTURE_2D, textureInfo.uTextureId );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, ( texture.wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, ( texture.wrapRepeat ? GL_REPEAT : GL_CLAMP_TO_EDGE ) );
const glm::uvec2& openglVersion = s_pSettings->getOpenglVersion();
if ( texture.generateMipMap ) {
switch ( texture.filterQuality ) {
case TextureInfo::FILTER_NONE : {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
break;
}
case TextureInfo::FILTER_GOOD: {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR );
break;
}
case TextureInfo::FILTER_BEST: {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
break;
}
default: {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
}
} // Switch
if ( openglVersion.x < 3 ) {
// In OpenGL v3 GL_GENERATE_MIPMAP Is Deprecated, And In 3.1+ It Was Removed
// So For Those Versions We Use glGenerateMipmap below
static const unsigned int GL_GENERATE_MIPMAP = 0x8191;
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
}
} else { // No MipMaps
switch( texture.filterQuality ) {
case TextureInfo::FILTER_NONE:
case TextureInfo::FILTER_GOOD: {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
break;
}
default: {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
}
}
}
// Load Texture Into Video Memory
glPixelStorei( GL_UNPACK_ALIGNMENT, texture.hasAlphaChannel ? 4 : 1 );
glTexImage2D( GL_TEXTURE_2D,
0,
( texture.hasAlphaChannel ? GL_RGBA8 : GL_RGB8 ),
texture.uWidth,
texture.uHeight,
0,
( texture.hasAlphaChannel ? GL_RGBA : GL_RGB ),
GL_UNSIGNED_BYTE,
&texture.vPixelData[0] );
if ( texture.generateMipMap && openglVersion.x >= 3 ) {
glGenerateMipmap( GL_TEXTURE_2D );
}
// Store TextureId
BlockThread blockThread( s_criticalSection );
m_textureInfos.insert( MapTextureInfos::value_type( strFilename, textureInfo ) );
if ( s_pSettings->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
Logger::log( std::string( "Created " ) + strFilename );
}
return textureInfo;
}
bool AssetStorage::removeTextureInfo( const std::string& strFilename ) {
MapTextureInfos::iterator itTexture = m_textureInfos.find( strFilename );
if ( itTexture == m_textureInfos.end() ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed. " << strFilename << " was not found in Asset Storage";
Logger::log( strStream );
return false;
}
if ( s_pSettings->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
Logger::log( std::string( "Destroyed " ) + strFilename );
}
glDeleteTextures( 1, &(itTexture->second.uTextureId) );
m_textureInfos.erase( itTexture );
return true;
}
bool AssetStorage::removeTextureInfo( unsigned uTextureId ) {
for ( MapTextureInfos::iterator itTexture = m_textureInfos.begin(); itTexture != m_textureInfos.end(); ++itTexture ) {
if ( uTextureId == itTexture->second.uTextureId ) {
if ( s_pSettings->isDebugLoggingEnabled( Settings::DEBUG_MEMORY ) ) {
Logger::log( std::string( "Destroyed " ) + itTexture->first );
}
glDeleteTextures( 1, &uTextureId );
m_textureInfos.erase( itTexture );
return true;
}
}
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed. TextureId[" << uTextureId << "] was not found in AssetStorage";
Logger::log( strStream, Logger::TYPE_WARNING );
return false;
}
void AssetStorage::showLoadedTextureInfo() const {
BlockThread blockThread( s_criticalSection );
Logger::log( "Loaded textures listed below: ", Logger::TYPE_CONSOLE );
for each ( const std::pair<std::string, TextureInfo>& texture in m_textureInfos ) {
std::ostringstream strStream;
strStream << "textureId(" << texture.second.uTextureId << ") "
<< "transparency(" << ( texture.second.hasTransparency ? "Y" : "N" ) << ") "
<< "size" << texture.second.size << " "
<< texture.first << std::endl;
Logger::log( strStream, Logger::TYPE_CONSOLE );
}
Logger::log( " ", Logger::TYPE_CONSOLE );
}
GuiElement* AssetStorage::getGuiElement( const std::string& strId, GuiType type ) const {
switch( type ) {
case GUI_SCREEN: {
return getGuiElement( strId, m_guiScreenAssets );
}
case GUI_RENDERABLE: {
return getGuiElement( strId, m_guiRenderableAssets );
}
default : {
std::ostringstream strStream;
strStream << __FUNCTION__ << "Unrecognzied guiType = " << type;
throw ExceptionHandler( strStream );
}
}
return nullptr;
}
GuiElement* AssetStorage::getGuiElement( const std::string& strId, const MapGuiAssets& guiMap ) const {
BlockThread blockThread( s_criticalSection );
MapGuiAssets::const_iterator itGuiAsset = guiMap.find( strId );
if ( itGuiAsset == guiMap.cend() ) {
return nullptr;
}
return itGuiAsset->second.get();
}
void AssetStorage::add( GuiElement* pGui, GuiType type ) {
if ( nullptr == pGui ) {
throw ExceptionHandler( __FUNCTION__ + std::string( " pGui==nullptr passed in" ) );
}
// Make Sure Name Is Unique Across All GuiElement Types
for ( int i = 0; i < GUI_UKNOWN; ++i ) {
if ( getGuiElement( pGui->getId(), (GuiType)i ) != nullptr ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " attempting to store " << pGui->getId() << " multiple times";
throw ExceptionHandler( strStream );
}
}
switch( type ) {
case GUI_SCREEN: {
add( pGui, m_guiScreenAssets );
break;
}
case GUI_RENDERABLE: {
add( pGui, m_guiRenderableAssets );
break;
}
default: {
std::ostringstream strStream;
strStream << __FUNCTION__ << " unrecognized GuiType = " << type;
}
}
}
void AssetStorage::add( GuiElement* pGui, MapGuiAssets& guiMap ) {
BlockThread blockThread( s_criticalSection );
guiMap.insert( MapGuiAssets::value_type( pGui->getId(), std::shared_ptr<GuiElement>( pGui ) ) );
}
template<>
bool AssetStorage::removeGuiElement( GuiScreen* pGui, bool removeTextures ) {
return removeGuiElement( pGui->getId(), m_guiScreenAssets, removeTextures );
}
template<>
bool AssetStorage::removeGuiElement( GuiRenderable* pGui, bool removeTextures ) {
return removeGuiElement( pGui->getId(), m_guiRenderableAssets, removeTextures );
}
bool AssetStorage::removeGuiElement( const std::string& strId, bool removeTextures ) {
// Find Which Type This Gui Element Is In
for ( int i = 0; i < GUI_UKNOWN; ++i ) {
GuiElement* pGui = getGuiElement( strId, (GuiType)i );
if ( pGui != nullptr ) {
// Found It
switch( static_cast<GuiType>( i ) ) {
case GUI_SCREEN: {
return removeGuiElement( pGui->getId(), m_guiScreenAssets, removeTextures );
}
case GUI_RENDERABLE: {
return removeGuiElement( pGui->getId(), m_guiRenderableAssets, removeTextures );
}
default: {
std::ostringstream strStream;
strStream << __FUNCTION__ << " unrecognized GuiType = " << i;
throw ExceptionHandler( strStream );
}
}
}
}
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed. " << strId << " was not found in AssetStorage";
Logger::log( strStream, Logger::TYPE_WARNING );
return false;
}
bool AssetStorage::removeGuiElement( const std::string& strId, MapGuiAssets& guiMap, bool removeTextures ) {
BlockThread blockThread( s_criticalSection );
MapGuiAssets::iterator itGuiAsset = guiMap.find( strId );
if ( itGuiAsset == guiMap.end() ) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed. " << strId << " was not found in AssetStorage";
Logger::log( strStream, Logger::TYPE_WARNING );
return false;
} else {
itGuiAsset->second.get()->setRemoveTextures( removeTextures );
guiMap.erase( itGuiAsset );
// When The Above Gui Was Deleted, There Might Have Been Some Children
// That Also Got Marked For Removal. We Can Remove Them Now Here
for ( unsigned i = 0; i < m_vGuiForRemoval.size(); ++i ) {
itGuiAsset = m_guiRenderableAssets.find( m_vGuiForRemoval[i] );
if ( itGuiAsset != m_guiRenderableAssets.end() ) {
// Remove This Gui
itGuiAsset->second.get()->setRemoveTextures( false );
m_guiRenderableAssets.erase( itGuiAsset );
} else {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed to find " << m_vGuiForRemoval[i] << " for removal from the m_guiRenderableAssets";
Logger::log( strStream, Logger::TYPE_WARNING );
}
}
m_vGuiForRemoval.clear();
return true;
}
}
void AssetStorage::markGuiForRemoval( const std::string& strId ) {
m_vGuiForRemoval.push_back( strId );
}
void AssetStorage::cleanOrphanedGuiObjects() {
}
void AssetStorage::showLoadedGuiObjects() const {
BlockThread blockThread( s_criticalSection );
// Reset Print Flags
for each( const std::pair<std::string, std::shared_ptr<GuiElement>>& gui in m_guiRenderableAssets ) {
GuiRenderable* pGui = dynamic_cast<GuiRenderable*>( gui.second.get() );
if ( pGui != nullptr ) {
pGui->resetPrinted();
}
}
if ( m_guiScreenAssets.size() > 0 ) {
Logger::log( "Loaded gui screen's: ", Logger::TYPE_CONSOLE );
for each ( const std::pair<std::string, std::shared_ptr<GuiElement>>& gui in m_guiScreenAssets ) {
gui.second.get()->print();
Logger::log( " ", Logger::TYPE_CONSOLE );
}
} else {
Logger::log( "There are no loaded gui screens.", Logger::TYPE_CONSOLE );
}
Logger::log( " ", Logger::TYPE_CONSOLE );
bool isMessageShown = false;
for each( const std::pair<std::string, std::shared_ptr<GuiElement>>& gui in m_guiRenderableAssets ) {
GuiRenderable* pGui = dynamic_cast<GuiRenderable*>( gui.second.get() );
if ( !pGui->wasPrinted() ) {
if ( !isMessageShown ) {
isMessageShown = true;
Logger::log( "Loaded gui renderables not attached to a screen: ", Logger::TYPE_CONSOLE );
}
pGui->print();
}
}
if ( isMessageShown ) {
Logger::log( " ", Logger::TYPE_CONSOLE );
}
}
} // /*namespace name here*/
它最初是在 Visual Studio 2010 和 12 中构建的,并已移植到 VS 2015,因此它没有使用所有 modern c++ 技术,但确实使用了 C++11 的许多功能。希望有一天我会把它移植到2017 版本以使用C++17。
我最初提议将所有存储的对象放在一个类中,但是对于任何类型的 3D 引擎,内存类的大小都会迅速爆炸,正如您从上面的 AssetStorage 类中看到的那样,因此可以提供帮助保持简单和模块化,我将它们分解为单独的管理类。