1 | #pragma once
|
---|
2 |
|
---|
3 | #include <boost/thread.hpp>
|
---|
4 |
|
---|
5 | #include <iterator>
|
---|
6 | #include <string>
|
---|
7 | #include <sstream>
|
---|
8 |
|
---|
9 | #include <mars_util.h>
|
---|
10 | #include <mars_calc.h>
|
---|
11 | #include <mars_ptr.h>
|
---|
12 | #include <mars_grids.h>
|
---|
13 |
|
---|
14 | #include <coroutines.h>
|
---|
15 | #include <linalgadapt.h>
|
---|
16 |
|
---|
17 | #include "gwtypedefs.h"
|
---|
18 | #include "PNGDEM.h"
|
---|
19 |
|
---|
20 | extern boost::posix_time::milliseconds gst_DefaultLockTimeout;
|
---|
21 |
|
---|
22 | #define GW_MUTEX(x) mutable boost::mutex _##x
|
---|
23 | #define STATIC_GW_MUTEX(x) static boost::mutex _##x
|
---|
24 | #define DEFN_STATIC_GW_MUTEX(cls,x) boost::mutex cls::_##x
|
---|
25 | #define GW_SCOPED_LOCK(x) boost::mutex::scoped_lock x(_##x)
|
---|
26 |
|
---|
27 | #ifdef _DEBUG
|
---|
28 | #define GW_WAIT(x) { assert(_##x.timed_lock(gst_DefaultLockTimeout) && "Possible deadlock encountered"); _##x.unlock(); }
|
---|
29 | #else
|
---|
30 | #define GW_WAIT(x) { _##x.lock(); _##x.unlock(); }
|
---|
31 | #endif
|
---|
32 |
|
---|
33 | #ifdef WIN32
|
---|
34 | #pragma warning( disable : 4290 )
|
---|
35 | #endif
|
---|
36 |
|
---|
37 | namespace geoworld
|
---|
38 | {
|
---|
39 | inline int ALIGN(const int x, const unsigned short nMacroLevel)
|
---|
40 | {
|
---|
41 | if (x < 0)
|
---|
42 | return x - ((x + 1) % nMacroLevel + (nMacroLevel - 1));
|
---|
43 | else
|
---|
44 | return x - (x % nMacroLevel);
|
---|
45 | }
|
---|
46 |
|
---|
47 | template< typename BBP >
|
---|
48 | inline mars::vector2Df CLAMP(const mars::BBox< BBP > & bbox, const mars::vector2Df & pt)
|
---|
49 | {
|
---|
50 | return
|
---|
51 | mars::vector2Df(
|
---|
52 | bbox.horizontal().clamp(static_cast< BBP > (pt.x)),
|
---|
53 | bbox.vertical().clamp(static_cast< BBP > (pt.y))
|
---|
54 | );
|
---|
55 | }
|
---|
56 |
|
---|
57 | template< typename MTX, typename LOCKTYPE >
|
---|
58 | class DetachableScopedTryLock
|
---|
59 | {
|
---|
60 | public:
|
---|
61 | DetachableScopedTryLock(MTX & mtx)
|
---|
62 | : _plck(new LOCKTYPE(mtx, boost::try_to_lock))
|
---|
63 | {}
|
---|
64 | ~DetachableScopedTryLock()
|
---|
65 | {
|
---|
66 | delete _plck;
|
---|
67 | }
|
---|
68 |
|
---|
69 | inline LOCKTYPE * detach()
|
---|
70 | {
|
---|
71 | assert(_plck != NULL);
|
---|
72 | LOCKTYPE * plckTmp = _plck;
|
---|
73 | _plck = NULL;
|
---|
74 | return plckTmp;
|
---|
75 | }
|
---|
76 |
|
---|
77 | inline bool operator !() const { return !_plck->operator bool (); }
|
---|
78 | inline operator bool () const { return _plck->operator bool (); }
|
---|
79 |
|
---|
80 | private:
|
---|
81 | LOCKTYPE * _plck;
|
---|
82 | };
|
---|
83 |
|
---|
84 | template <class Derived>
|
---|
85 | class CylindricalZone
|
---|
86 | {
|
---|
87 | public:
|
---|
88 | template <class J>
|
---|
89 | class IterateUpsideProxy
|
---|
90 | {
|
---|
91 | public:
|
---|
92 | const J & zone;
|
---|
93 |
|
---|
94 | inline IterateUpsideProxy (const J & zone)
|
---|
95 | : zone(zone) {}
|
---|
96 |
|
---|
97 | inline float operator () (const float & x, const float & y) const { return zone.upside(x, y); }
|
---|
98 | };
|
---|
99 | template <class J>
|
---|
100 | class IterateDownsideProxy
|
---|
101 | {
|
---|
102 | public:
|
---|
103 | const J & zone;
|
---|
104 |
|
---|
105 | inline IterateDownsideProxy (const J & zone)
|
---|
106 | : zone(zone) {}
|
---|
107 |
|
---|
108 | inline float operator () (const float & x, const float & y) const { return zone.downside(x, y); }
|
---|
109 | };
|
---|
110 |
|
---|
111 | template <class J, class IteratorProxy >
|
---|
112 | class DEMIterator : public std::iterator <std::input_iterator_tag, GWCoords >
|
---|
113 | {
|
---|
114 | private:
|
---|
115 | const J & _zone;
|
---|
116 | GWCoords _center, _curr;
|
---|
117 | const unsigned short _nMacroLevel;
|
---|
118 | int
|
---|
119 | _y, _x, _hsq, _out, _in,
|
---|
120 | _nOutside, _nInside;
|
---|
121 | const IteratorProxy _proxy;
|
---|
122 |
|
---|
123 | CR_CONTEXT;
|
---|
124 |
|
---|
125 | private:
|
---|
126 | inline DEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel)
|
---|
127 | : _center (center), _zone(parent), _nMacroLevel(nMacroLevel),
|
---|
128 | _nOutside (ALIGN(mars::RNDi(parent.outside()), nMacroLevel)), _nInside (mars::RNDi(parent.inside())),
|
---|
129 | _proxy (parent)
|
---|
130 | {
|
---|
131 | CR_INIT();
|
---|
132 | process();
|
---|
133 | }
|
---|
134 | inline void assignmentStep ()
|
---|
135 | {
|
---|
136 | _hsq = mars::SQ(_x) + mars::SQ(_y);
|
---|
137 |
|
---|
138 | _curr.x = _x + _center.x;
|
---|
139 | _curr.y = _y + _center.y;
|
---|
140 | _curr.z = static_cast <GWCoords::Precision> (
|
---|
141 | _proxy(static_cast <float> (_x), static_cast <float> (_y))
|
---|
142 | ) + _center.z;
|
---|
143 | }
|
---|
144 | void process ()
|
---|
145 | {
|
---|
146 | CR_START();
|
---|
147 | using namespace mars;
|
---|
148 |
|
---|
149 | // Iterate top-side of ring
|
---|
150 | for (_y = -_nOutside; _y <= -_nInside; _y += _nMacroLevel)
|
---|
151 | {
|
---|
152 | _out = ALIGN(RNDi(sqrt(static_cast <float> (SQ(_nOutside) - SQ(_y)))), _nMacroLevel);
|
---|
153 | for (_x = -_out; _x <= +_out; _x += _nMacroLevel)
|
---|
154 | {
|
---|
155 | assignmentStep();
|
---|
156 | CR_RETURN_VOID;
|
---|
157 | }
|
---|
158 | }
|
---|
159 |
|
---|
160 | // Iterate left and right sides of ring
|
---|
161 | for (; _y < +_nInside; _y += _nMacroLevel)
|
---|
162 | {
|
---|
163 | _out = ALIGN(RNDi(sqrt(static_cast <float> (SQ(_nOutside) - SQ(_y)))), _nMacroLevel);
|
---|
164 | _in = ALIGN(RNDi(sqrt(static_cast <float> (std::max(0, SQ(_nInside) - SQ(_y))))), _nMacroLevel);
|
---|
165 | // Left side
|
---|
166 | // FIXME: Seems to get caught in an infinite loop having big numbers with CraterGM
|
---|
167 | // CraterGM parameters: 0.5f, 100.0f, 0.5f, 0.5f, 0.025f, 0.35f, 0.65f, 0.125f
|
---|
168 | for (_x = -_out; _x <= -_in; _x += _nMacroLevel)
|
---|
169 | {
|
---|
170 | assignmentStep();
|
---|
171 | CR_RETURN_VOID;
|
---|
172 | }
|
---|
173 | // Right side
|
---|
174 | for (_x = +_out; _x >= +_in; _x -= _nMacroLevel)
|
---|
175 | {
|
---|
176 | assignmentStep();
|
---|
177 | CR_RETURN_VOID;
|
---|
178 | }
|
---|
179 | }
|
---|
180 |
|
---|
181 | // Iterate bottom side of ring
|
---|
182 | for (; _y <= +_nOutside; _y += _nMacroLevel)
|
---|
183 | {
|
---|
184 | _out = ALIGN(RNDi(sqrt(static_cast <float> (SQ(_nOutside) - SQ(_y)))), _nMacroLevel);
|
---|
185 | for (_x = -_out; _x <= +_out; _x += _nMacroLevel)
|
---|
186 | {
|
---|
187 | assignmentStep();
|
---|
188 | CR_RETURN_VOID;
|
---|
189 | }
|
---|
190 | }
|
---|
191 |
|
---|
192 | CR_END();
|
---|
193 | }
|
---|
194 |
|
---|
195 | public:
|
---|
196 | inline GWCoords & operator*() { return _curr; }
|
---|
197 | inline GWCoords * operator->() { return &_curr; }
|
---|
198 | inline operator bool () { return !CR_TERM; }
|
---|
199 | inline DEMIterator & operator++()
|
---|
200 | {
|
---|
201 | process();
|
---|
202 | return *this;
|
---|
203 | }
|
---|
204 | inline DEMIterator operator++(int)
|
---|
205 | {
|
---|
206 | auto old = *this;
|
---|
207 |
|
---|
208 | process();
|
---|
209 | return old;
|
---|
210 | }
|
---|
211 |
|
---|
212 | friend class CylindricalZone;
|
---|
213 | };
|
---|
214 |
|
---|
215 | template <class J>
|
---|
216 | class UpsideDEMIterator : public DEMIterator <J, IterateUpsideProxy <J> >
|
---|
217 | {
|
---|
218 | public:
|
---|
219 | inline UpsideDEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel)
|
---|
220 | : DEMIterator <J, IterateUpsideProxy <J> > (parent, center, nMacroLevel) {}
|
---|
221 | };
|
---|
222 |
|
---|
223 | template <class J>
|
---|
224 | class DownsideDEMIterator : public DEMIterator <J, IterateDownsideProxy <J> >
|
---|
225 | {
|
---|
226 | public:
|
---|
227 | inline DownsideDEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel)
|
---|
228 | : DEMIterator <J, IterateDownsideProxy <J> > (parent, center, nMacroLevel) {}
|
---|
229 | };
|
---|
230 |
|
---|
231 | UpsideDEMIterator <Derived> walkUpside (const GWCoords & center, const unsigned short nMacroLevel = 1) const { return UpsideDEMIterator <Derived> (static_cast <const Derived &> (*this), center, nMacroLevel); }
|
---|
232 | DownsideDEMIterator <Derived> walkDownside (const GWCoords & center, const unsigned short nMacroLevel = 1) const { return DownsideDEMIterator <Derived> (static_cast <const Derived &> (*this), center, nMacroLevel); }
|
---|
233 |
|
---|
234 | inline float outside () const { return static_cast <const Derived &> (*this) .outside(); }
|
---|
235 | inline float inside () const { return static_cast <const Derived &> (*this) .inside(); }
|
---|
236 | inline float downside (const float x, const float y) const { return static_cast <const Derived &> (*this) .downside(x, y); }
|
---|
237 | inline float upside (const float x, const float y) const { return static_cast <const Derived &> (*this) .upside(x, y); }
|
---|
238 | inline float area () const { return static_cast <const Derived &> (*this) .area(); }
|
---|
239 |
|
---|
240 | /************************************************************************
|
---|
241 | * Computes the p and z coordinates of random cylindrical coordinates inside
|
---|
242 | * bounded region of the perimeter uplift zone by obtaining a random integer
|
---|
243 | * from zero to total area of the region and setting p to the modulus of the
|
---|
244 | * total width of the region and z to the random integer divided by width and
|
---|
245 | * modulus by total region height
|
---|
246 | ************************************************************************/
|
---|
247 | const GWCoords random (const GWCoords & center) const
|
---|
248 | {
|
---|
249 | using namespace mars;
|
---|
250 |
|
---|
251 | const RangeX< short > mmiRadius = RangeX< short >
|
---|
252 | (
|
---|
253 | static_cast< short > (inside()),
|
---|
254 | static_cast< short > (outside())
|
---|
255 | );
|
---|
256 | const VectorTag< short >::PC
|
---|
257 | coords = VectorTag< short >::PC (
|
---|
258 | mmiRadius.next(),
|
---|
259 | static_cast <float> (RAND(static_cast <int> (2 * mars::PI * 100)) / 100)
|
---|
260 | );
|
---|
261 | const VectorTag< short >::V2 v2 =
|
---|
262 | static_cast< VectorTag< short >::V2 > (coords);
|
---|
263 |
|
---|
264 | return GWCoords(
|
---|
265 | v2.x + center.x,
|
---|
266 | v2.y + center.y,
|
---|
267 | center.z + RangeX< short > (
|
---|
268 | static_cast< short > (downside(v2.x, v2.y)),
|
---|
269 | static_cast< short > (upside(v2.x, v2.y))
|
---|
270 | ) .next()
|
---|
271 | );
|
---|
272 | }
|
---|
273 | int volume () const
|
---|
274 | {
|
---|
275 | return mars::RNDi(abs(area() * (outside() - inside())) * mars::PI);
|
---|
276 | }
|
---|
277 | };
|
---|
278 |
|
---|
279 | namespace noise {
|
---|
280 | template< bool FLAG > struct SIGNED;
|
---|
281 | template<> struct SIGNED< true > { enum { DIVISOR = 2 }; };
|
---|
282 | template<> struct SIGNED< false > { enum { DIVISOR = 1 }; };
|
---|
283 | }
|
---|
284 |
|
---|
285 | template< typename T >
|
---|
286 | class NoiseGenerator
|
---|
287 | {
|
---|
288 | public:
|
---|
289 | using NoiseMap = mars::MidpointDisplacementGrid< T >;
|
---|
290 |
|
---|
291 | private:
|
---|
292 | float _frSmoothIter;
|
---|
293 |
|
---|
294 | public:
|
---|
295 | T noise;
|
---|
296 |
|
---|
297 | inline NoiseGenerator (const float frSmoothIter, const T frNoise)
|
---|
298 | : _frSmoothIter(frSmoothIter), noise(frNoise) {}
|
---|
299 |
|
---|
300 | mars::ptr< NoiseMap > compute (const unsigned short width, const unsigned short height, bool bSeed = false) const
|
---|
301 | {
|
---|
302 | using namespace noise;
|
---|
303 |
|
---|
304 | assert(_frSmoothIter >= 0.0f && _frSmoothIter <= 1.0f);
|
---|
305 |
|
---|
306 | mars::ptr< NoiseMap > map = NoiseMap::createInstance (std::max(static_cast< unsigned short > (2), width), std::max(static_cast< unsigned short > (2), height), mars::Wrap);
|
---|
307 |
|
---|
308 | if (bSeed)
|
---|
309 | for (typename NoiseMap::EdgeSeedIterator it = map->edgeSeedIterator(); it; ++it)
|
---|
310 | it = mars::RANDf(map->mindim)
|
---|
311 | - static_cast< T > (SIGNED< std::numeric_limits< T >::is_signed >::DIVISOR - 1)
|
---|
312 | * (map->mindim / static_cast< T > (SIGNED< std::numeric_limits< T >::is_signed >::DIVISOR));
|
---|
313 | else
|
---|
314 | map->clear();
|
---|
315 |
|
---|
316 | const unsigned short nBrownIter = static_cast< unsigned short > (static_cast< float > (map->itercount) * (_frSmoothIter));
|
---|
317 |
|
---|
318 | if (map->itercount - nBrownIter > 0)
|
---|
319 | {
|
---|
320 | typename NoiseMap::PinkFn funcPink (map->mindim, noise);
|
---|
321 |
|
---|
322 | map->iterations(map->itercount - nBrownIter, funcPink);
|
---|
323 | }
|
---|
324 | if (nBrownIter > 0)
|
---|
325 | {
|
---|
326 | typename NoiseMap::BrownianFn funcBrown (map->mindim, noise);
|
---|
327 |
|
---|
328 | map->iterations(nBrownIter, funcBrown);
|
---|
329 | }
|
---|
330 | return map;
|
---|
331 | }
|
---|
332 | };
|
---|
333 |
|
---|
334 | class TaperFn : private mars::GaussianFn< float >
|
---|
335 | {
|
---|
336 | public:
|
---|
337 | const float outside;
|
---|
338 | const mars::Magnitudinal< float > displace;
|
---|
339 |
|
---|
340 | TaperFn ()
|
---|
341 | : outside(0), displace(0) {}
|
---|
342 |
|
---|
343 | inline TaperFn & operator = (const TaperFn & copy)
|
---|
344 | {
|
---|
345 | GaussianFn::operator = (copy);
|
---|
346 | const_cast< float & > (outside) = copy.outside;
|
---|
347 | const_cast< mars::Magnitudinal< float > & > (displace) = copy.displace;
|
---|
348 | return *this;
|
---|
349 | }
|
---|
350 |
|
---|
351 | inline static TaperFn createTaperFn (const float fScale, const float fDisplace = 0.0f)
|
---|
352 | {
|
---|
353 | return TaperFn(fScale, fDisplace, GaussianFn< float > (1, 1, (fScale - fDisplace) / 3).f(fScale));
|
---|
354 | }
|
---|
355 |
|
---|
356 | inline const float f (const float x, const float y) const
|
---|
357 | {
|
---|
358 | // TODO: Try to optimize-away sqrt
|
---|
359 | return GaussianFn::f(std::max(0.0f, static_cast< float > (sqrt(mars::SQ(x) + mars::SQ(y)) - displace)));
|
---|
360 | }
|
---|
361 |
|
---|
362 | inline const float f (const float x) const
|
---|
363 | {
|
---|
364 | return std::max(0.0f, GaussianFn::f(abs(x) - displace));
|
---|
365 | }
|
---|
366 |
|
---|
367 | const float blend (const float x, const float y, const float a, const float b) const
|
---|
368 | {
|
---|
369 | const float fFactor = f(x, y);
|
---|
370 |
|
---|
371 | return a * (1.0f - fFactor) + b * fFactor;
|
---|
372 | }
|
---|
373 | const float blend (const float x, const float a, const float b) const
|
---|
374 | {
|
---|
375 | const float fFactor = f(x);
|
---|
376 |
|
---|
377 | return a * (1.0f - fFactor) + b * fFactor;
|
---|
378 | }
|
---|
379 |
|
---|
380 | private:
|
---|
381 | TaperFn (const float fScale, const float fDisplace, const float fFalloffDisplace)
|
---|
382 | : GaussianFn(1.0f, 1.0f + fFalloffDisplace, (fScale - fDisplace) / 3, -fFalloffDisplace), displace(fDisplace),
|
---|
383 | outside(mars::BisectMethod< float, GaussianFn< float >, 20 >::solve(GaussianFn< float > (1.0f, 1.0f + fFalloffDisplace, (fScale - fDisplace) / 3, -fFalloffDisplace), 0, (fScale - fDisplace)*2) + fDisplace) {}
|
---|
384 | };
|
---|
385 |
|
---|
386 | template <typename J, typename F>
|
---|
387 | inline GeoHeightMap::Precision blend ( const GeoHeightMap::Precision nVal1, const J nVal2, const F fAmt )
|
---|
388 | {
|
---|
389 | return
|
---|
390 | static_cast <GeoHeightMap::Precision> (
|
---|
391 | static_cast <F> (nVal1) * (static_cast <F> (1.0) - fAmt)
|
---|
392 | )
|
---|
393 | + static_cast <GeoHeightMap::Precision> (
|
---|
394 | static_cast <F> (nVal2) * fAmt
|
---|
395 | );
|
---|
396 | }
|
---|
397 |
|
---|
398 | void dumpPNGDEM (PNGDEM & pngdem);
|
---|
399 | void writePNGDEM (PNGDEM & pngdem, const std::string & sName);
|
---|
400 | void loadPNGDEM (PNGDEM & pngdem, const std::string & sName);
|
---|
401 |
|
---|
402 | extern PNGDEM GLOBALDEM;
|
---|
403 |
|
---|
404 | #ifdef _GWDEBUG
|
---|
405 | #define DUMP_GLOBALDEM() dumpPNGDEM(GLOBALDEM)
|
---|
406 | #define LOAD_GLOBALDEM(x) loadPNGDEM(GLOBALDEM,x)
|
---|
407 | #define ADDCROSS_GLOBALDEM(x,y) GLOBALDEM.addCrosshairPoint(x,y)
|
---|
408 | #define ADDCROSS_RGB_GLOBALDEM(x,y,r,g,b) GLOBALDEM.addCrosshairPoint(x,y,r,g,b)
|
---|
409 | #define ADDCROSS_RGBA_GLOBALDEM(x,y,r,g,b,a) GLOBALDEM.addCrosshairPoint(x,y,r,g,b,a)
|
---|
410 | #define INCCROSS_GLOBALDEM() GLOBALDEM.nextCrosshair()
|
---|
411 | #else
|
---|
412 | #define DUMP_GLOBALDEM() (NULL)
|
---|
413 | #define LOAD_GLOBALDEM(x) (NULL)
|
---|
414 | #define ADDCROSS_GLOBALDEM(x,y) (NULL)
|
---|
415 | #define ADDCROSS_RGB_GLOBALDEM(x,y,r,g,b) (NULL)
|
---|
416 | #define ADDCROSS_RGBA_GLOBALDEM(x,y,r,g,b,a) (NULL)
|
---|
417 | #define INCCROSS_GLOBALDEM() (NULL)
|
---|
418 | #endif
|
---|
419 |
|
---|
420 | static class DemDump
|
---|
421 | {
|
---|
422 | private:
|
---|
423 | GW_MUTEX(mutex);
|
---|
424 |
|
---|
425 | public:
|
---|
426 | template< typename V >
|
---|
427 | inline void operator << ( const V & view )
|
---|
428 | {
|
---|
429 | #ifdef _GWDEBUG
|
---|
430 | { GW_SCOPED_LOCK(mutex);
|
---|
431 | GLOBALDEM << view;
|
---|
432 | dumpPNGDEM(GLOBALDEM);
|
---|
433 | }
|
---|
434 | #endif
|
---|
435 | }
|
---|
436 | } DEMDUMP;
|
---|
437 |
|
---|
438 | class DemSave
|
---|
439 | {
|
---|
440 | private:
|
---|
441 | GW_MUTEX(mutex);
|
---|
442 | #ifdef _GWDEBUG
|
---|
443 | const std::string _sName;
|
---|
444 | #endif
|
---|
445 |
|
---|
446 | public:
|
---|
447 | inline DemSave (std::stringstream & ss)
|
---|
448 | #ifdef _GWDEBUG
|
---|
449 | : _sName(ss.str())
|
---|
450 | #endif
|
---|
451 | {}
|
---|
452 | inline DemSave (const std::string & sName)
|
---|
453 | #ifdef _GWDEBUG
|
---|
454 | : _sName (sName)
|
---|
455 | #endif
|
---|
456 | {}
|
---|
457 |
|
---|
458 | template< typename V >
|
---|
459 | inline void operator << (const V & view)
|
---|
460 | {
|
---|
461 | #ifdef _GWDEBUG
|
---|
462 | { GW_SCOPED_LOCK(mutex);
|
---|
463 | GLOBALDEM << view;
|
---|
464 | writePNGDEM(GLOBALDEM, _sName);
|
---|
465 | }
|
---|
466 | #endif
|
---|
467 | }
|
---|
468 | };
|
---|
469 | #define DEMSAVE(x) DemSave(static_cast< std::strstream && > (std::strstream() << x << std::ends))
|
---|
470 | }
|
---|