source: Revenant/geoworld/include/gwutil.h@ 7ef8ec4

port/mars-tycoon
Last change on this file since 7ef8ec4 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: 13.3 KB
Line 
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
20extern 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
37namespace 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}
Note: See TracBrowser for help on using the repository browser.