source: Revenant/geoworld/src/gwpaging.cpp@ 8125274

port/mars-tycoon
Last change on this file since 8125274 was 80a6a52, checked in by Jonathan Neufeld <support@…>, 3 years ago

Get to a compile state for terrain procedural generation

  • Property mode set to 100644
File size: 18.8 KB
RevLine 
[80a6a52]1#include "gwpaging.h"
2
3#include <mars_ptr.h>
4#include <sstream>
5
6namespace geoworld
7{
8 PagingStore::PageMutexProvider::PageMutexProvider( const unsigned int nCellsX, const unsigned int nCellsY )
9 : _nW(nCellsX), _nH(nCellsY), _szLen (nCellsX * nCellsY)
10 {
11 _ppShMutexes = new boost::shared_mutex * [_szLen];
12
13 for (size_t c = 0; c < _szLen; ++c)
14 _ppShMutexes[c] = new boost::shared_mutex();
15 }
16
17 PagingStore::PageMutexProvider::~PageMutexProvider()
18 {
19 for (size_t c = 0; c < _szLen; ++c)
20 delete _ppShMutexes[c];
21
22 delete [] _ppShMutexes;
23 }
24
25 size_t PagingStore::PageMutexProvider::idx( const long nPageX, const long nPageY ) const
26 {
27 return mars::WRAP(nPageY, _nH) * _nW + mars::WRAP(nPageX, _nW);
28 }
29
30 PagingStore::PageMutexProvider::NeighborhoodMutex PagingStore::PageMutexProvider::acquireNeighborhood( const long nPageX, const long nPageY )
31 {
32 boost::shared_mutex * ppNeigh[NeighborhoodMutex::TotalSpots];
33
34 ppNeigh[NeighborhoodMutex::N] = _ppShMutexes[idx(nPageX, nPageY - 1)];
35 ppNeigh[NeighborhoodMutex::W] = _ppShMutexes[idx(nPageX - 1, nPageY)];
36 ppNeigh[NeighborhoodMutex::C] = _ppShMutexes[idx(nPageX, nPageY)];
37 ppNeigh[NeighborhoodMutex::E] = _ppShMutexes[idx(nPageX + 1, nPageY)];
38 ppNeigh[NeighborhoodMutex::S] = _ppShMutexes[idx(nPageX, nPageY + 1)];
39
40 return NeighborhoodMutex(ppNeigh);
41 }
42
43 GeoWorldPage * PagingStore::requestPage( const unsigned int nPageX, const unsigned int nPageY )
44 {
45 GeoWorldPage * pPage;
46
47 assert(nPageX < getNumPagesWide() && nPageY < getNumPagesHigh());
48
49 { GW_SCOPED_LOCK(mtxMaster);
50 LOG(mars::Log::Debug)
51 << "Loading DEM for page " << nPageX << "x" << nPageY;
52
53 _pFile->tilemap.seekg(nPageX, nPageY, std::ios::beg);
54 _pFile->tilemap >> *_pUtilityBlock;
55 pPage = new GeoWorldPage(*_pUtilityBlock, nPageX, nPageY, _pFile->getWorldDepth(), _pFile->geohost.count);
56 }
57
58 GeoWorldPage::Interface page(pPage->acquireInterface());
59 InstanceFile * pInst;
60
61 { PageMutexProvider::NeighborhoodMutex
62 neighborhood = _pMutexProvider->acquireNeighborhood(nPageX, nPageY); // Will block if any neighbor pages are busy rendering
63
64 LOG(mars::Log::Debug)
65 << "Acquired read lock on " << nPageX << "x" << nPageY << ", checking for an instance file...";
66 pInst = loadInstanceFile(nPageX, nPageY);
67
68 if (pInst == NULL)
69 {
70 LOG(mars::Log::Debug)
71 << "Instance file non-existent, preparing to generate page " << nPageX << "x" << nPageY;
72
73 neighborhood.genLock();
74
75 LOG(mars::Log::Debug)
76 << "Write-lock acquired for page " << nPageX << "x" << nPageY << " and for neighboring tiles";
77
78 // Check again to see if this was actually a bogus redundant page request and the first thread already did the generating
79 pInst = loadInstanceFile(nPageX, nPageY);
80 if (pInst == NULL)
81 {
82 pInst = new InstanceFile(_pFile->getPhysicalTileDim(), _pFile->getWorldDepth(), _pFile->geohost.count);
83
84 mars::ptr< FileSource::MineralHostMap::LayerMap::Block >
85 pLayerBlock = _pFile->geohost.createLayerBlock();
86 mars::ptr< FileSource::MineralHostMap::TopDEM::Block >
87 pHeightBlock = _pFile->geohost.createTopDEMBlock();
88 enum Neighbor
89 {
90 N = 0,
91 W = 1,
92 E = 2,
93 S = 3
94 };
95 InstanceFile * pInstNeighbors[4];
96 // Use virtual tile dim here (a power of 2) because MPDG will automatically add one unit to make non-even dimensions as is required.
97 GeoStratumMPDG * pLayerMPDG = GeoStratumMPDG::createInstance(_pFile->getVirtualTileDim(), _pFile->getVirtualTileDim(), mars::Normal);
98 GeoHeightMPDG * pHeightMPDG = GeoHeightMPDG::createInstance(_pFile->getVirtualTileDim(), _pFile->getVirtualTileDim(), mars::Normal);
99
100 // TODO: Cache loaded instance files
101 pInstNeighbors[W] = loadInstanceFile(mars::WRAP(static_cast< signed long > (nPageX) - 1, getNumPagesWide()), nPageY);
102 pInstNeighbors[E] = loadInstanceFile(mars::WRAP(static_cast< signed long > (nPageX) + 1, getNumPagesWide()), nPageY);
103 pInstNeighbors[N] = loadInstanceFile(nPageX, mars::WRAP(static_cast< signed long > (nPageY) - 1, getNumPagesHigh()));
104 pInstNeighbors[S] = loadInstanceFile(nPageX, mars::WRAP(static_cast< signed long > (nPageY) + 1, getNumPagesHigh()));
105
106 { GW_SCOPED_LOCK(mtxMaster);
107 _pFile->geohost.top.seekg(nPageX, nPageY, std::ios::beg);
108 _pFile->geohost.top >> *pHeightBlock;
109 }
110
111 pHeightMPDG->clear();
112 pHeightMPDG->seedFrom(*pHeightBlock, 0, 0, _pFile->geohost.getLOD());
113
114 int nStitch = 0;
115 if (pInstNeighbors[W] != NULL)
116 nStitch |= mars::StitchLeft;
117 if (pInstNeighbors[E] != NULL)
118 nStitch |= mars::StitchRight;
119 if (pInstNeighbors[N] != NULL)
120 nStitch |= mars::StitchTop;
121 if (pInstNeighbors[S] != NULL)
122 nStitch |= mars::StitchBottom;
123
124 LOG(mars::Log::Debug) << "Stitch Flags: " << nStitch;
125 pHeightMPDG->stitchAll(
126 nStitch,
127 pInstNeighbors[W] == NULL ? NULL : & pInstNeighbors[W]->getStratum().getBase(),
128 pInstNeighbors[N] == NULL ? NULL : & pInstNeighbors[N]->getStratum().getBase(),
129 pInstNeighbors[E] == NULL ? NULL : & pInstNeighbors[E]->getStratum().getBase(),
130 pInstNeighbors[S] == NULL ? NULL : & pInstNeighbors[S]->getStratum().getBase()
131 );
132
133 pHeightMPDG->run(mars::RANDf(1.0f), nStitch); // TODO: Export coarseness constant
134 pInst->top() << *pHeightMPDG;
135
136 for (unsigned short c = 0; c < _pFile->geohost.count; ++c)
137 {
138 FileSource::MineralHostMap::LayerMap & layer = _pFile->geohost.layer(c);
139
140 { GW_SCOPED_LOCK(mtxMaster);
141 layer.seekg(nPageX, nPageY, std::ios::beg);
142 layer >> *pLayerBlock;
143 }
144
145 assert(pLayerBlock->range().minimum.altitude >= 0);
146
147 pLayerMPDG->clear();
148 pLayerMPDG->seedFrom(*pLayerBlock, 0, 0, _pFile->geohost.getLOD());
149 layer.putDefs(*pLayerMPDG);
150
151 nStitch = 0;
152 if (pInstNeighbors[W] != NULL)
153 nStitch |= mars::StitchLeft;
154 if (pInstNeighbors[E] != NULL)
155 nStitch |= mars::StitchRight;
156 if (pInstNeighbors[N] != NULL)
157 nStitch |= mars::StitchTop;
158 if (pInstNeighbors[S] != NULL)
159 nStitch |= mars::StitchBottom;
160
161 LOG(mars::Log::Debug) << "Stitch Flags: " << nStitch;
162 pLayerMPDG->stitchAll(
163 nStitch,
164 pInstNeighbors[W] == NULL ? NULL : & pInstNeighbors[W]->layer(c),
165 pInstNeighbors[N] == NULL ? NULL : & pInstNeighbors[N]->layer(c),
166 pInstNeighbors[E] == NULL ? NULL : & pInstNeighbors[E]->layer(c),
167 pInstNeighbors[S] == NULL ? NULL : & pInstNeighbors[S]->layer(c)
168 );
169
170 pLayerMPDG->run(mars::RANDf(1.0f), nStitch); // TODO: Export coarseness constant
171
172 pInst->layer(c) << *pLayerMPDG;
173 assert(pInst->layer(c).elementCount() > 0);
174 }
175
176 pInst->getStratum().updateIndexMap();
177
178 delete pHeightMPDG;
179 delete pLayerMPDG;
180
181 delete pInstNeighbors[N];
182 delete pInstNeighbors[S];
183 delete pInstNeighbors[W];
184 delete pInstNeighbors[E];
185
186 FileSource::MineralMap::TileResult * pMinerals;
187
188 { GW_SCOPED_LOCK(mtxMaster);
189 pMinerals = new FileSource::MineralMap::TileResult(_pFile->minerals(nPageX, nPageY));
190 }
191
192 for (FileSource::MineralMap::TileResult::const_iterator i = pMinerals->begin();
193 i != pMinerals->end();
194 ++i
195 )
196 {
197 // TODO: LookupTree API is too rigid
198 page.minerals.add(new MineralPtr((*i).first), OctTreeMineralDeposits::MyRadialRegion((*i).second));
199 }
200 delete pMinerals;
201
202 LOG(mars::Log::Debug)
203 << "Writing generated instance file to disk for page " << nPageX << "x" << nPageY;
204
205 InstanceFile::write(makeFilename(nPageX, nPageY), pInst);
206 } else
207 LOG(mars::Log::Debug)
208 << "Bogus redundant request, page was already generated, using its instance file instead";
209 }
210 }
211
212 LOGD << "Out of critical section for " << nPageX << "x" << nPageY;
213
214 pInst->getStratum() >> page.stratum;
215 delete pInst;
216
217 LOGD << "Page for " << nPageX << "x" << nPageY << " loaded";
218
219 return pPage;
220 }
221
222 void PagingStore::releasePage( GeoWorldPage * pPage )
223 {
224 delete pPage;
225 }
226
227 PagingStore::~PagingStore()
228 {
229 delete _pMutexProvider;
230 delete _pUtilityBlock;
231 delete _pFile;
232 }
233
234 PagingStore::PagingStore( const std::string & sFileName, const std::string & sStoreDirectory, const std::string & sFilePrefix /*= "gwpage-"*/, const std::string & sFileSuffix /*= ".gwp"*/ )
235 : _pFile(NULL), _pUtilityBlock(NULL), _sFilePrefix(sFilePrefix), _sFileSuffix(sFileSuffix), _sStoreDirectory(sStoreDirectory)
236 {
237 _pFile = FileSource::open(sFileName);
238 _pFile->load();
239 _pUtilityBlock = _pFile->tilemap.createBlock();
240 _pMutexProvider = new PageMutexProvider(_pFile->getTilesWide(), _pFile->getTilesHigh());
241 }
242
243 std::string PagingStore::makeFilename( const unsigned int nPageX, const unsigned int nPageY ) const
244 {
245 std::stringstream ss;
246
247 ss << _sStoreDirectory << '/' << _sFilePrefix << std::setw(8) << std::setfill('0') << std::hex << calculatePageID(nPageX, nPageY) << _sFileSuffix << std::ends;
248 return ss.str();
249 }
250
251 unsigned long PagingStore::calculatePageID( const unsigned int nPageX, const unsigned int nPageY )
252 { return ((nPageX & 0xFFFF) << 16) | (nPageY & 0xFFFF); }
253
254 InstanceFile * PagingStore::loadInstanceFile( const unsigned int nPageX, const unsigned int nPageY ) const
255 {
256 try
257 {
258 return InstanceFile::load(makeFilename(nPageX, nPageY));
259 } catch (InstanceFile::Ex &) {}
260
261 return NULL;
262 }
263
264 void PagingStore::logBorders( const GeoHeightMap::View & base, const unsigned int nPageX, const unsigned int nPageY )
265 {
266 enum Neighbor
267 {
268 N = 0,
269 W = 1,
270 E = 2,
271 S = 3
272 };
273 const GeoHeightMap::View * pSlices[4];
274
275 pSlices[N] = base.createView(0, 0, base.width - 1, 0);
276 pSlices[E] = base.createView(base.width - 1, 0, base.width - 1, base.height - 1);
277 pSlices[S] = base.createView(0, base.height - 1, base.width - 1, base.height - 1);
278 pSlices[W] = base.createView(0, 0, 0, base.height - 1);
279
280 std::vector< std::vector< GeoHeightMap::Precision > > vecSlices[4];
281
282 *pSlices[N] >> vecSlices[N];
283 *pSlices[E] >> vecSlices[E];
284 *pSlices[S] >> vecSlices[S];
285 *pSlices[W] >> vecSlices[W];
286
287 LOGD << "\tPrinting slices for page (" << nPageX << ',' << nPageY << ")\n"
288 << "\t\tN: " << pSlices[N]->bbox() << " : " << vecSlices[N] << '\n'
289 << "\t\tE: " << pSlices[E]->bbox() << " : " << vecSlices[E] << '\n'
290 << "\t\tS: " << pSlices[S]->bbox() << " : " << vecSlices[S] << '\n'
291 << "\t\tW: " << pSlices[W]->bbox() << " : " << vecSlices[W];
292
293 base.releaseView(pSlices[N]);
294 base.releaseView(pSlices[E]);
295 base.releaseView(pSlices[S]);
296 base.releaseView(pSlices[W]);
297 }
298
299 bool InstanceFile::InfoHeader::validate() const
300 {
301 return strncmp(IDENT, "GWIF", sizeof(IDENT)) == 0 &&
302 endian == 1 &&
303 version == 1 &&
304 dim > 0 && depth > 0;
305 }
306
307 InstanceFile::InfoHeader::InfoHeader()
308 : endian(1), version(1), stratumcount(0), dim(0), depth(0)
309 {
310 memcpy(IDENT, "GWIF", sizeof(IDENT));
311 }
312
313 void InstanceFile::write( const std::string & sFileName, const InstanceFile * pInstFile )
314 {
315 std::fstream * pOut = open (sFileName, std::ios::out);
316
317 if (!*pOut)
318 throw Ex("Failed to create file");
319
320 *pInstFile >> *pOut;
321 delete pOut;
322 }
323
324 InstanceFile * InstanceFile::load( const std::string & sFileName )
325 {
326 mars::ptr< std::fstream > pIn = open (sFileName, std::ios::in);
327 InstanceFile * pInst = NULL;
328
329 if (!*pIn)
330 {
331 LOG(mars::Log::Debug)
332 << "Failure loading InstanceFile: " << sFileName;
333 return NULL;
334 }
335
336 pInst = new InstanceFile();
337 *pInst << *pIn;
338 return pInst;
339 }
340
341 std::fstream * InstanceFile::open( const std::string & sFileName, const std::ios::openmode & nMode )
342 {
343 const std::ios::openmode nEffectiveMode = nMode | std::ios::binary | ((nMode & std::ios::out) != 0 ? std::ios::trunc | std::ios::ate : static_cast<std::ios::openmode>(0));
344 return new std::fstream(sFileName, nEffectiveMode);
345 }
346
347 std::ostream & InstanceFile::operator >> ( std::ostream & outs ) const
348 {
349 assert(_pStratum != NULL && _nDim > 0 && _nDepth > 0);
350
351 InfoHeader header;
352
353 header.stratumcount = _pStratum->size();
354 header.dim = _nDim;
355 header.depth = _nDepth;
356 outs.write(reinterpret_cast< const char * > (&header), sizeof(header));
357 return *_pStratum >> outs;
358 }
359
360 std::istream & InstanceFile::operator << ( std::istream & ins )
361 {
362 InfoHeader header;
363
364 ins.read(reinterpret_cast< char * > (&header), sizeof(header));
365 if (!header.validate())
366 throw Ex("Failed to validate file");
367
368 delete _pStratum;
369 _nDim = header.dim;
370 _nDepth = header.depth;
371 _pStratum = new Stratum(header.stratumcount, header.dim, header.dim, header.depth, 0);
372 return *_pStratum << ins;
373 }
374
375 InstanceFile::InstanceFile() : _pStratum(NULL), _nDim(0), _nDepth(0) {}
376 InstanceFile::InstanceFile( const unsigned short nDim, const unsigned short nDepth, const unsigned short nLayerCount )
377 : _pStratum(new Stratum(nLayerCount, nDim, nDim, nDepth, 0)), _nDim(nDim), _nDepth(nDepth)
378 {
379 assert(((nDim - 2) & (nDim - 1)) == 0); // Must be a power of 2 + 1 (normal non-wrapped MPDG-compatible field)
380 }
381
382 InstanceFile::~InstanceFile()
383 {
384 delete _pStratum;
385 }
386
387 DEFN_STATIC_GW_MUTEX(PagingStore::PageMutexProvider::NeighborhoodMutex, ATOMIC);
388
389 PagingStore::PageMutexProvider::NeighborhoodMutex::NeighborhoodMutex( boost::shared_mutex * const * ppShMutexes )
390 : _plckCenter(NULL)
391 {
392 for (unsigned int c = 0; c < TotalSpots; ++c)
393 {
394 _pmtxNeighbors[c] = ppShMutexes[c];
395 _plckNeighbors[c] = NULL;
396 }
397 _plckPreamble = new preamble_lock(*ppShMutexes[C]);
398 }
399
400 PagingStore::PageMutexProvider::NeighborhoodMutex::NeighborhoodMutex( NeighborhoodMutex && movable )
401 : _plckPreamble(movable._plckPreamble), _plckCenter(movable._plckCenter)
402 {
403 if (&movable != this)
404 {
405 for (unsigned int c = 0; c < TotalSpots; ++c)
406 {
407 _plckNeighbors[c] = movable._plckNeighbors[c];
408 _pmtxNeighbors[c] = movable._pmtxNeighbors[c];
409
410 movable._pmtxNeighbors[c] = NULL;
411 movable._plckNeighbors[c] = NULL;
412 }
413 movable._plckPreamble = NULL;
414 movable._plckCenter = NULL;
415 }
416 }
417
418 PagingStore::PageMutexProvider::NeighborhoodMutex::~NeighborhoodMutex()
419 {
420 { GW_SCOPED_LOCK(ATOMIC);
421 for (unsigned int c = 0; c < TotalSpots; ++c)
422 delete _plckNeighbors[c];
423
424 delete _plckCenter;
425 delete _plckPreamble;
426 }
427 }
428
429 void PagingStore::PageMutexProvider::NeighborhoodMutex::genLock()
430 {
431 assert(_plckPreamble != NULL && *_plckPreamble);
432 assert(
433 _plckNeighbors[N] == NULL &&
434 _plckNeighbors[E] == NULL &&
435 _plckNeighbors[S] == NULL &&
436 _plckNeighbors[W] == NULL &&
437 _plckNeighbors[C] == NULL
438 );
439
440 Spot enLockedSpot;
441 bool bUnavailable = false;
442
443 do
444 {
445 { GW_SCOPED_LOCK(ATOMIC);
446 _plckPreamble->unlock(); // Release read lock on center tile
447 {
448 // Try-establish write-lock on center tile
449 DetachableScopedGenerationTryLock lckCenter(*_pmtxNeighbors[C]);
450
451 bUnavailable = !lckCenter;
452 if (lckCenter)
453 {
454 DetachableScopedQueryTryLock
455 lckN (*_pmtxNeighbors[N]),
456 lckS (*_pmtxNeighbors[S]),
457 lckW (*_pmtxNeighbors[W]),
458 lckE (*_pmtxNeighbors[E]);
459
460 bUnavailable = !(lckN && lckS && lckW && lckE);
461
462 if (bUnavailable)
463 {
464 if (!lckN) enLockedSpot = N;
465 if (!lckS) enLockedSpot = S;
466 if (!lckW) enLockedSpot = W;
467 if (!lckE) enLockedSpot = E;
468 } else
469 {
470 _plckNeighbors[N] = lckN.detach();
471 _plckNeighbors[S] = lckS.detach();
472 _plckNeighbors[W] = lckW.detach();
473 _plckNeighbors[E] = lckE.detach();
474 _plckCenter = lckCenter.detach();
475 }
476 } else
477 enLockedSpot = C;
478
479 if (bUnavailable)
480 _plckPreamble->lock(); // Not supposed to block, we unlocked a previously-held shared-lock inside this same critical section
481 }
482 }
483
484 // Occurs outside of main atomic locking operation, waits for something to finish before attempting atomic locking transaction again
485 if (bUnavailable)
486 {
487 if (enLockedSpot == C)
488 {
489 upgraded_lock cond(*_plckPreamble);
490 } else
491 {
492 qry_lock cond(*_pmtxNeighbors[enLockedSpot]);
493 }
494 }
495
496 } while (bUnavailable);
497 }
498
499 GeoWorldPage::GeoWorldPage( const GeoHeightMap::View & hm, const unsigned int nPageX, const unsigned int nPageY, const unsigned short nDepth, const size_t nLayers ) // TODO: Check bounds for the OctTree, is this good enough?
500 : _heightmap(hm), _stratum(nLayers, hm.width, hm.height, nDepth, 0), _minerals(std::max(hm.width, hm.height)), _nIFaceRefCount(0), _bShouldAbort(false),
501 x(nPageX), y(nPageY)
502 {
503 assert(((hm.width - 2) & (hm.width - 1)) == 0 && ((hm.height - 2) & (hm.height - 1)) == 0); // Must be a power of 2 + 1 (normal non-wrapped MPDG-compatible field)
504 }
505
506 GeoWorldPage::~GeoWorldPage()
507 {
508 { GW_SCOPED_LOCK(atomic);
509 assert(_nIFaceRefCount == 0);
510 if (_nIFaceRefCount > 0)
511 throw IFaceEx("Still open interface on GeoWorldPage instance");
512 }
513 }
514
515 GeoWorldPage::Interface::Interface(GeoWorldPage * pParent)
516 : _pParent(pParent), heightmap(pParent->_heightmap), stratum(pParent->_stratum), minerals(pParent->_minerals)
517 {
518 _pParent->checkOutIFace();
519 }
520
521 GeoWorldPage::Interface::Interface(GeoWorldPage::Interface && move)
522 : _pParent(move._pParent), heightmap(move.heightmap), stratum(move.stratum), minerals(move.minerals) {
523 move._pParent = NULL;
524 }
525
526 GeoWorldPage::Interface::~Interface()
527 {
528 // TODO: Stratum::~Stratum() needs to be atomic
529 if (_pParent != NULL)
530 _pParent->checkInIFace();
531 }
532
533 Stratum::View * GeoWorldPage::Interface::createStratumView( const WorldUnit nLeft, const WorldUnit nTop, const int nShallow, const WorldUnit nRight, const WorldUnit nBottom, const WorldUnit nDeep ) const
534 {
535 { GW_SCOPED_LOCK(atomic);
536 return _pParent->_stratum.createView(nLeft, nTop, nShallow, nRight, nBottom, nDeep);
537 }
538 }
539
540 Stratum::View * GeoWorldPage::Interface::createStratumView( const WorldUnit nLeft, const WorldUnit nTop, const WorldUnit nRight, const WorldUnit nBottom ) const
541 {
542 { GW_SCOPED_LOCK(atomic);
543 return _pParent->_stratum.createView(nLeft, nTop, nRight, nBottom);
544 }
545 }
546
547 void GeoWorldPage::Interface::releaseStratumView( const Stratum::View * pView ) const
548 {
549 { GW_SCOPED_LOCK(atomic); // TODO: Verify, is it correct to delete inside critical section?
550 _pParent->_stratum.releaseView(pView);
551 }
552 }
553
554 GeoHeightMap::View * GeoWorldPage::Interface::createHeightMapView( const unsigned short nLeft, const unsigned short nTop, const unsigned short nRight, const unsigned short nBottom ) const
555 {
556 { GW_SCOPED_LOCK(atomic);
557 return heightmap.createView(nLeft, nTop, nRight, nBottom);
558 }
559 }
560
561 void GeoWorldPage::Interface::releaseHeightMapView( const GeoHeightMap::View * pView ) const
562 {
563 { GW_SCOPED_LOCK(atomic);
564 heightmap.releaseView(pView);
565 }
566 }
567
568 void GeoWorldPage::abort(const bool bWait /*= false*/) const
569 {
570 { GW_SCOPED_LOCK(atomic);
571 _bShouldAbort = true;
572 }
573
574 if (bWait)
575 GW_WAIT(work);
576 }
577
578 bool GeoWorldPage::isAborted() const
579 {
580 { GW_SCOPED_LOCK(atomic);
581 return _bShouldAbort;
582 }
583 }
584
585 void GeoWorldPage::checkOutIFace() const
586 {
587 _work.lock();
588 { GW_SCOPED_LOCK(atomic);
589 ++_nIFaceRefCount;
590 }
591 }
592
593 void GeoWorldPage::checkInIFace() const
594 {
595 { GW_SCOPED_LOCK(atomic);
596 --_nIFaceRefCount;
597 }
598 _work.unlock();
599 }
600}
Note: See TracBrowser for help on using the repository browser.