Трудно сказать, просто прочитав исходный код, не сидя там и не пройдя через отладчик, который вручную просматривает все динамическое распределение памяти и освобождение объектов.Это довольно громоздкая задача.Может быть довольно сложно дать решительный ответ.Здесь я могу предложить вам несколько советов, поскольку в прошлом я создавал движки для 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
и т. Д., Которые сами являются Singleton
, и я не буду здесь их показывать.Это не скомпилируется на вашем компьютере.
Мой класс 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 Engine класс памяти очень быстро увеличится в размерах, как вы можете видеть из AssetStorage
класс выше, поэтому, чтобы упростить и упростить задачу, я разбил их на отдельные классы управления.