#include // TnzCore includes #include "tgl.h" // TnzExt includes #include "ext/meshtexturizer.h" // tcg includes #include "tcg/tcg_list.h" // Qt includes #include #include #include #include #include "ext/ttexturesstorage.h" //*************************************************************************************** // Local namespace - structures //*************************************************************************************** struct TexturesContainer { MeshTexturizer m_texturizer; //!< The mesh texturizer - actual textures container tcg::list m_keys; //!< Keys in the storage public: TexturesContainer() {} private: TexturesContainer(const TexturesContainer &); TexturesContainer &operator=(const TexturesContainer &); }; //*************************************************************************************** // Local namespace - variables //*************************************************************************************** namespace { QMutex l_mutex(QMutex::Recursive); // A mutex is needed to synchronize access // to the following objects std::map l_texturesContainers; // Texture Containers by display lists space id QCache l_objects(500 * 1024); // 500 MB cache // for now - NOTE: // MUST be // allocated // before the // following } // namespace //*************************************************************************************** // Local namespace - global functions //*************************************************************************************** namespace { inline QString textureString(int dlSpaceId, const std::string &texId) { return QString::number(dlSpaceId) + "_" + QString::fromStdString(texId); } //------------------------------------------------------------------------------------- inline void deleteTexturesContainer( const std::pair &pair) { delete pair.second; } } //*************************************************************************************** // DrawableTextureData implementation //*************************************************************************************** DrawableTextureData::~DrawableTextureData() { QMutexLocker locker(&l_mutex); TexturesContainer *texContainer = l_texturesContainers[m_dlSpaceId]; if (m_dlSpaceId >= 0) { // Load the container's display lists space (remember current OpenGL // context, too) TGLDisplayListsProxy *proxy = TGLDisplayListsManager::instance()->dlProxy(m_dlSpaceId); TGlContext currentContext = tglGetCurrentContext(); // Unbind the textures { QMutexLocker locker(proxy->mutex()); proxy->makeCurrent(); texContainer->m_texturizer.unbindTexture(m_texId); } // Restore OpenGL context - equivalent to tglDoneCurrent if currentContext // == TGlContext() tglMakeCurrent(currentContext); } else // Temporary - use current OpenGL context directly texContainer->m_texturizer.unbindTexture(m_texId); texContainer->m_keys.erase(m_objIdx); } //*************************************************************************************** // TTexturesStorage implementation //*************************************************************************************** TTexturesStorage::TTexturesStorage() { // This singleton is dependent on TGLDisplayListsManager TGLDisplayListsManager::instance()->addObserver(this); } //------------------------------------------------------------------------------------- TTexturesStorage::~TTexturesStorage() { l_objects.clear(); std::for_each(l_texturesContainers.begin(), l_texturesContainers.end(), deleteTexturesContainer); } //------------------------------------------------------------------------------------- TTexturesStorage *TTexturesStorage::instance() { static TTexturesStorage theInstance; return &theInstance; } //------------------------------------------------------------------------------------- DrawableTextureDataP TTexturesStorage::loadTexture(const std::string &textureId, const TRaster32P &ras, const TRectD &geometry) { // Try to retrieve the proxy associated to current OpenGL context TGlContext currentContext = tglGetCurrentContext(); int dlSpaceId = TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext); QString texString(::textureString(dlSpaceId, textureId)); // Deal with containers QMutexLocker locker(&l_mutex); // If necessary, allocate a textures container std::map::iterator it = l_texturesContainers.find(dlSpaceId); if (it == l_texturesContainers.end()) it = l_texturesContainers .insert(std::make_pair(dlSpaceId, new TexturesContainer)) .first; MeshTexturizer &texturizer = it->second->m_texturizer; DrawableTextureDataP dataPtr = std::make_shared(); DrawableTextureData *data = dataPtr.get(); data->m_dlSpaceId = dlSpaceId; data->m_texId = texturizer.bindTexture(ras, geometry); data->m_objIdx = it->second->m_keys.push_back(texString); data->m_textureData = texturizer.getTextureData(data->m_texId); l_objects.insert(texString, new DrawableTextureDataP(dataPtr), (ras->getLx() * ras->getLy() * ras->getPixelSize()) >> 10); if (dlSpaceId < 0) { // obj is a temporary. It was pushed in the cache to make space for it - // however, it must not be // stored. Remove it now. l_objects.remove(texString); } return dataPtr; } //------------------------------------------------------------------------------------- void TTexturesStorage::unloadTexture(const std::string &textureId) { QMutexLocker locker(&l_mutex); // Remove the specified texture from ALL the display lists spaces std::map::iterator it, iEnd(l_texturesContainers.end()); for (it = l_texturesContainers.begin(); it != iEnd; ++it) l_objects.remove(::textureString(it->first, textureId)); } //----------------------------------------------------------------------------------- void TTexturesStorage::onDisplayListDestroyed(int dlSpaceId) { QMutexLocker locker(&l_mutex); // Remove the textures container associated with dlSpaceId std::map::iterator it = l_texturesContainers.find(dlSpaceId); if (it == l_texturesContainers.end()) return; tcg::list::iterator st, sEnd(it->second->m_keys.end()); for (st = it->second->m_keys.begin(); st != sEnd;) // Note that the increment // is performed BEFORE the // texture is removed. l_objects.remove(*st++); // This is because texture removal may destroy the // key being addressed, // whose iterator would then be invalidated. delete it->second; l_texturesContainers.erase(it); } //------------------------------------------------------------------------------------- DrawableTextureDataP TTexturesStorage::getTextureData( const std::string &textureId) { // Get current display lists space TGlContext currentContext = tglGetCurrentContext(); int dlSpaceId = TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext); // If there is no known associated display lists space, the texture cannot be // stored. if (dlSpaceId < 0) return DrawableTextureDataP(); QMutexLocker locker(&l_mutex); // Search the texture object QString texString(::textureString(dlSpaceId, textureId)); if (!l_objects.contains(texString)) return DrawableTextureDataP(); return *l_objects.object(texString); }