00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <multires_image/tile_cache.h>
00031
00032
00033 #include <cmath>
00034 #include <cstdlib>
00035 #include <algorithm>
00036 #include <iostream>
00037 #include <exception>
00038
00039
00040 #include <QApplication>
00041 #include <QEvent>
00042
00043 #include <multires_image/tile_set_layer.h>
00044
00045 namespace multires_image
00046 {
00047 TileCache::TileCache(TileSet* tileSet, QGLWidget* widget) :
00048 m_tileSet(tileSet),
00049 m_widget(widget),
00050 m_currentLayer(0),
00051 m_currentPosition(0, 0, 0),
00052 m_exit(false),
00053 m_memorySize(0),
00054 m_cacheThread(this),
00055 m_freeThread(this),
00056 m_renderRequestsLock(QMutex::Recursive),
00057 m_renderRequestSetLock(QMutex::Recursive),
00058 m_precacheRequestsLock(QMutex::Recursive),
00059 m_precacheRequestSetLock(QMutex::Recursive),
00060 m_textureLoadedLock(QMutex::Recursive)
00061 {
00062 connect(this, SIGNAL(SignalLoadTexture(Tile*)),
00063 SLOT(LoadTextureSlot(Tile*)), Qt::BlockingQueuedConnection);
00064
00065 connect(this, SIGNAL(SignalDeleteTexture(Tile*)),
00066 SLOT(DeleteTextureSlot(Tile*)), Qt::BlockingQueuedConnection);
00067
00068 m_cacheThread.setPriority(QThread::NormalPriority);
00069 m_cacheThread.start();
00070
00071 m_freeThread.setPriority(QThread::LowPriority);
00072 m_freeThread.start();
00073
00074 for (int i = 0; i < m_tileSet->LayerCount(); i++)
00075 {
00076 m_precacheRequests.push_back(std::queue<Tile*>());
00077 }
00078 }
00079
00080 TileCache::~TileCache(void)
00081 {
00082 m_exit = true;
00083 m_cacheThread.wait();
00084 m_freeThread.wait();
00085 }
00086
00087 void TileCache::LoadTextureSlot(Tile* tile)
00088 {
00089 tile->LoadTexture();
00090 }
00091
00092 void TileCache::DeleteTextureSlot(Tile* tile)
00093 {
00094 tile->UnloadTexture();
00095 }
00096
00097 void TileCache::Load(Tile* tile)
00098 {
00099 m_renderRequestsLock.lock();
00100 m_renderRequestSetLock.lock();
00101
00102 try
00103 {
00104 if (m_renderRequestSet.count(tile->TileID()) == 0)
00105 {
00106 m_renderRequests.push(tile);
00107 m_renderRequestSet[tile->TileID()] = tile;
00108 }
00109 }
00110 catch(const std::exception& e)
00111 {
00112 std::cout << "An exception occurred queuing a tile to be cached: " << e.what() << std::endl;
00113 }
00114
00115 m_renderRequestSetLock.unlock();
00116 m_renderRequestsLock.unlock();
00117 }
00118
00119 void TileCache::Precache(double x, double y)
00120 {
00121 tf::Point point(x, y, 0);
00122 Precache(point);
00123 }
00124
00125 void TileCache::Precache(const tf::Point& position)
00126 {
00127 m_currentPosition = position;
00128
00129 int sizes[] = {3, 2, 2, 1, 1, 1};
00130
00131 PrecacheLayer(m_currentLayer, m_currentPosition, sizes[0]);
00132
00133 for (int i = 1; i <= 5; i++)
00134 {
00135 int layer = m_currentLayer + i;
00136 if (layer < m_tileSet->LayerCount())
00137 {
00138 PrecacheLayer(layer, m_currentPosition, sizes[i]);
00139 }
00140
00141 layer = m_currentLayer - i;
00142 if (layer >= 0)
00143 {
00144 PrecacheLayer(layer, m_currentPosition, sizes[i]);
00145 }
00146 }
00147 }
00148
00149 void TileCache::PrecacheLayer(int layerNum, const tf::Point& position, int size)
00150 {
00151 TileSetLayer* layer = m_tileSet->GetLayer(layerNum);
00152
00153 int row, column;
00154 layer->GetTileIndex(position, row, column);
00155
00156 int startRow = std::max(0, row - size);
00157 int endRow = std::min(layer->RowCount() - 1, row + size);
00158 int startColumn = std::max(0, column - size);
00159 int endColumn = std::min(layer->ColumnCount() - 1, column + size);
00160
00161 for (int c = startColumn; c <= endColumn; c++)
00162 {
00163 for (int r = startRow; r <= endRow; r++)
00164 {
00165 Tile* tile = layer->GetTile(c, r);
00166
00167 m_precacheRequestsLock.lock();
00168 m_precacheRequestSetLock.lock();
00169
00170 try
00171 {
00172 if (m_precacheRequestSet.count(tile->TileID()) == 0)
00173 {
00174 m_precacheRequests[layerNum].push(tile);
00175 m_precacheRequestSet[tile->TileID()] = tile;
00176 }
00177 }
00178 catch (const std::exception& e)
00179 {
00180 std::cout << "An exception occurred queuing tiles for precaching: " << e.what() << std::endl;
00181 }
00182
00183 m_precacheRequestSetLock.unlock();
00184 m_precacheRequestsLock.unlock();
00185 }
00186 }
00187 }
00188
00189 void TileCache::Exit()
00190 {
00191 m_exit = true;
00192 }
00193
00194 void TileCache::LoadTexture(Tile* tile)
00195 {
00196 Q_EMIT SignalLoadTexture(tile);
00197
00198 m_memorySize += tile->MemorySize();
00199 Q_EMIT SignalMemorySize(m_memorySize);
00200
00201 m_textureLoadedLock.lock();
00202
00203 try
00204 {
00205 m_textureLoaded[tile->TileID()] = tile;
00206 }
00207 catch (const std::exception& e)
00208 {
00209 std::cout << "An exception occurred loading texture: " << e.what() << std::endl;
00210 }
00211
00212 m_textureLoadedLock.unlock();
00213
00214 if (tile->Layer() == m_currentLayer)
00215 {
00216 QApplication::postEvent(m_widget, new QEvent(QEvent::UpdateRequest));
00217 }
00218 }
00219
00220 void TileCache::UnloadTexture(Tile* tile)
00221 {
00222 Q_EMIT SignalDeleteTexture(tile);
00223
00224 m_memorySize -= tile->MemorySize();
00225 Q_EMIT SignalMemorySize(m_memorySize);
00226
00227 m_textureLoadedLock.lock();
00228
00229 try
00230 {
00231 m_textureLoaded.erase(tile->TileID());
00232 }
00233 catch (const std::exception& e)
00234 {
00235 std::cout << "An exception occurred unloading texture: " << e.what() << std::endl;
00236 }
00237
00238 m_textureLoadedLock.unlock();
00239 }
00240
00241 void TileCache::CacheThread::run()
00242 {
00243 while (!p->m_exit)
00244 {
00245 Tile* tile = NULL;
00246 p->m_renderRequestsLock.lock();
00247
00248 if (p->m_renderRequests.size() > 0)
00249 {
00250 tile = p->m_renderRequests.top();
00251 p->m_renderRequests.pop();
00252 }
00253
00254 p->m_renderRequestsLock.unlock();
00255
00256 if (tile != NULL)
00257 {
00258 if (!tile->Failed())
00259 {
00260 if (tile->Layer() == p->m_currentLayer)
00261 {
00262 int row, column;
00263 p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00264
00265 if (abs(tile->Row() - row) <= 3 || abs(tile->Column() - column) < 3)
00266 {
00267 if (!tile->TextureLoaded())
00268 {
00269 if (tile->LoadImageToMemory() == true)
00270 {
00271 p->LoadTexture(tile);
00272 tile->UnloadImage();
00273 }
00274 else
00275 {
00276 printf("failed to load image\n");
00277 }
00278 }
00279 }
00280 }
00281 else
00282 {
00283 p->m_precacheRequests[tile->Layer()].push(tile);
00284 }
00285
00286 p->m_renderRequestSetLock.lock();
00287 p->m_renderRequestSet.erase(tile->TileID());
00288 p->m_renderRequestSetLock.unlock();
00289 }
00290 else
00291 {
00292 }
00293 }
00294 else
00295 {
00296 p->m_precacheRequestsLock.lock();
00297
00298 try
00299 {
00300 for (uint32_t i = 0; (i < p->m_precacheRequests.size()) && (tile == NULL); i++)
00301 {
00302 int32_t index = p->m_currentLayer + i;
00303 if ((index < (int64_t)p->m_precacheRequests.size()) &&
00304 (p->m_precacheRequests[index].size() > 0))
00305 {
00306 tile = p->m_precacheRequests[index].front();
00307 p->m_precacheRequests[index].pop();
00308 }
00309 else if (i != 0)
00310 {
00311 index = p->m_currentLayer - i;
00312 if (index >= 0 && p->m_precacheRequests[index].size() > 0)
00313 {
00314 tile = p->m_precacheRequests[index].front();
00315 p->m_precacheRequests[index].pop();
00316 }
00317 }
00318 }
00319 }
00320 catch (const std::exception& e)
00321 {
00322 std::cout << "An exception occurred precaching texture: " << e.what() << std::endl;
00323 }
00324
00325 p->m_precacheRequestsLock.unlock();
00326
00327 if (tile != NULL && !tile->Failed() && !tile->TextureLoaded())
00328 {
00329 int row, column;
00330 p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00331 if (abs(tile->Row() - row) <= 3 || abs(tile->Column() - column) <= 3)
00332 {
00333 if (tile->LoadImageToMemory() == true)
00334 {
00335 p->LoadTexture(tile);
00336
00337 tile->UnloadImage();
00338 }
00339 else
00340 {
00341 printf("failed to precache load image\n");
00342 }
00343 }
00344
00345 p->m_precacheRequestSetLock.lock();
00346 p->m_precacheRequestSet.erase(tile->TileID());
00347 p->m_precacheRequestSetLock.unlock();
00348 }
00349 }
00350
00351 if (tile == NULL)
00352 {
00353 usleep(10);
00354 }
00355 }
00356 }
00357
00358 void TileCache::FreeThread::run()
00359 {
00360 while (!p->m_exit)
00361 {
00362 std::map<int64_t, Tile*>* tiles;
00363 p->m_textureLoadedLock.lock();
00364
00365 tiles = new std::map<int64_t, Tile*>(p->m_textureLoaded);
00366
00367 p->m_textureLoadedLock.unlock();
00368
00369 std::map<int64_t, Tile*>::iterator iter;
00370
00371 for (iter = tiles->begin(); iter != tiles->end(); ++iter)
00372 {
00373 Tile* tile = iter->second;
00374 int row, column;
00375 p->m_tileSet->GetLayer(tile->Layer())->GetTileIndex(p->m_currentPosition, row, column);
00376
00377 if (abs(tile->Row() - row) > 6 || abs(tile->Column() - column) > 6)
00378 {
00379 p->m_renderRequestSetLock.lock();
00380 p->m_renderRequestSet.erase(tile->TileID());
00381 p->m_renderRequestSetLock.unlock();
00382
00383 p->m_precacheRequestSetLock.lock();
00384 p->m_precacheRequestSet.erase(tile->TileID());
00385 p->m_precacheRequestSetLock.unlock();
00386
00387 p->UnloadTexture(tile);
00388 }
00389 }
00390
00391 delete tiles;
00392
00393 sleep(2);
00394 }
00395 }
00396 }