/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #pragma once #include "stdafx.h" #include #include #include #include #include #include "parser.h" /*rozne takie duperele do operacji na stringach w paszczalu, pewnie w delfi sa lepsze*/ /*konwersja zmiennych na stringi, funkcje matematyczne, logiczne, lancuchowe, I/O etc*/ template T sign(T x) { return x < static_cast(0) ? static_cast(-1) : (x > static_cast(0) ? static_cast(1) : static_cast(0)); } #define DegToRad(a) ((M_PI / 180.0) * (a)) //(a) w nawiasie, bo może być dodawaniem #define RadToDeg(r) ((180.0 / M_PI) * (r)) #define szSceneryPath "scenery/" #define szTexturePath "textures/" #define szModelPath "models/" #define szDynamicPath "dynamic/" #define szSoundPath "sounds/" #define szDataPath "data/" #define MAKE_ID4(a,b,c,d) (((std::uint32_t)(d)<<24)|((std::uint32_t)(c)<<16)|((std::uint32_t)(b)<<8)|(std::uint32_t)(a)) extern bool DebugModeFlag; extern bool FreeFlyModeFlag; extern bool EditorModeFlag; extern bool DebugCameraFlag; extern bool DebugTractionFlag; /*funkcje matematyczne*/ double Max0R(double x1, double x2); double Min0R(double x1, double x2); inline double Sign(double x) { return x >= 0 ? 1.0 : -1.0; } inline long Round(double const f) { return (long)(f + 0.5); //return lround(f); } double Random(double a, double b); int RandomInt(int min, int max); double LocalRandom(double a, double b); inline double Random() { return Random(0.0,1.0); } inline double Random(double b) { return Random(0.0, b); } inline double LocalRandom() { return LocalRandom( 0.0, 1.0 ); } inline double LocalRandom( double b ) { return LocalRandom( 0.0, b ); } inline double BorlandTime() { auto timesinceepoch = std::time( nullptr ); return timesinceepoch / (24.0 * 60 * 60); /* // std alternative auto timesinceepoch = std::chrono::system_clock::now().time_since_epoch(); return std::chrono::duration_cast( timesinceepoch ).count() / (24.0 * 60 * 60); */ } std::string Now(); double CompareTime( double t1h, double t1m, double t2h, double t2m ); /*funkcje logiczne*/ inline bool TestFlag( int const Flag, int const Value ) { return ( ( Flag & Value ) == Value ); } inline bool TestFlagAny( int const Flag, int const Value ) { return ( ( Flag & Value ) != 0 ); } bool SetFlag( int &Flag, int const Value); bool ClearFlag(int &Flag, int const Value); bool FuzzyLogic(double Test, double Threshold, double Probability); /*jesli Test>Threshold to losowanie*/ bool FuzzyLogicAI(double Test, double Threshold, double Probability); /*to samo ale zawsze niezaleznie od DebugFlag*/ /*operacje na stringach*/ std::string DUE(std::string s); /*Delete Until Equal sign*/ std::string DWE(std::string s); /*Delete While Equal sign*/ std::string ExchangeCharInString( std::string const &Source, char const From, char const To ); // zamienia jeden znak na drugi std::vector &Split(const std::string &s, char delim, std::vector &elems); std::vector Split(const std::string &s, char delim); //std::vector Split(const std::string &s); std::pair split_string_and_number( std::string const &Key ); std::string to_string(int Value); std::string to_string(unsigned int Value); std::string to_string(int Value, int width); std::string to_string(double Value); std::string to_string(double Value, int precision); std::string to_string(double Value, int precision, int width); std::string to_hex_str( int const Value, int const width = 4 ); std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); inline std::string to_string(bool Value) { return ( Value == true ? "true" : "false" ); } template std::string to_string( glm::tvec3 const &Value ) { return to_string( Value.x, 2 ) + ", " + to_string( Value.y, 2 ) + ", " + to_string( Value.z, 2 ); } template std::string to_string( glm::tvec4 const &Value, int const Width = 2 ) { return to_string( Value.x, Width ) + ", " + to_string( Value.y, Width ) + ", " + to_string( Value.z, Width ) + ", " + to_string( Value.w, Width ); } bool string_ends_with(std::string const &string, std::string const &ending); bool string_starts_with(std::string const &string, std::string const &begin); int stol_def(const std::string & str, const int & DefaultValue); std::string ToLower(std::string const &text); std::string ToUpper(std::string const &text); // replaces polish letters with basic ascii void win1250_to_ascii( std::string &Input ); // TODO: unify with win1250_to_ascii() std::string Bezogonkow( std::string Input, bool const Underscorestospaces = false ); std::string win1250_to_utf8(const std::string &input); inline std::string extract_value( std::string const &Key, std::string const &Input ) { // NOTE, HACK: the leading space allows to uniformly look for " variable=" substring std::string const input { " " + Input }; std::string value; auto lookup = input.find( " " + Key + "=" ); if( lookup != std::string::npos ) { value = input.substr( input.find_first_not_of( ' ', lookup + Key.size() + 2 ) ); lookup = value.find( ' ' ); if( lookup != std::string::npos ) { // trim everything past the value value.erase( lookup ); } } return value; } template bool extract_value( Type_ &Variable, std::string const &Key, std::string const &Input, std::string const &Default ) { auto value = extract_value( Key, Input ); if( false == value.empty() ) { // set the specified variable to retrieved value std::stringstream converter; converter << value; converter >> Variable; return true; // located the variable } else { // set the variable to provided default value if( false == Default.empty() ) { std::stringstream converter; converter << Default; converter >> Variable; } return false; // couldn't locate the variable in provided input } } template <> bool extract_value( bool &Variable, std::string const &Key, std::string const &Input, std::string const &Default ); bool FileExists( std::string const &Filename ); std::pair FileExists( std::vector const &Names, std::vector const &Extensions ); // returns time of last modification for specified file std::time_t last_modified( std::string const &Filename ); // potentially erases file extension from provided file name. returns: true if extension was removed, false otherwise bool erase_extension( std::string &Filename ); // potentially erase leading slashes from provided file path void erase_leading_slashes( std::string &Filename ); // potentially replaces backward slashes in provided file path with unix-compatible forward slashes void replace_slashes( std::string &Filename ); // returns potential path part from provided file name std::string substr_path( std::string const &Filename ); // returns common prefix of two provided strings std::ptrdiff_t len_common_prefix( std::string const &Left, std::string const &Right ); // returns true if provided string ends with another provided string bool ends_with( std::string_view String, std::string_view Suffix ); // returns true if provided string begins with another provided string bool starts_with( std::string_view String, std::string_view Prefix ); // returns true if provided string contains another provided string bool contains( std::string_view const String, std::string_view Substring ); bool contains( std::string_view const String, char Character ); template void SafeDelete( Type_ &Pointer ) { delete Pointer; Pointer = nullptr; } template void SafeDeleteArray( Type_ &Pointer ) { delete[] Pointer; Pointer = nullptr; } template Type_ is_equal( Type_ const &Left, Type_ const &Right, Type_ const Epsilon = 1e-5 ) { if( Epsilon != 0 ) { return glm::epsilonEqual( Left, Right, Epsilon ); } else { return ( Left == Right ); } } template Type_ clamp( Type_ const Value, Type_ const Min, Type_ const Max ) { Type_ value = Value; if( value < Min ) { value = Min; } if( value > Max ) { value = Max; } return value; } // keeps the provided value in specified range 0-Range, as if the range was circular buffer template Type_ clamp_circular( Type_ Value, Type_ const Range = static_cast(360) ) { Value -= Range * (int)( Value / Range ); // clamp the range to 0-360 if( Value < Type_(0) ) Value += Range; return Value; } // rounds down provided value to nearest power of two template Type_ clamp_power_of_two( Type_ Value, Type_ const Min = static_cast(1), Type_ const Max = static_cast(16384) ) { Type_ p2size{ Min }; Type_ size; while( ( p2size <= Max ) && ( p2size <= Value ) ) { size = p2size; p2size = p2size << 1; } return size; } template Type_ quantize( Type_ const Value, Type_ const Step ) { return ( Step * std::round( Value / Step ) ); } template Type_ min_speed( Type_ const Left, Type_ const Right ) { if( Left == Right ) { return Left; } return std::min( ( Left != -1 ? Left : std::numeric_limits::max() ), ( Right != -1 ? Right : std::numeric_limits::max() ) ); } template Type_ interpolate( Type_ const &First, Type_ const &Second, float const Factor ) { return static_cast( ( First * ( 1.0f - Factor ) ) + ( Second * Factor ) ); } template Type_ interpolate( Type_ const &First, Type_ const &Second, double const Factor ) { return static_cast( ( First * ( 1.0 - Factor ) ) + ( Second * Factor ) ); } template Type_ smoothInterpolate(Type_ const &First, Type_ const &Second, double Factor) { // Apply smoothing (ease-in-out quadratic) Factor = Factor * Factor * (3 - 2 * Factor); return static_cast((First * (1.0 - Factor)) + (Second * Factor)); } // tests whether provided points form a degenerate triangle template bool degenerate( VecType_ const &Vertex1, VecType_ const &Vertex2, VecType_ const &Vertex3 ) { // degenerate( A, B, C, minarea ) = ( ( B - A ).cross( C - A ) ).lengthSquared() < ( 4.0f * minarea * minarea ); return ( glm::length2( glm::cross( Vertex2 - Vertex1, Vertex3 - Vertex1 ) ) == 0.0 ); } // calculates bounding box for provided set of points template void bounding_box( VecType_ &Mincorner, VecType_ &Maxcorner, Iterator_ First, Iterator_ Last ) { Mincorner = VecType_( std::numeric_limits::max() ); Maxcorner = VecType_( std::numeric_limits::lowest() ); std::for_each( First, Last, [&]( typename Iterator_::value_type &point ) { Mincorner = glm::min( Mincorner, VecType_{ point } ); Maxcorner = glm::max( Maxcorner, VecType_{ point } ); } ); } // finds point on specified segment closest to specified point in 3d space. returns: point on segment as value in range 0-1 where 0 = start and 1 = end of the segment template typename VecType_::value_type nearest_segment_point( VecType_ const &Segmentstart, VecType_ const &Segmentend, VecType_ const &Point ) { auto const v = Segmentend - Segmentstart; auto const w = Point - Segmentstart; auto const c1 = glm::dot( w, v ); if( c1 <= 0.0 ) { return 0.0; } auto const c2 = glm::dot( v, v ); if( c2 <= c1 ) { return 1.0; } return c1 / c2; } glm::dvec3 LoadPoint( class cParser &Input ); // extracts a group of tokens from provided data stream std::string deserialize_random_set( cParser &Input, char const *Break = "\n\r\t ;" ); int count_trailing_zeros( uint32_t val ); // extracts a group of pairs from provided data stream // NOTE: expects no more than single pair per line template void deserialize_map( MapType_ &Map, cParser &Input ) { while( Input.ok() && !Input.eof() ) { auto const key { Input.getToken( false ) }; auto const value { Input.getToken( false, "\n" ) }; Map.emplace( key, value ); } } namespace threading { // simple POD pairing of a data item and a mutex // NOTE: doesn't do any locking itself, it's merely for cleaner argument arrangement and passing template struct lockable { Type_ data; std::mutex mutex; }; // basic wrapper simplifying use of std::condition_variable for most typical cases. // has its own mutex and secondary variable to ignore spurious wakeups class condition_variable { public: // methods void wait() { std::unique_lock lock( m_mutex ); m_condition.wait( lock, [ this ]() { return m_spurious == false; } ); } template< class Rep_, class Period_ > void wait_for( const std::chrono::duration &Time ) { std::unique_lock lock( m_mutex ); m_condition.wait_for( lock, Time, [ this ]() { return m_spurious == false; } ); } void notify_one() { spurious( false ); m_condition.notify_one(); } void notify_all() { spurious( false ); m_condition.notify_all(); } void spurious( bool const Spurious ) { std::lock_guard lock( m_mutex ); m_spurious = Spurious; } private: // members mutable std::mutex m_mutex; std::condition_variable m_condition; bool m_spurious { true }; }; } // threading //---------------------------------------------------------------------------