// // Crytek Source code // // written my Martin Mittring // // used by CHeightmapAccessibility // // Dependencies: none // #pragma once #define _USE_MATH_DEFINES // M_PI #include // sin() #include // STL vector<> #include // assert() #include // FLT_MAX // helper class to calculated hemisphere accessibility of a 2d graph or more useful for a heightmap (apply the same algo. n times) // call Insert() 2d point on a graph (x coordiante has to advance for each point // this method returns the slope at that position (without any noise) // // Performance for a line with n points: // O_min(n), O_avg(k*n*n) k<1 depending on input, Omax(n*n) // // because of the cache locality this is a very fast way to calculate the accessibility // // Comparison with simple raycasting (other algothms are much more complex to code): // result is noisy, O_avg(q*n*n), q>8 depending on quality, with more programming you can get cache locality almost like here // class CHorizonTracker { public: //! constructor (reinstance for every line you want to calculate) CHorizonTracker( void ) { m_vHorizon.reserve(1024); // to avoid too many reallocations } //! \param infX has to be always bigger that the value put in before //! \param infY (height) has to be in the same scale as infX //! \return slope (always positive or 0) float Insert( const float infX, const float infY ) { int iSize=(int)m_vHorizon.size(); for(;iSize>=2;) { SPoint2D &Current=m_vHorizon[iSize-1]; SPoint2D &Prev=m_vHorizon[iSize-2]; assert(Prev.xCurrent.y) { m_vHorizon.pop_back();iSize--; // remove current } else break; // horizon found } m_vHorizon.push_back( SPoint2D(infX,infY) ); // calculate slope if(iSize<=0)return 0; else { SPoint2D &Current=m_vHorizon[iSize-1]; assert(infX-Current.x!=0); // infX has to advance (check your input) return min( (infY-Current.y)/(infX-Current.x) , 0 ); } } //! reset to inital state void Clear() { m_vHorizon.resize(0); } private: struct SPoint2D { SPoint2D() {} SPoint2D( const float infX, const float infY ) { x=infX;y=infY; } float x,y; }; std::vector< SPoint2D > m_vHorizon; //!< sorted by x (first element has the lowest x) }; //! slow but stable //!\param indwValue has to be power of two inline DWORD GetIntLog2( const DWORD indwValue ) { for(DWORD i=0;i<32;i++) if((1<