1 #include <memory>
2
3 // TnzCore includes
4 #include "tgl.h"
5
6 // TnzExt includes
7 #include "ext/meshtexturizer.h"
8
9 // tcg includes
10 #include "tcg/tcg_list.h"
11
12 // Qt includes
13 #include <QString>
14 #include <QCache>
15 #include <QMutex>
16 #include <QMutexLocker>
17
18 #include "ext/ttexturesstorage.h"
19
20 //***************************************************************************************
21 // Local namespace - structures
22 //***************************************************************************************
23
24 struct TexturesContainer {
25 MeshTexturizer
26 m_texturizer; //!< The mesh texturizer - actual textures container
27 tcg::list<QString> m_keys; //!< Keys in the storage
28
29 public:
TexturesContainerTexturesContainer30 TexturesContainer() {}
31
32 private:
33 TexturesContainer(const TexturesContainer &);
34 TexturesContainer &operator=(const TexturesContainer &);
35 };
36
37 //***************************************************************************************
38 // Local namespace - variables
39 //***************************************************************************************
40
41 namespace {
42
43 QMutex l_mutex(QMutex::Recursive); // A mutex is needed to synchronize access
44 // to the following objects
45
46 std::map<int, TexturesContainer *>
47 l_texturesContainers; // Texture Containers by display lists space id
48 QCache<QString, DrawableTextureDataP> l_objects(500 * 1024); // 500 MB cache
49 // for now - NOTE:
50 // MUST be
51 // allocated
52 // before the
53 // following
54
55 } // namespace
56
57 //***************************************************************************************
58 // Local namespace - global functions
59 //***************************************************************************************
60
61 namespace {
62
textureString(int dlSpaceId,const std::string & texId)63 inline QString textureString(int dlSpaceId, const std::string &texId) {
64 return QString::number(dlSpaceId) + "_" + QString::fromStdString(texId);
65 }
66
67 //-------------------------------------------------------------------------------------
68
deleteTexturesContainer(const std::pair<int,TexturesContainer * > & pair)69 inline void deleteTexturesContainer(
70 const std::pair<int, TexturesContainer *> &pair) {
71 delete pair.second;
72 }
73 }
74
75 //***************************************************************************************
76 // DrawableTextureData implementation
77 //***************************************************************************************
78
~DrawableTextureData()79 DrawableTextureData::~DrawableTextureData() {
80 QMutexLocker locker(&l_mutex);
81
82 TexturesContainer *texContainer = l_texturesContainers[m_dlSpaceId];
83
84 if (m_dlSpaceId >= 0) {
85 // Load the container's display lists space (remember current OpenGL
86 // context, too)
87 TGLDisplayListsProxy *proxy =
88 TGLDisplayListsManager::instance()->dlProxy(m_dlSpaceId);
89
90 TGlContext currentContext = tglGetCurrentContext();
91
92 // Unbind the textures
93 {
94 QMutexLocker locker(proxy->mutex());
95
96 proxy->makeCurrent();
97 texContainer->m_texturizer.unbindTexture(m_texId);
98 }
99
100 // Restore OpenGL context - equivalent to tglDoneCurrent if currentContext
101 // == TGlContext()
102 tglMakeCurrent(currentContext);
103 } else
104 // Temporary - use current OpenGL context directly
105 texContainer->m_texturizer.unbindTexture(m_texId);
106
107 texContainer->m_keys.erase(m_objIdx);
108 }
109
110 //***************************************************************************************
111 // TTexturesStorage implementation
112 //***************************************************************************************
113
TTexturesStorage()114 TTexturesStorage::TTexturesStorage() {
115 // This singleton is dependent on TGLDisplayListsManager
116 TGLDisplayListsManager::instance()->addObserver(this);
117 }
118
119 //-------------------------------------------------------------------------------------
120
~TTexturesStorage()121 TTexturesStorage::~TTexturesStorage() {
122 l_objects.clear();
123 std::for_each(l_texturesContainers.begin(), l_texturesContainers.end(),
124 deleteTexturesContainer);
125 }
126
127 //-------------------------------------------------------------------------------------
128
instance()129 TTexturesStorage *TTexturesStorage::instance() {
130 static TTexturesStorage theInstance;
131 return &theInstance;
132 }
133
134 //-------------------------------------------------------------------------------------
135
loadTexture(const std::string & textureId,const TRaster32P & ras,const TRectD & geometry)136 DrawableTextureDataP TTexturesStorage::loadTexture(const std::string &textureId,
137 const TRaster32P &ras,
138 const TRectD &geometry) {
139 // Try to retrieve the proxy associated to current OpenGL context
140 TGlContext currentContext = tglGetCurrentContext();
141 int dlSpaceId =
142 TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext);
143
144 QString texString(::textureString(dlSpaceId, textureId));
145
146 // Deal with containers
147 QMutexLocker locker(&l_mutex);
148
149 // If necessary, allocate a textures container
150 std::map<int, TexturesContainer *>::iterator it =
151 l_texturesContainers.find(dlSpaceId);
152 if (it == l_texturesContainers.end())
153 it = l_texturesContainers
154 .insert(std::make_pair(dlSpaceId, new TexturesContainer))
155 .first;
156
157 MeshTexturizer &texturizer = it->second->m_texturizer;
158
159 DrawableTextureDataP dataPtr = std::make_shared<DrawableTextureData>();
160 DrawableTextureData *data = dataPtr.get();
161
162 data->m_dlSpaceId = dlSpaceId;
163 data->m_texId = texturizer.bindTexture(ras, geometry);
164 data->m_objIdx = it->second->m_keys.push_back(texString);
165 data->m_textureData = texturizer.getTextureData(data->m_texId);
166
167 l_objects.insert(texString, new DrawableTextureDataP(dataPtr),
168 (ras->getLx() * ras->getLy() * ras->getPixelSize()) >> 10);
169
170 if (dlSpaceId < 0) {
171 // obj is a temporary. It was pushed in the cache to make space for it -
172 // however, it must not be
173 // stored. Remove it now.
174 l_objects.remove(texString);
175 }
176
177 return dataPtr;
178 }
179
180 //-------------------------------------------------------------------------------------
181
unloadTexture(const std::string & textureId)182 void TTexturesStorage::unloadTexture(const std::string &textureId) {
183 QMutexLocker locker(&l_mutex);
184
185 // Remove the specified texture from ALL the display lists spaces
186 std::map<int, TexturesContainer *>::iterator it,
187 iEnd(l_texturesContainers.end());
188 for (it = l_texturesContainers.begin(); it != iEnd; ++it)
189 l_objects.remove(::textureString(it->first, textureId));
190 }
191
192 //-----------------------------------------------------------------------------------
193
onDisplayListDestroyed(int dlSpaceId)194 void TTexturesStorage::onDisplayListDestroyed(int dlSpaceId) {
195 QMutexLocker locker(&l_mutex);
196
197 // Remove the textures container associated with dlSpaceId
198 std::map<int, TexturesContainer *>::iterator it =
199 l_texturesContainers.find(dlSpaceId);
200 if (it == l_texturesContainers.end()) return;
201
202 tcg::list<QString>::iterator st, sEnd(it->second->m_keys.end());
203
204 for (st = it->second->m_keys.begin(); st != sEnd;) // Note that the increment
205 // is performed BEFORE the
206 // texture is removed.
207 l_objects.remove(*st++); // This is because texture removal may destroy the
208 // key being addressed,
209 // whose iterator would then be invalidated.
210 delete it->second;
211 l_texturesContainers.erase(it);
212 }
213
214 //-------------------------------------------------------------------------------------
215
getTextureData(const std::string & textureId)216 DrawableTextureDataP TTexturesStorage::getTextureData(
217 const std::string &textureId) {
218 // Get current display lists space
219 TGlContext currentContext = tglGetCurrentContext();
220 int dlSpaceId =
221 TGLDisplayListsManager::instance()->displayListsSpaceId(currentContext);
222
223 // If there is no known associated display lists space, the texture cannot be
224 // stored.
225 if (dlSpaceId < 0) return DrawableTextureDataP();
226
227 QMutexLocker locker(&l_mutex);
228
229 // Search the texture object
230 QString texString(::textureString(dlSpaceId, textureId));
231 if (!l_objects.contains(texString)) return DrawableTextureDataP();
232
233 return *l_objects.object(texString);
234 }
235