text: #pragma once
  
  //Defines for external libraries
  //enable glm SSE extension
  #define GLM_FORCE_INTRINSICS
  
  #define GLFW_INCLUDE_NONE
  
  #include <iostream>
  #include <memory>
  #include <filesystem>
  #include <chrono>
  
  
  //-----------------------
  //--- compiler macros ---
  //-----------------------
  
  //Debugging
  #if TR_DEBUG == 1   
  	#define LOG(msg) std::cout << msg << " (" << std::filesystem::path(__FILE__).filename().string() << ", line: " << __LINE__ << ")) " << std::endl;
  	#define STR(msg) #msg
  	#define TR_ASSERT(condition, msg) \
  	  {\
  		  if(!(condition)) \
  		  {\
          std::string error = "failed assert ("; \
  			  error.append(STR(condition)); \
          error.append(" ): "); \
  			  error.append(msg); \
  			  LOG(error); \
          __debugbreak(); \
  		  }\
      }
  #else
    #define LOG(msg)
  	#define STR(msg)
  	#define TR_ASSERT(condition, msg)
  #endif
  
  //Profiling
  #if TR_PROFILING == 1
    #define LU_PROFILE_START_SESSION(name, filePath)  ::Lucy::Profiler::get().startSession(name, filePath)
    #define LU_PROFILE_END_SESSION()									::Lucy::Profiler::get().endSession()  
    #define LU_PROFILE_SCOPE_INT_FINAL(name, line)    ::Lucy::ProfileTimer timer_##line{name}
    #define LU_PROFILE_SCOPE_INT(name, line)			  	LU_PROFILE_SCOPE_INT_FINAL(name, line)
  	#define LU_PROFILE_SCOPE(name)										LU_PROFILE_SCOPE_INT(name, __LINE__)
    #define LU_PROFILE_FUNCTION()											LU_PROFILE_SCOPE(__FUNCSIG__)
  #else
  	#define LU_PROFILE_START_SESSION(name, filePath) 
  	#define LU_PROFILE_END_SESSION()									
  	#define LU_PROFILE_SCOPE(name)										
  	#define LU_PROFILE_FUNCTION()											
  #endif
  
  //Logging
  //engine side
  #define TR_ENGINE_TRACE(...)		::Lucy::ServiceLocator::logger()->engineLogger()->trace(__VA_ARGS__)
  #define TR_ENGINE_DEBUG(...)		::Lucy::ServiceLocator::logger()->engineLogger()->debug(__VA_ARGS__)
  #define TR_ENGINE_INFO(...)		  ::Lucy::ServiceLocator::logger()->engineLogger()->info(__VA_ARGS__)
  #define TR_ENGINE_WARN(...)			::Lucy::ServiceLocator::logger()->engineLogger()->warn(__VA_ARGS__)
  #define TR_ENGINE_ERROR(...)		::Lucy::ServiceLocator::logger()->engineLogger()->error(__VA_ARGS__)
  #define TR_ENGINE_CRITICAL(...) ::Lucy::ServiceLocator::logger()->engineLogger()->critical(__VA_ARGS__)
  																															
  //client side																								
  #define TR_APP_TRACE(...)				::Lucy::ServiceLocator::logger()->clientLogger()->trace(__VA_ARGS__)
  #define TR_APP_DEBUG(...)				::Lucy::ServiceLocator::logger()->clientLogger()->debug(__VA_ARGS__)
  #define TR_APP_INFO(...)				::Lucy::ServiceLocator::logger()->clientLogger()->info(__VA_ARGS__)
  #define TR_APP_WARN(...)		   	::Lucy::ServiceLocator::logger()->clientLogger()->warn(__VA_ARGS__)
  #define TR_APP_ERROR(...)				::Lucy::ServiceLocator::logger()->clientLogger()->error(__VA_ARGS__)
  #define TR_APP_CRITICAL(...)		::Lucy::ServiceLocator::logger()->clientLogger()->critical(__VA_ARGS__)
  
  
  
  
  //Helper
  
  #define BIT(shift) (1 << shift)
  
  
  namespace Lucy {
    //----------------------------
    //--- global functionality ---
    //----------------------------
  	
    //wrapper for unique pointer generation
  	template<typename T>
  	using UnqPtr = std::unique_ptr<T>;
  	template<typename T, typename ... Args>
  	constexpr UnqPtr<T> CreateUnique(Args&& ... args)
  	{
  		return std::make_unique<T>(std::forward<Args>(args)...);
  	}
  
  	//wrapper for shared pointer generation
  	template<typename T>
  	using ShaPtr = std::shared_ptr<T>;
  	template<typename T, typename ... Args>
  	constexpr ShaPtr<T> CreateShared(Args&& ... args)
  	{
  		return std::make_shared<T>(std::forward<Args>(args)...);
  	}
  
  	//------------------------
  	//--- using directives ---
  	//------------------------
  
    using DeltaSeconds = std::chrono::duration<double, std::ratio<1, 1>>;
    using DeltaMillis = std::chrono::duration<double, std::milli>;
    using DeltaMicros = std::chrono::duration<double, std::micro>;
    using TimePointType = std::chrono::time_point<std::chrono::steady_clock>;
  }