#pragma once #include #include #include #include #include #include #include #include #include #include #include "gwtypedefs.h" #include "PNGDEM.h" extern boost::posix_time::milliseconds gst_DefaultLockTimeout; #define GW_MUTEX(x) mutable boost::mutex _##x #define STATIC_GW_MUTEX(x) static boost::mutex _##x #define DEFN_STATIC_GW_MUTEX(cls,x) boost::mutex cls::_##x #define GW_SCOPED_LOCK(x) boost::mutex::scoped_lock x(_##x) #ifdef _DEBUG #define GW_WAIT(x) { assert(_##x.timed_lock(gst_DefaultLockTimeout) && "Possible deadlock encountered"); _##x.unlock(); } #else #define GW_WAIT(x) { _##x.lock(); _##x.unlock(); } #endif #ifdef WIN32 #pragma warning( disable : 4290 ) #endif namespace geoworld { inline int ALIGN(const int x, const unsigned short nMacroLevel) { if (x < 0) return x - ((x + 1) % nMacroLevel + (nMacroLevel - 1)); else return x - (x % nMacroLevel); } template< typename BBP > inline mars::vector2Df CLAMP(const mars::BBox< BBP > & bbox, const mars::vector2Df & pt) { return mars::vector2Df( bbox.horizontal().clamp(static_cast< BBP > (pt.x)), bbox.vertical().clamp(static_cast< BBP > (pt.y)) ); } template< typename MTX, typename LOCKTYPE > class DetachableScopedTryLock { public: DetachableScopedTryLock(MTX & mtx) : _plck(new LOCKTYPE(mtx, boost::try_to_lock)) {} ~DetachableScopedTryLock() { delete _plck; } inline LOCKTYPE * detach() { assert(_plck != NULL); LOCKTYPE * plckTmp = _plck; _plck = NULL; return plckTmp; } inline bool operator !() const { return !_plck->operator bool (); } inline operator bool () const { return _plck->operator bool (); } private: LOCKTYPE * _plck; }; template class CylindricalZone { public: template class IterateUpsideProxy { public: const J & zone; inline IterateUpsideProxy (const J & zone) : zone(zone) {} inline float operator () (const float & x, const float & y) const { return zone.upside(x, y); } }; template class IterateDownsideProxy { public: const J & zone; inline IterateDownsideProxy (const J & zone) : zone(zone) {} inline float operator () (const float & x, const float & y) const { return zone.downside(x, y); } }; template class DEMIterator : public std::iterator { private: const J & _zone; GWCoords _center, _curr; const unsigned short _nMacroLevel; int _y, _x, _hsq, _out, _in, _nOutside, _nInside; const IteratorProxy _proxy; CR_CONTEXT; private: inline DEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel) : _center (center), _zone(parent), _nMacroLevel(nMacroLevel), _nOutside (ALIGN(mars::RNDi(parent.outside()), nMacroLevel)), _nInside (mars::RNDi(parent.inside())), _proxy (parent) { CR_INIT(); process(); } inline void assignmentStep () { _hsq = mars::SQ(_x) + mars::SQ(_y); _curr.x = _x + _center.x; _curr.y = _y + _center.y; _curr.z = static_cast ( _proxy(static_cast (_x), static_cast (_y)) ) + _center.z; } void process () { CR_START(); using namespace mars; // Iterate top-side of ring for (_y = -_nOutside; _y <= -_nInside; _y += _nMacroLevel) { _out = ALIGN(RNDi(sqrt(static_cast (SQ(_nOutside) - SQ(_y)))), _nMacroLevel); for (_x = -_out; _x <= +_out; _x += _nMacroLevel) { assignmentStep(); CR_RETURN_VOID; } } // Iterate left and right sides of ring for (; _y < +_nInside; _y += _nMacroLevel) { _out = ALIGN(RNDi(sqrt(static_cast (SQ(_nOutside) - SQ(_y)))), _nMacroLevel); _in = ALIGN(RNDi(sqrt(static_cast (std::max(0, SQ(_nInside) - SQ(_y))))), _nMacroLevel); // Left side // FIXME: Seems to get caught in an infinite loop having big numbers with CraterGM // CraterGM parameters: 0.5f, 100.0f, 0.5f, 0.5f, 0.025f, 0.35f, 0.65f, 0.125f for (_x = -_out; _x <= -_in; _x += _nMacroLevel) { assignmentStep(); CR_RETURN_VOID; } // Right side for (_x = +_out; _x >= +_in; _x -= _nMacroLevel) { assignmentStep(); CR_RETURN_VOID; } } // Iterate bottom side of ring for (; _y <= +_nOutside; _y += _nMacroLevel) { _out = ALIGN(RNDi(sqrt(static_cast (SQ(_nOutside) - SQ(_y)))), _nMacroLevel); for (_x = -_out; _x <= +_out; _x += _nMacroLevel) { assignmentStep(); CR_RETURN_VOID; } } CR_END(); } public: inline GWCoords & operator*() { return _curr; } inline GWCoords * operator->() { return &_curr; } inline operator bool () { return !CR_TERM; } inline DEMIterator & operator++() { process(); return *this; } inline DEMIterator operator++(int) { auto old = *this; process(); return old; } friend class CylindricalZone; }; template class UpsideDEMIterator : public DEMIterator > { public: inline UpsideDEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel) : DEMIterator > (parent, center, nMacroLevel) {} }; template class DownsideDEMIterator : public DEMIterator > { public: inline DownsideDEMIterator (const J & parent, const GWCoords & center, const unsigned short nMacroLevel) : DEMIterator > (parent, center, nMacroLevel) {} }; UpsideDEMIterator walkUpside (const GWCoords & center, const unsigned short nMacroLevel = 1) const { return UpsideDEMIterator (static_cast (*this), center, nMacroLevel); } DownsideDEMIterator walkDownside (const GWCoords & center, const unsigned short nMacroLevel = 1) const { return DownsideDEMIterator (static_cast (*this), center, nMacroLevel); } inline float outside () const { return static_cast (*this) .outside(); } inline float inside () const { return static_cast (*this) .inside(); } inline float downside (const float x, const float y) const { return static_cast (*this) .downside(x, y); } inline float upside (const float x, const float y) const { return static_cast (*this) .upside(x, y); } inline float area () const { return static_cast (*this) .area(); } /************************************************************************ * Computes the p and z coordinates of random cylindrical coordinates inside * bounded region of the perimeter uplift zone by obtaining a random integer * from zero to total area of the region and setting p to the modulus of the * total width of the region and z to the random integer divided by width and * modulus by total region height ************************************************************************/ const GWCoords random (const GWCoords & center) const { using namespace mars; const RangeX< short > mmiRadius = RangeX< short > ( static_cast< short > (inside()), static_cast< short > (outside()) ); const VectorTag< short >::PC coords = VectorTag< short >::PC ( mmiRadius.next(), static_cast (RAND(static_cast (2 * mars::PI * 100)) / 100) ); const VectorTag< short >::V2 v2 = static_cast< VectorTag< short >::V2 > (coords); return GWCoords( v2.x + center.x, v2.y + center.y, center.z + RangeX< short > ( static_cast< short > (downside(v2.x, v2.y)), static_cast< short > (upside(v2.x, v2.y)) ) .next() ); } int volume () const { return mars::RNDi(abs(area() * (outside() - inside())) * mars::PI); } }; namespace noise { template< bool FLAG > struct SIGNED; template<> struct SIGNED< true > { enum { DIVISOR = 2 }; }; template<> struct SIGNED< false > { enum { DIVISOR = 1 }; }; } template< typename T > class NoiseGenerator { public: using NoiseMap = mars::MidpointDisplacementGrid< T >; private: float _frSmoothIter; public: T noise; inline NoiseGenerator (const float frSmoothIter, const T frNoise) : _frSmoothIter(frSmoothIter), noise(frNoise) {} mars::ptr< NoiseMap > compute (const unsigned short width, const unsigned short height, bool bSeed = false) const { using namespace noise; assert(_frSmoothIter >= 0.0f && _frSmoothIter <= 1.0f); mars::ptr< NoiseMap > map = NoiseMap::createInstance (std::max(static_cast< unsigned short > (2), width), std::max(static_cast< unsigned short > (2), height), mars::Wrap); if (bSeed) for (typename NoiseMap::EdgeSeedIterator it = map->edgeSeedIterator(); it; ++it) it = mars::RANDf(map->mindim) - static_cast< T > (SIGNED< std::numeric_limits< T >::is_signed >::DIVISOR - 1) * (map->mindim / static_cast< T > (SIGNED< std::numeric_limits< T >::is_signed >::DIVISOR)); else map->clear(); const unsigned short nBrownIter = static_cast< unsigned short > (static_cast< float > (map->itercount) * (_frSmoothIter)); if (map->itercount - nBrownIter > 0) { typename NoiseMap::PinkFn funcPink (map->mindim, noise); map->iterations(map->itercount - nBrownIter, funcPink); } if (nBrownIter > 0) { typename NoiseMap::BrownianFn funcBrown (map->mindim, noise); map->iterations(nBrownIter, funcBrown); } return map; } }; class TaperFn : private mars::GaussianFn< float > { public: const float outside; const mars::Magnitudinal< float > displace; TaperFn () : outside(0), displace(0) {} inline TaperFn & operator = (const TaperFn & copy) { GaussianFn::operator = (copy); const_cast< float & > (outside) = copy.outside; const_cast< mars::Magnitudinal< float > & > (displace) = copy.displace; return *this; } inline static TaperFn createTaperFn (const float fScale, const float fDisplace = 0.0f) { return TaperFn(fScale, fDisplace, GaussianFn< float > (1, 1, (fScale - fDisplace) / 3).f(fScale)); } inline const float f (const float x, const float y) const { // TODO: Try to optimize-away sqrt return GaussianFn::f(std::max(0.0f, static_cast< float > (sqrt(mars::SQ(x) + mars::SQ(y)) - displace))); } inline const float f (const float x) const { return std::max(0.0f, GaussianFn::f(abs(x) - displace)); } const float blend (const float x, const float y, const float a, const float b) const { const float fFactor = f(x, y); return a * (1.0f - fFactor) + b * fFactor; } const float blend (const float x, const float a, const float b) const { const float fFactor = f(x); return a * (1.0f - fFactor) + b * fFactor; } private: TaperFn (const float fScale, const float fDisplace, const float fFalloffDisplace) : GaussianFn(1.0f, 1.0f + fFalloffDisplace, (fScale - fDisplace) / 3, -fFalloffDisplace), displace(fDisplace), outside(mars::BisectMethod< float, GaussianFn< float >, 20 >::solve(GaussianFn< float > (1.0f, 1.0f + fFalloffDisplace, (fScale - fDisplace) / 3, -fFalloffDisplace), 0, (fScale - fDisplace)*2) + fDisplace) {} }; template inline GeoHeightMap::Precision blend ( const GeoHeightMap::Precision nVal1, const J nVal2, const F fAmt ) { return static_cast ( static_cast (nVal1) * (static_cast (1.0) - fAmt) ) + static_cast ( static_cast (nVal2) * fAmt ); } void dumpPNGDEM (PNGDEM & pngdem); void writePNGDEM (PNGDEM & pngdem, const std::string & sName); void loadPNGDEM (PNGDEM & pngdem, const std::string & sName); extern PNGDEM GLOBALDEM; #ifdef _GWDEBUG #define DUMP_GLOBALDEM() dumpPNGDEM(GLOBALDEM) #define LOAD_GLOBALDEM(x) loadPNGDEM(GLOBALDEM,x) #define ADDCROSS_GLOBALDEM(x,y) GLOBALDEM.addCrosshairPoint(x,y) #define ADDCROSS_RGB_GLOBALDEM(x,y,r,g,b) GLOBALDEM.addCrosshairPoint(x,y,r,g,b) #define ADDCROSS_RGBA_GLOBALDEM(x,y,r,g,b,a) GLOBALDEM.addCrosshairPoint(x,y,r,g,b,a) #define INCCROSS_GLOBALDEM() GLOBALDEM.nextCrosshair() #else #define DUMP_GLOBALDEM() (NULL) #define LOAD_GLOBALDEM(x) (NULL) #define ADDCROSS_GLOBALDEM(x,y) (NULL) #define ADDCROSS_RGB_GLOBALDEM(x,y,r,g,b) (NULL) #define ADDCROSS_RGBA_GLOBALDEM(x,y,r,g,b,a) (NULL) #define INCCROSS_GLOBALDEM() (NULL) #endif static class DemDump { private: GW_MUTEX(mutex); public: template< typename V > inline void operator << ( const V & view ) { #ifdef _GWDEBUG { GW_SCOPED_LOCK(mutex); GLOBALDEM << view; dumpPNGDEM(GLOBALDEM); } #endif } } DEMDUMP; class DemSave { private: GW_MUTEX(mutex); #ifdef _GWDEBUG const std::string _sName; #endif public: inline DemSave (std::stringstream & ss) #ifdef _GWDEBUG : _sName(ss.str()) #endif {} inline DemSave (const std::string & sName) #ifdef _GWDEBUG : _sName (sName) #endif {} template< typename V > inline void operator << (const V & view) { #ifdef _GWDEBUG { GW_SCOPED_LOCK(mutex); GLOBALDEM << view; writePNGDEM(GLOBALDEM, _sName); } #endif } }; #define DEMSAVE(x) DemSave(static_cast< std::strstream && > (std::strstream() << x << std::ends)) }