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