борется с управлением памятью в с ++ и opengl - PullRequest
0 голосов
/ 13 декабря 2018

Я борюсь с управлением памятью в проекте c ++, который у меня есть.(просто интересный проект, чтобы учиться) На данный момент это в основном средство просмотра 3D-файлов, созданное с помощью glfw, opengl, glm и assimp.Я могу успешно загрузить некоторые файлы сетки и отобразить их в окне с помощью шейдера, даже отобразить текстуру!whaou
Я даже могу отображать несколько объектов, что было не так просто, как я.

«База кода» все еще довольно мала, но достаточно велика, чтобы я мог совершить много ошибок.

Таким образом, в основном все работает как положено, но при том факте, что при загрузке нового файла сетки программа никогда не освобождает память;иногда он уменьшается на 1 или 2 Мб, но кроме этого, объем памяти плеера продолжает расти (хотя, конечно, только когда я загружаю объект, но не постоянно во время выполнения программы)

Я перепробовал почти все, что мог придуматьуправлять памятью.Но ничто, что я делаю, не имеет никакого эффектаЯ пытался сильно ограничить использование «new», так как понимаю, что управлять им немного сложнее (т.е. нужно вручную удалять). Я также пытался везде, где только можно, очищать std :: vectors, когда они мне больше не нужны, с помощьюФункция clear ()

Я поставлю свой main.cpp здесь, может быть, проблема там.Все исходные файлы можно найти в https://github.com/gui2one/angine

#include <iostream>
#include "application.h"
#include "pch.h"

#include "generators/gridmesh.h"
#include "generators/spheremesh.h"

Object* obj1 = new Object();

int nCols = 4;
Application app ;

Mesh loadNewObject(){
    char file[1024];
    FILE *f = popen("zenity --file-selection --title='choose a 3d file' ", "r");
    fgets(file, 1024, f);   
    std::cout << "Loading -> "<<file << "\n";           
    ObjLoader loader;
    Mesh mesh;
    std::string str(file);

    str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());

    mesh = loader.assimp_load(str);

    return mesh;
}

void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
    std::cout << "key ->" << key << ", scancode --> "<< scancode << "\n";
    if (key == GLFW_KEY_UP && action == GLFW_PRESS){

        nCols +=3;

        obj1->mesh.clearAll();

        SphereMesh* sphere = new SphereMesh();
        sphere->generate(obj1->mesh,20,nCols);

        delete sphere;

        std::cout << nCols << "\n";
        obj1->buildVbo();

    }else if (key == GLFW_KEY_DOWN && action == GLFW_PRESS){
        if( nCols > 4){
            nCols -=3;
            obj1->mesh.clearAll();

            SphereMesh* sphere = new SphereMesh();
            sphere->generate(obj1->mesh,20,nCols);

            delete sphere;
            std::cout << nCols << "\n";
            obj1->buildVbo();

        }
    }else if (key == 79 /* letter o*/ && action == GLFW_PRESS){

        nCols -=3;
        obj1->mesh.clearAll();
        obj1->mesh = loadNewObject();
        std::cout << nCols << "\n";
        obj1->buildVbo();
    }
}

int main(){



    std::cout << "angine PROJECT\n";

    //obj1->mesh = loadNewObject();

    SphereMesh* sphere = new SphereMesh();
    sphere->generate(obj1->mesh,20,nCols);        
    delete sphere;

    obj1->color->x = 0.9;
    obj1->color->y = 0.8;
    obj1->color->z = 0.5;
    obj1->color->w = 1.0;

    obj1->position->x = 1.2f;

    obj1->shader.loadVertexShaderSource("../src/res/shaders/basic_shader.vert");
    obj1->shader.loadFragmentShaderSource("../src/res/shaders/basic_shader.frag");  

    obj1->buildVbo();
    obj1->buildTexture();
    obj1->shader.createShader();


    app.objects.push_back(obj1);




    app.window.objects = app.objects;

    glfwSetKeyCallback(app.window.win, key_callback);
    while(!app.window.shouldClose()){



        app.window.refresh();
        obj1->rotation->x = glfwGetTime()*0.2;
        obj1->rotation->y = glfwGetTime()*0.13;
        obj1->rotation->z = glfwGetTime()*0.11;


    }

    return 0;
}

