source: Revenant/geoworld/src/geoworld.cpp

port/mars-tycoon
Last change on this file 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: 33.8 KB
Line 
1#include "geoworld.h"
2
3#include <mars_calc.h>
4#include <mars_util.h>
5#include <mars_lookup.h>
6#include <math.h>
7#include <stdio.h>
8
9#include "geomorph.h"
10#include "lodtools.h"
11
12namespace geoworld
13{
14 void LockedGWSection::blitFrom( const FileSource::MainDEM::Block & block, const unsigned short nTileX, const unsigned short nTileY )
15 {
16 block.copyTo(_hm, nTileX, nTileY);
17 }
18
19 void LockedGWSection::blitTo( FileSource::MainDEM::Block & block, const unsigned short nTileX, const unsigned short nTileY ) const
20 { block.copyFrom (_hm, nTileX, nTileY); }
21
22 void LockedGWSection::operator >> ( PNGDEM & pngdem ) const
23 { pngdem << _hm; }
24
25 void LockedGWSection::operator>>( LockedGWSection::View && view ) const
26 {
27 if (view.getHeightMap() ->width == _hm.width && view.getHeightMap() ->height == _hm.height)
28 {
29 assert(view.getHeightMap() ->width == view.getStratum() ->width && view.getHeightMap() ->height == view.getStratum() ->height);
30 _hm >> *view.getHeightMap();
31 _stratum >> *view.getStratum();
32 } else
33 {
34 assert(abs(bbox.left) < MAX_LOCK_DIM && abs(bbox.top) < MAX_LOCK_DIM);
35
36 const signed int
37 x = static_cast< signed int > (bbox.left),
38 y = static_cast< signed int > (bbox.top);
39
40 _hm >> GeoHeightMap::View::Offset(view.getHeightMap(), x, y);
41 _stratum >> Stratum::View::Offset(view.getStratum(), x, y);
42 }
43 }
44
45 void LockedGWSection::operator << ( const PNGDEM & pngdem )
46 {
47 assert(pngdem.getWidth() <= _hm.width && pngdem.getHeight() <= _hm.height);
48 GeoHeightMap::Precision * pnData = new GeoHeightMap::Precision[pngdem.getWidth()];
49 for (unsigned int i = 0; i < pngdem.getHeight(); ++i)
50 {
51 pngdem.retrieveLine(pnData, i);
52 _hm.setn(0, i, pnData, pngdem.getWidth());
53 }
54 }
55
56 void LockedGWSection::operator << ( const LockedGWSection::View & view )
57 {
58 if (view.getHeightMap()->width == _hm.width && view.getHeightMap()->height == _hm.height)
59 {
60 assert(view.getHeightMap() ->width == view.getStratum() ->width && view.getHeightMap() ->height == view.getStratum() ->height);
61 _hm << *view.getHeightMap();
62 _stratum << *view.getStratum();
63 } else
64 {
65 assert(abs(bbox.left) < MAX_LOCK_DIM && abs(bbox.top) < MAX_LOCK_DIM);
66
67 const signed int
68 x = static_cast< signed int > (bbox.left),
69 y = static_cast< signed int > (bbox.top);
70
71 _hm << GeoHeightMap::View::Offset(view.getHeightMap(), x, y);
72 _stratum << Stratum::View::Offset(view.getStratum(), x, y);
73 }
74 }
75
76 mars::BBox< long > LockedGWSection::computeLockedSection( const mars::BBox< long > & bbox, const unsigned short nTileDim, const bool bPad /*= true*/ )
77 {
78 assert(((nTileDim - 1) & nTileDim) == 0); // Must be a power of 2
79
80 using namespace mars;
81 const unsigned short nPadHalfTile = (bPad ? nTileDim / 2 : 0);
82
83 // DEPS: LGWSBBA
84 return mars::BBox< long > (
85 ALIGN(bbox.left - nPadHalfTile, static_cast< long > (nTileDim)),
86 ALIGN(bbox.top - nPadHalfTile, static_cast< long > (nTileDim)),
87 ALIGN(bbox.right + nPadHalfTile + nTileDim, static_cast< long > (nTileDim)) - 1,
88 ALIGN(bbox.bottom + nPadHalfTile + nTileDim, static_cast< long > (nTileDim)) - 1
89 );
90 }
91
92 bool LockedGWSection::isValid( const mars::BBox< long > & bbox, const unsigned short nTileDim, const bool bPad /*= true */ )
93 {
94 assert(((nTileDim - 1) & nTileDim) == 0); // Must be a power of 2
95 if (bbox.empty())
96 return false;
97
98 const mars::BBox< long > bboxActual = computeLockedSection(bbox, nTileDim, bPad);
99 return bboxActual.getWidth() <= static_cast< long > (MAX_LOCK_DIM) && bboxActual.getHeight() <= static_cast< long > (MAX_LOCK_DIM);
100 }
101
102 LockedGWSection::LockedGWSection( const mars::BBox< long > & bbox, const long nDepth, const unsigned short nDEMLOD, const size_t nLayers, const unsigned short nStratumLOD )
103 : _hm(static_cast< unsigned short > (bbox.getWidth()), static_cast< unsigned short > (bbox.getHeight()), mars::Normal),
104 _stratum(
105 nLayers,
106 static_cast< WorldUnit > (bbox.getWidth()) << nDEMLOD,
107 static_cast< WorldUnit > (bbox.getHeight()) << nDEMLOD,
108 static_cast< WorldUnit > (nDepth) << nDEMLOD,
109 nStratumLOD,
110 mars::Normal
111 ),
112 bbox(bbox),
113 _ssop(SSync_Perfect), _nDEMLOD(nDEMLOD)
114 {
115 assert(bbox.getWidth() <= static_cast< long > (MAX_LOCK_DIM) && bbox.getHeight() <= static_cast< long > (MAX_LOCK_DIM));
116 }
117
118 LockedGWSection::LockedGWSection( const GeoHeightMap & hm, const unsigned short nDEMLOD, const Stratum & stratum )
119 : _hm(hm), _stratum(stratum.layers, hm.width << stratum.lod, hm.height << stratum.lod, stratum.absdepth, stratum.lod, stratum.getBase().gridtype), bbox(hm.left, hm.top, hm.right, hm.bottom),
120 _ssop(SSync_Perfect), _nDEMLOD(nDEMLOD)
121 {
122 _stratum << Stratum::View::Offset(&stratum, bbox.left, bbox.top);
123 }
124
125 LockedGWSection::View * LockedGWSection::createView( const long nLeft, const long nTop, const long nRight, const long nBottom )
126 {
127 assert (bbox.inside(nLeft, nTop) && bbox.inside(nRight, nBottom));
128
129 const unsigned short
130 nLeft2 = static_cast< unsigned short > (nLeft - bbox.left),
131 nTop2 = static_cast< unsigned short > (nTop - bbox.top),
132 nRight2 = static_cast< unsigned short > (nRight - bbox.left),
133 nBottom2 = static_cast< unsigned short > (nBottom - bbox.top);
134
135 View
136 * pView = new View(
137 _hm.createView (nLeft2, nTop2, nRight2, nBottom2),
138 _stratum.createView(nLeft2, nTop2, nRight2, nBottom2)
139 );
140
141 LOG(mars::Log::Debug) << bbox << ", " << pView->getHeightMap();
142 return pView;
143 }
144
145 const LockedGWSection::View * LockedGWSection::createView( const long nLeft, const long nTop, const long nRight, const long nBottom ) const
146 {
147 assert (bbox.inside(nLeft, nTop) && bbox.inside(nRight, nBottom));
148
149 const unsigned short
150 nLeft2 = static_cast< unsigned short > (nLeft - bbox.left),
151 nTop2 = static_cast< unsigned short > (nTop - bbox.top),
152 nRight2 = static_cast< unsigned short > (nRight - bbox.left),
153 nBottom2 = static_cast< unsigned short > (nBottom - bbox.top);
154
155 const View
156 * pView = new View(
157 _hm.createView (nLeft2, nTop2, nRight2, nBottom2),
158 _stratum.createView(nLeft2, nTop2, nRight2, nBottom2)
159 );
160
161 LOG(mars::Log::Debug) << bbox << ", " << pView->getHeightMap();
162 return pView;
163 }
164
165 PagedGeoWorld::PagedGeoWorld(DepositSynthesizer * pDepSynth, FileSource * pFile, const unsigned short nPasses)
166 : _pFile(pFile), _pAgentMaps(NULL), _passes(nPasses), _nNumProcs(DEFAULT_NUM_PROCS), _plsbboxLockedMutableRegions(NULL),
167 _pDepSynth(pDepSynth)
168 {
169 const unsigned long
170 nWorldWidth = pFile->getVirtualWidth(),
171 nWorldHeight = pFile->getVirtualHeight();
172
173 assert(_plsbboxLockedMutableRegions == NULL && _pAgentMaps == NULL);
174 assert(_pDepSynth->getStratum().getBase().gridtype == mars::Wrap);
175
176 _pFile = pFile;
177 for (PassList::iterator i = _passes.begin(); i != _passes.end(); ++i)
178 {
179 delete *i;
180 *i = new Pass(nWorldWidth, nWorldHeight);
181 }
182 _plsbboxLockedMutableRegions = new RegionContainer(nWorldWidth, nWorldHeight);
183 _pAgentMaps = new AllAgentMaps(nWorldWidth, nWorldHeight);
184 }
185
186 PagedGeoWorld::~PagedGeoWorld()
187 {
188 GW_SCOPED_LOCK(mutex);
189 {
190 delete _plsbboxLockedMutableRegions;
191 delete _pAgentMaps;
192
193 for (PassList::iterator i = _passes.begin(); i != _passes.end(); ++i)
194 delete *i;
195 }
196 }
197
198 template< PagedGeoWorld::Mode MODE, typename TYPE_LockedGWSection >
199 void PagedGeoWorld::performIOOperation( TYPE_LockedGWSection * pSection ) const
200 {
201 assert(_pFile != NULL);
202 FileSource::MainDEM::Block block (_pFile->tilemap.getVirtualTileDim());
203
204 const unsigned int
205 nTX0 = static_cast< unsigned int > (mars::WRAP(pSection->bbox.left, _pFile->tilemap.getVirtualWidth()) / _pFile->tilemap.getVirtualTileDim()),
206 nTY0 = static_cast< unsigned int > (mars::WRAP(pSection->bbox.top, _pFile->tilemap.getVirtualHeight()) / _pFile->tilemap.getVirtualTileDim()),
207 nTW = (pSection->getActualWidth() - 1) / _pFile->tilemap.getVirtualTileDim(), // - 1 accounts for non-even redundant tile-blocking
208 nTH = (pSection->getActualHeight() - 1) / _pFile->tilemap.getVirtualTileDim();
209
210 if (nTX0 >= 0 && nTX0 + nTW <= _pFile->tilemap.getTilesWide() &&
211 nTY0 >= 0 && nTY0 + nTH <= _pFile->tilemap.getTilesHigh())
212 {
213 seekTileOp<MODE>( nTX0, nTY0, std::ios::beg );
214
215 unsigned short j = 0;
216
217 while (j < nTH)
218 {
219 for (unsigned short i = 0; i < nTW; ++i)
220 blockOp<MODE>(pSection, block, i, j);
221
222 if (++j < nTH)
223 seekTileOp<MODE>(-static_cast< signed int > (nTW), 1);
224 }
225 } else
226 {
227 unsigned int
228 nTXI, nTYI;
229 bool bThumb;
230
231 seekTileOp<MODE>(nTX0, nTY0, std::ios::beg);
232 nTYI = 0;
233 while (nTY0 + nTYI < _pFile->tilemap.getTilesHigh() && nTYI < nTH)
234 {
235 nTXI = 0;
236 while (nTXI < nTW && nTX0 + nTXI < _pFile->tilemap.getTilesWide())
237 {
238 blockOp<MODE>(pSection, block, nTXI++, nTYI);
239 }
240
241 if (bThumb = (nTXI < nTW))
242 {
243 seekTileOp<MODE>(0, -1);
244 do
245 {
246 blockOp<MODE>(pSection, block, nTXI++, nTYI);
247 } while (nTXI < nTW);
248 }
249
250 ++nTYI;
251 if (nTY0 + nTYI < _pFile->tilemap.getTilesHigh() && nTYI < nTH)
252 seekTileOp<MODE>(-static_cast< signed int > (nTW), 1 + (bThumb ? 1 : 0));
253 else
254 break;
255 }
256 seekTileOp<MODE>(nTX0, 0, std::ios::beg);
257 while (nTYI < nTH)
258 {
259 nTXI = 0;
260 while (nTXI < nTW && nTX0 + nTXI < _pFile->tilemap.getTilesWide())
261 {
262 blockOp<MODE>(pSection, block, nTXI++, nTYI);
263 }
264 if (bThumb = (nTXI < nTW))
265 {
266 seekTileOp<MODE>(0, -1);
267 do
268 {
269 blockOp<MODE>(pSection, block, nTXI++, nTYI);
270 } while (nTXI < nTW);
271 }
272
273 if (++nTYI < nTH)
274 seekTileOp<MODE>(-static_cast< signed int > (nTW), 1 + (bThumb ? 1 : 0));
275 else
276 break;
277 }
278 }
279 }
280
281 void PagedGeoWorld::unlock( LockedGWSection * pSection )
282 {
283 using namespace std;
284 using namespace mars;
285
286 GW_SCOPED_LOCK(mutex);
287 {
288 assert(_pFile != NULL);
289 assert(_plsbboxLockedMutableRegions != NULL);
290
291 if (!_plsbboxLockedMutableRegions->removeRegion(pSection->bbox))
292 throw UnlockEx(pSection->bbox);
293
294 pSection->processSyncOp();
295 performIOOperation<Write>(pSection);
296
297 delete pSection;
298 }
299 }
300
301 void PagedGeoWorld::unlock( const LockedGWSection * pSection ) const
302 {
303 using namespace std;
304 using namespace mars;
305
306 GW_SCOPED_LOCK(mutex);
307 {
308 assert(_pFile != NULL);
309 assert(_plsbboxLockedMutableRegions != NULL);
310
311 // TODO: This doesn't quite work, will fail when a r/w section was requested while this region was locked and the regions overlap/intersect
312 if (_plsbboxLockedMutableRegions->intersects(pSection->bbox))
313 throw UnlockEx(pSection->bbox);
314
315 delete pSection;
316 }
317 }
318
319 geoworld::LockedGWSection * PagedGeoWorld::doLock( const mars::BBox< long > & bbox, const bool bPad /*= true*/, const bool bReadOnly /*= false*/ ) const
320 {
321 using namespace std;
322 using namespace mars;
323
324 assert(static_cast< unsigned long > (bbox.getWidth()) <= getWorldWidth() && static_cast< unsigned long > (bbox.getHeight()) < getWorldHeight());
325
326 GW_SCOPED_LOCK(mutex);
327 {
328 assert(_pFile != NULL);
329 assert(_plsbboxLockedMutableRegions != NULL);
330
331 const unsigned short nTileDim = _pFile->tilemap.getVirtualTileDim() >> getLOD();
332 const mars::BBox< long >
333 bboxActual = LockedGWSection::computeLockedSection(bbox, nTileDim, bPad);
334
335 if (_plsbboxLockedMutableRegions->intersects(bboxActual))
336 return NULL;
337
338 if (!bReadOnly)
339 _plsbboxLockedMutableRegions->addRegion(bboxActual);
340
341 LockedGWSection * pSection = new LockedGWSection(bboxActual, _pFile->getWorldDepth(), getLOD(), _pFile->geohost.count, _pFile->geohost.getLOD());
342 performIOOperation<Read>(pSection);
343 *pSection << Stratum::Offset(&_pDepSynth->getStratum(), bboxActual.left, bboxActual.top);
344 return pSection;
345 }
346 }
347
348 void PagedGeoWorld::processWorkQueue( PagedGeoWorld::WorkQueue & q, PagedGeoWorld::IWorkQueueListener * pListener /*= NULL*/ )
349 {
350 bool bOuterRunning = !q.inbox.empty();
351 bool bInnerRunning = false;
352
353 if (!bOuterRunning)
354 return;
355
356 #pragma omp parallel default(none) firstprivate(bOuterRunning, bInnerRunning, pListener) shared(q)
357 do
358 {
359 #pragma omp critical(work)
360 {
361 #pragma omp master
362 {
363 WorkQueue::ItemQueue inbox, ready, collisions;
364
365 #pragma omp critical(inbox)
366 { inbox = q.inbox; }
367
368 while (!inbox.empty() && ready.size() < _nNumProcs)
369 {
370 WorkItem item = inbox.front();
371 inbox.pop_front();
372
373 item.section = lock(item.picks->getBBox());
374
375 if (item.section != NULL)
376 ready.push_back(item);
377 else
378 collisions.push_back(item);
379 }
380
381 #pragma omp critical(ready)
382 {
383 q.ready.insert(q.ready.end(), ready.begin(), ready.end());
384 if (pListener != NULL && !ready.empty())
385 pListener->readyQueue(ready);
386 }
387
388 #pragma omp critical(inbox)
389 {
390 q.inbox.clear();
391 q.inbox.insert(q.inbox.end(), inbox.begin(), inbox.end());
392 q.inbox.insert(q.inbox.end(), collisions.begin(), collisions.end());
393
394 if (pListener != NULL && !collisions.empty())
395 pListener->collisions(collisions);
396 }
397 }
398 }
399
400 do
401 {
402 WorkItem item;
403
404 #pragma omp critical (ready)
405 {
406 bInnerRunning = !q.ready.empty();
407 if (bInnerRunning)
408 {
409 item = q.ready.front();
410 q.ready.pop_front();
411 }
412 }
413
414 if (bInnerRunning)
415 {
416 item.picks->consume(_pDepSynth, item.section, item.minerals);
417
418 #pragma omp critical (outbox)
419 { q.outbox.push_back(item); }
420 }
421 } while (bInnerRunning);
422
423 #pragma omp master
424 {
425 WorkQueue::ItemQueue outbox;
426
427 #pragma omp critical(outbox)
428 {
429 outbox = q.outbox;
430 q.outbox.clear();
431 }
432
433 if (pListener != NULL && !outbox.empty())
434 pListener->unlockQueue(outbox);
435
436 flushOutbox(outbox);
437 }
438
439 #pragma omp critical (inbox)
440 {
441 bOuterRunning = !q.inbox.empty();
442 }
443 } while (bOuterRunning);
444
445 // Outside of parallel region, this ensures everything is released
446 if (pListener != NULL && !q.outbox.empty())
447 pListener->unlockQueue(q.outbox);
448 flushOutbox(q.outbox);
449
450 assert(_plsbboxLockedMutableRegions->empty());
451 }
452
453 void PagedGeoWorld::flushOutbox( WorkQueue::ItemQueue &outbox )
454 {
455 while(!outbox.empty())
456 {
457 unlock(outbox.front().section);
458 flushMinerals(outbox.front().minerals);
459 outbox.pop_front();
460 }
461 }
462
463 void PagedGeoWorld::runMorphs( const unsigned short nPass, MorphList & rejects )
464 {
465 size_t c = 0;
466 Pass & pass = *_passes[nPass];
467
468 const long
469 nWW = _pFile->tilemap.getVirtualWidth(),
470 nWH = _pFile->tilemap.getVirtualHeight();
471 const unsigned short
472 nLW = static_cast< unsigned short > (std::min (static_cast< long > (LockedGWSection::MAX_LOCK_DIM), nWW / 4)),
473 nLH = static_cast< unsigned short > (std::min (static_cast< long > (LockedGWSection::MAX_LOCK_DIM), nWH / 4));
474
475 MasterSet master (&pass.quadtree, pass.list.begin(), pass.list.end());
476 const size_t nTotal = master.size();
477
478 class QueueListener : public IWorkQueueListener
479 {
480 private:
481 PagedGeoWorld * _pParent;
482 size_t _nTotal;
483
484 public:
485 size_t counter;
486
487 QueueListener (PagedGeoWorld * pParent, const size_t nTotal)
488 : _pParent(pParent), _nTotal(nTotal), counter(0) {}
489
490 void readyQueue (const WorkQueue::ItemQueue & readyq)
491 {
492 MorphList mrphs;
493 for (WorkQueue::ItemQueue::const_iterator i = readyq.begin(); i != readyq.end(); ++i)
494 for (Picks::iterator j = i->picks->begin(); j != i->picks->end(); ++j)
495 mrphs.push_back(*j);
496
497 _pParent->fire(&IGeoWorldListener::runningMorphs, mrphs.begin(), mrphs.end(), counter, mrphs.size(), _nTotal);
498 counter += mrphs.size();
499 }
500 } qListener(this, nTotal);
501
502 long i, j;
503 WorkQueue q;
504
505 for (j = 0; j < nWW; j += nLH)
506 {
507 for (i = 0; i < nWH; i += nLW)
508 {
509 mars::ptr< Picks > pPicks;
510
511 pPicks =
512 master.collect(
513 QTMorphs::Region (
514 QTMorphs::VECTOR(i, j),
515 QTMorphs::VECTOR(i + nLW - 1, j + nLH - 1)
516 )
517 );
518
519 if (isPickValid(*pPicks))
520 q.inbox.push_back(WorkItem(pPicks));
521 }
522 }
523
524 processWorkQueue(q, &qListener);
525
526 if (!master.empty())
527 {
528 for (MorphSet::const_iterator i = master.begin(); i != master.end(); )
529 {
530 mars::ptr< GeoMorph > pp = *i;
531 BoundedGeoMorph * pBGM = mars::ptr_dynamic_cast< BoundedGeoMorph > (pp);
532
533 if (pBGM != NULL)
534 {
535 mars::BBox< long > bbox = pBGM->getBBox();
536 QTMorphs::VECTOR ptCenter = (bbox.getMaximum() - bbox.getMinimum()) / 2 + bbox.getMinimum();
537 mars::ptr< Picks > pPicks = master.collect(
538 QTMorphs::Region(
539 QTMorphs::VECTOR(ptCenter.x - nLW / 2, ptCenter.y - nLH / 2),
540 QTMorphs::VECTOR(ptCenter.x + nLW / 2, ptCenter.y + nLH / 2)
541 )
542 );
543
544 if (isPickValid(*pPicks))
545 q.inbox.push_back(WorkItem(pPicks));
546
547 if (!pPicks->empty())
548 i = master.begin(); // Iterator is potentially invalid after calling "collect" and getting some picks, restart the list iteration
549 else
550 ++i;
551 } else
552 ++i;
553 }
554
555 processWorkQueue(q, &qListener);
556 }
557
558 if (!master.empty())
559 {
560 const unsigned short
561 nMax2LockWidth =
562 static_cast< unsigned short > (
563 std::min(
564 static_cast< unsigned long > (getWorldWidth() / 4),
565 static_cast< unsigned long > (1 << mars::LOG2(getMaxGeoMorphWidth()))
566 )
567 ),
568 nMax2LockHeight =
569 static_cast< unsigned short > (
570 std::min(
571 static_cast< unsigned long > (getWorldHeight() / 4),
572 static_cast< unsigned long > (1 << mars::LOG2(getMaxGeoMorphHeight()))
573 )
574 );
575
576 const unsigned short
577 n2iX = static_cast< unsigned short > (getWorldWidth() / nMax2LockWidth),
578 n2iY = static_cast< unsigned short > (getWorldHeight() / nMax2LockHeight),
579 n2Count = n2iX * n2iY;
580
581 for (MorphSet::const_iterator i = master.begin(); i != master.end(); ++i)
582 {
583 mars::ptr< GeoMorph > pp = *i;
584 BoundedGeoMorph * pBGM = mars::ptr_dynamic_cast< BoundedGeoMorph > (pp);
585
586 if (pBGM != NULL) // TODO: Support all GM types
587 {
588 const mars::BBox< long > bbox = pBGM->getBBox();
589
590 if (isValidSectionBBox(bbox))
591 q.inbox.push_back(WorkItem(pp));
592 else
593 {
594 fire(&IGeoWorldListener::rejectedMorph, *i);
595 rejects.push_back(*i);
596 }
597 } else
598 {
599 HeightMapGeoMorph * pGM = mars::ptr_dynamic_cast< HeightMapGeoMorph > (pp);
600
601 if (pGM != NULL)
602 {
603 long x, y;
604
605 for (unsigned short j = 0; j < n2iY; ++j)
606 {
607 y = static_cast< long > ((j * 2) % n2iY + (j * 2 / n2iY)) * nMax2LockHeight;
608 for (unsigned short i = 0; i < n2iX; ++i)
609 {
610 x = static_cast< long > ((i * 2) % n2iX + (i * 2 / n2iX)) * nMax2LockWidth;
611 q.inbox.push_back(
612 WorkItem(
613 pp,
614 mars::BBox< long > (
615 x,
616 y,
617 x + nMax2LockWidth - 1,
618 y + nMax2LockHeight - 1
619 )
620 )
621 );
622 }
623 }
624
625 this->fire(&IGeoWorldListener::runningMorph, pp, qListener.counter++, nTotal);
626 processWorkQueue(q);
627 }
628 }
629 }
630 processWorkQueue(q, &qListener);
631 }
632 }
633
634 bool PagedGeoWorld::isValidSectionBBox (const mars::BBox< long > & bbox) const
635 {
636 if (bbox.empty())
637 return false;
638
639 if (bbox.getWidth() > getMaxGeoMorphWidth() || bbox.getHeight() > getMaxGeoMorphHeight())
640 return false;
641
642 return LockedGWSection::isValid(bbox, _pFile->getVirtualTileDim());
643 }
644 bool PagedGeoWorld::isPickValid (const Picks & p) const
645 {
646 return isValidSectionBBox(p.getBBox()) && !p.empty();
647 }
648
649 unsigned short PagedGeoWorld::getMaxGeoMorphWidth() const
650 {
651 return static_cast< unsigned short > (
652 std::min(
653 static_cast< unsigned long > (
654 LockedGWSection::getMaxViewportDim(_pFile->tilemap.getVirtualTileDim())
655 ),
656 static_cast< unsigned long > (
657 LockedGWSection::getActualViewportDim(
658 static_cast< unsigned short > (
659 std::min(
660 _pFile->tilemap.getVirtualWidth(),
661 static_cast< unsigned long > (std::numeric_limits< unsigned short >::max())
662 )
663 ),
664 _pFile->tilemap.getVirtualTileDim()
665 )
666 )
667 ) >> getLOD()
668 );
669 }
670
671 unsigned short PagedGeoWorld::getMaxGeoMorphHeight() const
672 {
673 return static_cast< unsigned short > (
674 std::min(
675 static_cast< unsigned long > (
676 LockedGWSection::getMaxViewportDim(_pFile->tilemap.getVirtualTileDim())
677 ),
678 static_cast< unsigned long > (
679 LockedGWSection::getActualViewportDim(
680 static_cast< unsigned short > (
681 std::min(
682 _pFile->tilemap.getVirtualHeight(),
683 static_cast< unsigned long > (std::numeric_limits< unsigned short >::max())
684 )
685 ),
686 _pFile->tilemap.getVirtualTileDim()
687 )
688 )
689 ) >> getLOD()
690 );
691 }
692
693 void PagedGeoWorld::addMorphs( MorphList & morphs, MorphList & rejects, const unsigned short nPass )
694 {
695 Pass & pass = *_passes[nPass];
696
697 for (MorphList::const_iterator i = morphs.begin(); i != morphs.end(); ++i)
698 {
699 if (!checkGeoMorph(*i))
700 {
701 rejects.push_back(*i);
702 i = morphs.erase(i);
703
704 if (i == morphs.end())
705 break;
706 }
707 else
708 pass.quadtree.addMorph(*i);
709 }
710 pass.list.insert(pass.list.end(), morphs.begin(), morphs.end());
711 }
712
713 bool PagedGeoWorld::addMorph( mars::ptr <GeoMorph> & gm, const unsigned short nPass )
714 {
715 if (checkGeoMorph(gm))
716 {
717 Pass & pass = *_passes[nPass];
718 pass.list.push_back(gm);
719 pass.quadtree.addMorph(gm);
720 return true;
721 }
722
723 return false;
724 }
725
726 void PagedGeoWorld::readBlock( LockedGWSection * pSection, FileSource::MainDEM::Block & block, const unsigned short i, const unsigned short j ) const
727 {
728 block << _pFile->tilemap;
729 pSection->blitFrom(block, i, j);
730 }
731
732 void PagedGeoWorld::writeBlock( const LockedGWSection * pSection, FileSource::MainDEM::Block & block, const unsigned short i, const unsigned short j ) const
733 {
734 pSection->blitTo(block, i, j);
735 block >> _pFile->tilemap;
736 }
737
738 void PagedGeoWorld::flushMinerals( MineralsContainer & ctrMins )
739 {
740 GW_SCOPED_LOCK(mutex);
741 {
742 assert(_pFile != NULL);
743 ctrMins.flushTo(_pFile->minerals);
744 }
745 }
746
747 bool PagedGeoWorld::checkGeoMorph( const mars::ptr<GeoMorph> &gm )
748 {
749 const BoundedGeoMorph * pBGM = dynamic_cast< const BoundedGeoMorph * > (gm.pointer());
750
751 if (pBGM != NULL)
752 {
753 if (!isValidSectionBBox(pBGM->getBBox()))
754 return false;
755 }
756
757 return true;
758 }
759
760 void PagedGeoWorld::Picks::consume( const IMineralQuery * pQMin, LockedGWSection * pSection, MineralsContainer & ctrMins )
761 {
762 assert(!_bbox.empty());
763 // TODO: Got an access violation in this loop, invalid iterator? list pulled-out from beneath by something else?
764 for (iterator i = begin(); i != end(); ++i)
765 {
766 mars::ptr< GeoMorph > pp = *i;
767 HeightMapGeoMorph * pSyGM = mars::ptr_dynamic_cast< HeightMapGeoMorph > (pp);
768
769 if (pSyGM != NULL)
770 pSyGM->doMorph(*pSection);
771
772 MineralSpawnGeoMorph * pMSGM = mars::ptr_dynamic_cast< MineralSpawnGeoMorph > (pp);
773
774 if (pMSGM != NULL)
775 pMSGM->doSpawnMinerals(pQMin, ctrMins);
776 }
777 }
778
779 void PagedGeoWorld::Picks::computeBBox()
780 {
781 _bbox = mars::BBox< long >();
782
783 for (MorphSet::const_iterator k = begin(); k != end(); ++k)
784 {
785 const BoundedGeoMorph * pBGM = mars::ptr_dynamic_cast< BoundedGeoMorph > (*k);
786
787 if (pBGM != NULL)
788 {
789 if (_bbox.empty())
790 _bbox = pBGM->getBBox();
791 else
792 _bbox.add(pBGM->getBBox());
793 }
794 }
795 }
796
797 mars::ptr< PagedGeoWorld::Picks > PagedGeoWorld::MasterSet::collect( const QTMorphs::Region & rgBBox )
798 {
799 GW_SCOPED_LOCK(mutex);
800 {
801 mars::ptr< Picks > picks = new Picks();
802 QTMorphs::MorphIterator mit = _pQTMorphs->morphs(rgBBox);
803
804 while (mit)
805 {
806 mars::ptr< GeoMorph > pGM = static_cast< mars::ptr< GeoMorph > > (mit);
807
808 if (find(pGM) != end() && (rgBBox ^ mit.region()))
809 {
810 picks->insert(pGM);
811 erase(pGM);
812 }
813 ++mit;
814 }
815
816 picks->computeBBox();
817 return picks;
818 }
819 }
820
821 bool PagedGeoWorld::MasterSet::empty()
822 {
823 GW_SCOPED_LOCK(mutex);
824 {
825 return MorphSet::empty();
826 }
827 }
828
829 PagedGeoWorld::MasterSet::MasterSet( QTMorphs * pQTMorphs, MorphList::const_iterator iMorphs0, MorphList::const_iterator iMorphsN )
830 : MorphSet(iMorphs0, iMorphsN), _pQTMorphs(pQTMorphs) {}
831
832 void PagedGeoWorld::MasterSet::push( const mars::ptr< Picks > & pPicks )
833 {
834 GW_SCOPED_LOCK(mutex);
835 {
836 insert(pPicks->begin(), pPicks->end());
837 }
838 }
839
840 GeoWorld::GeoWorld( DepositSynthesizer * pDepSynth, const unsigned short nLODLowest, const unsigned short nLODMid, FileSource * pFile )
841 : _nLODLowest(nLODLowest), _nLODMid(nLODMid), _phmLowest(NULL), _nTileDim(pFile->getVirtualTileDim() >> (nLODLowest - nLODMid)),
842 _nLowWidth(pFile->getWorldWidth()), _nLowHeight(pFile->getWorldHeight()), _pDepSynth(pDepSynth), _pFile(pFile)
843 {
844 using namespace mars;
845
846 assert(nLODLowest >= MIN_LOWEST_LOD);
847
848 _phmLowest = new GeoHeightMap (
849 static_cast< unsigned short > (pFile->getWorldWidth() >> (nLODLowest - nLODMid)),
850 static_cast< unsigned short > (pFile->getWorldHeight() >> (nLODLowest - nLODMid)),
851 mars::Wrap
852 );
853 _phmLowest->clear();
854 assert(_pDepSynth->getStratum().getBase().gridtype == mars::Wrap);
855
856 _plsbboxLockedMutableRegions = new RegionContainer(_phmLowest->width, _phmLowest->height);
857 _pAllAgentMaps = new AllAgentMaps(_phmLowest->width, _phmLowest->height);
858 assert((_nLowWidth % _nTileDim) == 0 && (_nLowHeight % _nTileDim) == 0);
859
860 assert(
861 _nLowWidth <= FileSource::MAX_AXIS_TILES * FileSource::MAX_TILE_DIM &&
862 _nLowHeight <= FileSource::MAX_AXIS_TILES * FileSource::MAX_TILE_DIM
863 );
864 }
865
866 GeoWorld::~GeoWorld()
867 {
868 delete _phmLowest;
869 delete _plsbboxLockedMutableRegions;
870 delete _pAllAgentMaps;
871 }
872
873 void GeoWorld::unlock( LockedGWSection * pSection )
874 {
875 using namespace std;
876 using namespace mars;
877
878 GW_SCOPED_LOCK(mutex);
879 {
880 if (!_plsbboxLockedMutableRegions->removeRegion(pSection->bbox))
881 throw UnlockEx(pSection->bbox);
882
883 pSection->processSyncOp();
884 *pSection >> LockedGWSection::View(_phmLowest, &_pDepSynth->getStratum());
885 delete pSection;
886 }
887 }
888
889 void GeoWorld::unlock( const LockedGWSection * pSection ) const
890 {
891 GW_SCOPED_LOCK(mutex);
892 {
893 if (_plsbboxLockedMutableRegions->intersects(pSection->bbox))
894 throw UnlockEx(pSection->bbox);
895
896 delete pSection;
897 }
898 }
899
900 geoworld::LockedGWSection * GeoWorld::lock( const mars::BBox< long > & bbox, const bool bReadOnly ) const
901 {
902 using namespace std;
903 using namespace mars;
904
905 assert(static_cast< unsigned short > (bbox.getWidth()) <= _phmLowest->width && static_cast< unsigned short > (bbox.getHeight()) <= _phmLowest->height);
906
907 GW_SCOPED_LOCK(mutex);
908 {
909 const mars::BBox< long >
910 bboxActual = LockedGWSection::computeLockedSection(bbox, _nTileDim);
911
912 if (_plsbboxLockedMutableRegions->intersects(bboxActual))
913 return NULL;
914
915 if (!bReadOnly)
916 _plsbboxLockedMutableRegions->addRegion(bboxActual);
917
918 LockedGWSection * pSection = new LockedGWSection(bboxActual, _pFile->getWorldDepth(), getLOD(), _pFile->geohost.count, _pFile->geohost.getLOD());
919
920 *pSection << LockedGWSection::View(_phmLowest, &_pDepSynth->getStratum());
921 return pSection;
922 }
923 }
924
925 LockedGWSection * GeoWorld::lock(const bool bReadOnly) const
926 {
927 using namespace mars;
928
929 GW_SCOPED_LOCK(mutex);
930 {
931 const BBox< long >
932 bboxAll = BBox< long >(
933 0,
934 0,
935 (getWidth() >> getLOD()) - 1,
936 (getHeight() >> getLOD()) - 1
937 );
938
939 if (_plsbboxLockedMutableRegions->intersects(bboxAll))
940 return NULL;
941
942 if (!bReadOnly)
943 _plsbboxLockedMutableRegions->addRegion(bboxAll);
944
945 LockedGWSection * pSection = new LockedGWSection(bboxAll, _pFile->getWorldDepth(), getLOD(), _pFile->geohost.count, _pFile->geohost.getLOD());
946 *pSection << LockedGWSection::View(_phmLowest, &_pDepSynth->getStratum());
947
948 return pSection;
949 }
950 }
951
952 void GeoWorld::runMorphs( const MineralsDB & mindb, MorphList & rejects )
953 {
954 size_t c = 0;
955
956 for (MorphList::iterator i = _morphs.begin(); i != _morphs.end(); ++i, ++c)
957 {
958 BoundedGeoMorph * pBGM = dynamic_cast< BoundedGeoMorph * > (i->pointer()); // TODO: Lazily going through bounded geomorphs
959
960 if (pBGM != NULL)
961 {
962 mars::BBox< long > bbox = pBGM->getBBox();
963 const mars::BBox< long >
964 bboxActual = LockedGWSection::computeLockedSection(bbox, _nTileDim);
965
966 if (bboxActual.getWidth() <= _phmLowest->width &&
967 bboxActual.getHeight() <= _phmLowest->height &&
968 LockedGWSection::isValid(bbox, _nTileDim))
969 {
970 fire(&IGeoWorldListener::runningMorph, *i, c, _morphs.size());
971
972 LockedGWSection * pLockedSection = lock(
973 bbox.left,
974 bbox.top,
975 static_cast< unsigned short > (bbox.getWidth()),
976 static_cast< unsigned short > (bbox.getHeight())
977 );
978
979 runMorph(mindb, *i, pLockedSection);
980
981 unlock(pLockedSection);
982 } else
983 {
984 fire(&IGeoWorldListener::rejectedMorph, *i);
985 rejects.push_back(*i);
986 }
987 } else
988 {
989 fire(&IGeoWorldListener::runningMorph, *i, c, _morphs.size());
990
991 LockedGWSection * pLockedWorld = lock();
992 runMorph(mindb, *i, pLockedWorld);
993 unlock(pLockedWorld);
994 }
995 }
996
997 LOGN << "Macro world DEM range: " << _phmLowest->range();
998 }
999
1000 bool GeoWorld::addMorph( mars::ptr <GeoMorph> & gm )
1001 {
1002 if (checkGeoMorph(gm))
1003 {
1004 _morphs.push_back(gm);
1005 return true;
1006 }
1007
1008 return false;
1009 }
1010
1011 void GeoWorld::addMorphs( MorphList & morphs, MorphList & rejects )
1012 {
1013 for (MorphList::iterator i = morphs.begin(); i != morphs.end(); ++i)
1014 {
1015 if (!checkGeoMorph(*i))
1016 {
1017 rejects.push_back(*i);
1018 i = morphs.erase(i);
1019
1020 if (i == morphs.end())
1021 break;
1022 }
1023 }
1024
1025 _morphs.insert(_morphs.end(), morphs.begin(), morphs.end());
1026 }
1027
1028 bool GeoWorld::checkGeoMorph( const mars::ptr<GeoMorph> &gm )
1029 {
1030 const BoundedGeoMorph * pBGM = dynamic_cast< const BoundedGeoMorph * > (gm.pointer());
1031
1032 if (pBGM != NULL)
1033 {
1034 const mars::BBox< long > bbox = pBGM->getBBox();
1035
1036 if (bbox.getWidth() >= getMaxGeoMorphWidth() || bbox.getHeight() >= getMaxGeoMorphHeight())
1037 return false;
1038 }
1039
1040 return true;
1041 }
1042
1043 unsigned short GeoWorld::getMaxGeoMorphWidth() const
1044 {
1045 return static_cast< unsigned short > ((_nLowWidth >> getDeltaLOD()) - _nTileDim * 2 - 1); // - 1 accounts for non-event redundant tile-blocking
1046 }
1047
1048 unsigned short GeoWorld::getMaxGeoMorphHeight() const
1049 {
1050 return static_cast< unsigned short > ((_nLowHeight >> getDeltaLOD()) - _nTileDim * 2 - 1); // - 1 accounts for non-event redundant tile-blocking
1051 }
1052
1053 void GeoWorld::write(const float fCoarseness)
1054 {
1055 _pFile->applyDEM(_phmLowest, fCoarseness);
1056 *_pDepSynth >> _pFile->geohost;
1057 *_pDepSynth >> _pFile->minerals;
1058 }
1059
1060 void GeoWorld::runMorph( const MineralsDB & mindb, mars::ptr< GeoMorph > pGM, LockedGWSection * pLockedSection )
1061 {
1062 HeightMapGeoMorph * pCGM = mars::ptr_dynamic_cast< HeightMapGeoMorph > (pGM);
1063
1064 if (pCGM != NULL)
1065 {
1066 pCGM->doMorph(*pLockedSection);
1067 LOGN << "Macro world DEM range after morph " << pGM->getTypeName() << ": " << pLockedSection->getElevationRange();
1068 }
1069
1070 MineralSpawnGeoMorph * pMSGM = mars::ptr_dynamic_cast< MineralSpawnGeoMorph > (pGM);
1071
1072 if (pMSGM != NULL)
1073 {
1074 pMSGM->doSpawnMinerals(_pDepSynth, _ctrMins);
1075 }
1076 }
1077
1078 bool QTMorphs::addMorph( mars::ptr <GeoMorph> gm )
1079 {
1080 BoundedGeoMorph * pBGM = dynamic_cast< BoundedGeoMorph * > (gm.pointer());
1081
1082 if (pBGM != NULL)
1083 {
1084 const mars::BBox< long > bbox = pBGM->getBBox();
1085
1086 assert(!bbox.empty());
1087 add(gm, Region(bbox.getMinimum(), bbox.getMaximum()));
1088
1089 return true;
1090 }
1091
1092 return false;
1093 }
1094
1095 bool filesource::InfoHeader::validate() const
1096 {
1097 return strncmp(IDENT, "PGWM", sizeof(IDENT)) == 0 &&
1098 endian == 1 &&
1099 version == 1 &&
1100 tdim > 0 &&
1101 tx > 0 && ty > 0 && depth > 0;
1102 }
1103
1104 filesource::InfoHeader::InfoHeader()
1105 : endian(1), version(1), tdim(0), tx(0), ty(0), depth(0)
1106 {
1107 memcpy(IDENT, "PGWM", sizeof(IDENT));
1108 }
1109
1110 void MineralsContainer::flushTo( FileSource::MineralMap & minmap )
1111 {
1112 for (SphPackList::const_iterator i = _sphpacks.begin(); i != _sphpacks.end(); ++i)
1113 for (GeoSpherePack::const_iterator j = i->second->iterate(); j; ++j)
1114 minmap.add(i->first, *j);
1115
1116 _sphpacks.clear();
1117 }
1118
1119 bool RegionContainer::removeRegion( const mars::BBox< long > & bbox )
1120 {
1121 bool bFound = false;
1122 std::list< mars::BBox< long > > ::iterator i = begin();
1123
1124 while (i != end())
1125 if (bbox == *i)
1126 {
1127 i = erase(i);
1128 bFound = true;
1129 } else
1130 ++i;
1131
1132 return bFound;
1133 }
1134
1135 bool RegionContainer::intersects( const mars::BBox< long > & bbox ) const
1136 {
1137 using namespace mars;
1138
1139 for (list< mars::BBox< long > > ::const_iterator i = begin(); i != end(); ++i)
1140 if (bbox.intersects(*i))
1141 return true;
1142
1143 // Now perform more rigorous testing, checks bounding boxes that wrap around the world edges
1144 const BBox< long >
1145 bbox_2r = bbox + vector2D< long > (static_cast< long > (_nWWidth), 0),
1146 bbox_2b = bbox + vector2D< long > (0, static_cast< long > (_nWHeight)),
1147 bbox_2br = bbox + vector2D< long > (static_cast< long > (_nWWidth), static_cast< long > (_nWHeight));
1148
1149 for (list< mars::BBox< long > > ::const_iterator i = begin(); i != end(); ++i)
1150 if (bbox_2r.intersects(*i) || bbox_2b.intersects(*i) || bbox_2br.intersects(*i))
1151 return true;
1152
1153 return false;
1154 }
1155
1156 float AgentMap::sample( const GWCoords & coords ) const
1157 {
1158 using namespace mars;
1159
1160 double d = 1;
1161
1162 for (QuadTreeSpherePacks::Explicit< QuadTreeSpherePacks::Tag3D >::const_EntityPointIterator
1163 i = _qtField.contents(PointRegion< QuadTreeSpherePacks::Tag3D > (coords));
1164 i; ++i)
1165 {
1166 const double
1167 fDistSQ = static_cast< double > (MAGSQ(i.region().p3() - coords)),
1168 rSQ = static_cast < double > (mars::SQ(i.region().r));
1169
1170 // TODO: Check
1171 d *= fDistSQ / rSQ;
1172 }
1173
1174 return static_cast< float > (1.0 - d + base);
1175 }
1176
1177 mars::vector3Df AgentMap::gradient( const GWCoords & coords ) const
1178 {
1179 using namespace mars;
1180
1181 vector3Df v;
1182 GWCoords temp;
1183
1184 for (QuadTreeSpherePacks::Explicit< QuadTreeSpherePacks::Tag3D >::const_EntityPointIterator
1185 i = _qtField.contents(PointRegion< QuadTreeSpherePacks::Tag3D > (coords));
1186 i; ++i)
1187 {
1188 // TODO: Check
1189 return v += CAST< float > (
1190 i.region().p3() - coords
1191 ) / static_cast< float > (i.region().r);
1192 }
1193
1194 return v;
1195 }
1196
1197
1198 AgentMap & AllAgentMaps::operator[]( const FieldType enftType )
1199 {
1200 switch (enftType)
1201 {
1202 case FT_Density:
1203 return density;
1204 }
1205
1206 throw PGWIllegal ("Invalid field type requested for agent map");
1207 }
1208
1209 const AgentMap & AllAgentMaps::operator[]( const FieldType enftType ) const
1210 {
1211 switch (enftType)
1212 {
1213 case FT_Density:
1214 return density;
1215 }
1216
1217 throw PGWIllegal ("Invalid field type requested for agent map");
1218 }
1219
1220 AllAgentMaps::AllAgentMaps( const unsigned long nWidth, const unsigned long nHeight )
1221 : density(FT_Density, nWidth, nHeight, 1.0f)
1222 {}
1223
1224}
Note: See TracBrowser for help on using the repository browser.