классе, отвечающем за загрузку данных сетки ObjLoader:

ObjLoader.h:

#ifndef OBJLOADER_H
#define OBJLOADER_H
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <stdio.h>

#include "../mesh.h"
#include "../vector3.h"

#include "../include/assimp/cimport.h"
#include "../include/assimp/scene.h"
#include "../include/assimp/postprocess.h"

class ObjLoader{
    public:
        Mesh assimp_load(std::string file_path);

};

#endif

ObjLoader.cpp:

Mesh ObjLoader::assimp_load(std::string file_path){

    const struct aiScene* scene = NULL;
    scene = aiImportFile(file_path.c_str(), aiProcessPreset_TargetRealtime_MaxQuality);

    if(scene){


        std::vector<Vertex> vertices;
        std::vector<float> positions;
        std::vector<float> normals;
        for (int i = 0; i < scene->mMeshes[0]->mNumFaces; i++)
        {
            Vertex vertex;

            for (int j = 0; j < scene->mMeshes[0]->mFaces[i].mNumIndices; j++)
            {
                    int index = scene->mMeshes[0]->mFaces[i].mIndices[j];

                    vertex.position.x = scene->mMeshes[0]->mVertices[index].x;
                    vertex.position.y = scene->mMeshes[0]->mVertices[index].y;
                    vertex.position.z = scene->mMeshes[0]->mVertices[index].z;

                    vertex.normal.x = scene->mMeshes[0]->mNormals[index].x;
                    vertex.normal.y = scene->mMeshes[0]->mNormals[index].y;
                    vertex.normal.z = scene->mMeshes[0]->mNormals[index].z;



                    if(scene->mMeshes[0]->HasTextureCoords(0)){

                        //~ std::cout << scene->mMeshes[0]->mTextureCoords[0][index].x  << "-------------"<< "\n";
                        vertex.t_coords.x = scene->mMeshes[0]->mTextureCoords[0][index].x;
                        vertex.t_coords.y = scene->mMeshes[0]->mTextureCoords[0][index].y;
                    }


                    vertices.push_back(vertex);

                    positions.push_back(scene->mMeshes[0]->mVertices[index].x);
                    positions.push_back(scene->mMeshes[0]->mVertices[index].y);
                    positions.push_back(scene->mMeshes[0]->mVertices[index].z);
            }

        }
        Mesh mesh;

        mesh.vertices = vertices;

        //// trying to delete everything I can
        delete scene;
        vertices.clear();
        positions.clear();
        normals.clear();

        return mesh;
    }else{
        Mesh empty_mesh;
        return empty_mesh;
    }


}

Дело в том, что проблема остается даже тогда, когда этот класс не используется для загрузки сетки, а генерирует сетку процедурно.Я не могу публиковать здесь все, но у меня также есть код opengl для рисования этих мешей.Здесь я также пытаюсь «очистить» все и отменить привязку буферов gl после их использования.

У меня нет идей.Я понимаю, что этот вопрос довольно расплывчатый.я попытаюсь сделать это более точным, поскольку я исследую больше, но мне действительно нужна помощь, чтобы понять.

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

Я наконец-то нашел, в чем проблема в моем коде.Я загружал данные в постоянный объект с некоторыми

glGenBuffers() 

, но я никогда не использовал

glDeleteBuffers(1,&m_id)

. Я представляю, что каждый раз, когда я вызывал glGenBuffers (1, & m_id);opengl создает совершенно новый буфер, поэтому я должен очистить его раньше.

Моя программа теперь использует нормальный объем памяти.

0 голосов
/ 13 декабря 2018

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...