Added some utility files
Tested to be working although INIFile is currently a windows-only utility and so is currently removed from the project (but still in the repo as it may be re-written to be cross-platform)Gui_Panel_Refactor
parent
c0c1a48e22
commit
fd424abd16
@ -0,0 +1,65 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Filename: HighResTimer.cpp
|
||||||
|
* Date: 12/06/2010
|
||||||
|
* Mod. Date: 03/21/2018
|
||||||
|
* Author: Joseph R. Pollack
|
||||||
|
* Purpose: A high resolution timer suitable for profiling code. This new
|
||||||
|
* version has stripped out the game specific functionality and
|
||||||
|
* does not include windows.h in the header.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "HighResTimer.h"
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
|
||||||
|
HighResTimer::HighResTimer()
|
||||||
|
{
|
||||||
|
Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void HighResTimer::Initialize()
|
||||||
|
{
|
||||||
|
mStartTime = 0;
|
||||||
|
LARGE_INTEGER tickFreq;
|
||||||
|
QueryPerformanceFrequency(&tickFreq);
|
||||||
|
mTickFrequency = tickFreq.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts or re-starts the timer.
|
||||||
|
void HighResTimer::Reset()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER tickStart;
|
||||||
|
QueryPerformanceCounter(&tickStart);
|
||||||
|
mStartTime = tickStart.QuadPart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the amount of time in microseconds since the last Reset() call.
|
||||||
|
int64_t HighResTimer::GetElapsedTime()
|
||||||
|
{
|
||||||
|
LARGE_INTEGER ticks;
|
||||||
|
QueryPerformanceCounter(&ticks);
|
||||||
|
int64_t elapsedMicro = ticks.QuadPart - mStartTime;
|
||||||
|
|
||||||
|
elapsedMicro *= mcMils;
|
||||||
|
elapsedMicro /= mTickFrequency;
|
||||||
|
|
||||||
|
return elapsedMicro;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double HighResTimer::GetElapsedSeconds()
|
||||||
|
{
|
||||||
|
int64_t emicro = GetElapsedTime();
|
||||||
|
double dmicro = ((double)emicro);
|
||||||
|
double dmcMils = ((double)mcMils);
|
||||||
|
double seconds = dmicro / dmcMils;
|
||||||
|
return seconds;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Filename: HighResTimer.h
|
||||||
|
* Date: 12/06/2010
|
||||||
|
* Mod. Date: 03/21/2018
|
||||||
|
* Author: Joseph R. Pollack
|
||||||
|
* Purpose: A high resolution timer suitable for profiling code. This new
|
||||||
|
* version has stripped out the game specific functionality and
|
||||||
|
* does not include windows.h in the header.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef HIGH_RES_TIMER_H_
|
||||||
|
#define HIGH_RES_TIMER_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
|
||||||
|
class HighResTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// NOTE: Currently unused
|
||||||
|
enum eUnits { SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS, PICOSECONDS };
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
HighResTimer();
|
||||||
|
|
||||||
|
void Initialize();
|
||||||
|
|
||||||
|
// Starts or re starts the timer.
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
// Returns the amount of time in microseconds since the last Reset() call.
|
||||||
|
int64_t GetElapsedTime();
|
||||||
|
|
||||||
|
// Returns the elapsed time in terms of seconds
|
||||||
|
double GetElapsedSeconds();
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int64_t mStartTime;
|
||||||
|
int64_t mTickFrequency;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const int mcMils = 1000000;
|
||||||
|
const int mcBils = 1000000000;
|
||||||
|
const long long mcTrils = 1000000000000;
|
||||||
|
|
||||||
|
/* // OLD MEMBERS
|
||||||
|
long long m_TickFreqQuadPart;
|
||||||
|
double m_StartTime;
|
||||||
|
*/
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif // HIGH_RES_TIMER_H_
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - INIFile.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2017/11/28 (y/m/d)
|
||||||
|
* Mod Date - 2017/11/28 (y/m/d)
|
||||||
|
* Description - Read/Write from a .ini file
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "INIFile.h"
|
||||||
|
|
||||||
|
// TODO: This needs to be re-written without the windows-specific functions
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
INIFile::INIFile(const char * filename)
|
||||||
|
{
|
||||||
|
mFullPath = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
INIFile::~INIFile()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string INIFile::Read(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
char buffer[256];
|
||||||
|
GetPrivateProfileStringA(section, key, nullptr, buffer, 256, mFullPath.c_str());
|
||||||
|
return std::string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int INIFile::ReadInt(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
int val = GetPrivateProfileIntA(section, key, -1, mFullPath.c_str());
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INIFile::ReadBool(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
std::string buffer = Read(section, key);
|
||||||
|
|
||||||
|
if (buffer.size() < 1)
|
||||||
|
throw std::runtime_error("ReadBool() Failed: buffer was empty!");
|
||||||
|
|
||||||
|
std::transform(buffer.begin(), buffer.end(), buffer.begin(), ::tolower);
|
||||||
|
|
||||||
|
if (buffer == std::string("false"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (buffer == std::string("true"))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
throw std::runtime_error("ReadBool() Failed: buffer not a boolean value!");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
double INIFile::ReadDouble(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
throw "Not implemented!";
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::Write(const char * section, const char * key, const char * value)
|
||||||
|
{
|
||||||
|
WritePrivateProfileStringA(section, key, value, mFullPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::WriteInt(const char * section, const char * key, int value)
|
||||||
|
{
|
||||||
|
std::string strVal = std::to_string(value);
|
||||||
|
WritePrivateProfileStringA(section, key, strVal.c_str(), mFullPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::WriteBool(const char * section, const char * key, bool value)
|
||||||
|
{
|
||||||
|
std::string strVal = "true";
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
strVal = "false";
|
||||||
|
}
|
||||||
|
|
||||||
|
WritePrivateProfileStringA(section, key, strVal.c_str(), mFullPath.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::WriteDouble(const char * section, const char * key, double value)
|
||||||
|
{
|
||||||
|
throw "INIFile::WriteDouble Not implemented!";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool INIFile::KeyExists(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
return Read(section, key).length() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::DeleteKey(const char* section, const char* key)
|
||||||
|
{
|
||||||
|
Write(section, key, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void INIFile::DeleteSection(const char * section)
|
||||||
|
{
|
||||||
|
Write(section, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - INIFile.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2017/11/28 (y/m/d)
|
||||||
|
* Mod Date - 2017/11/28 (y/m/d)
|
||||||
|
* Description - Read/Write from a .ini file
|
||||||
|
* Based on the C# class writen by Danny Beckett and released
|
||||||
|
* to public domain:
|
||||||
|
* https://stackoverflow.com/questions/217902/reading-writing-an-ini-file
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _INI_FILE_H_
|
||||||
|
#define _INI_FILE_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
class INIFile
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// filename must be a full, absolute path to the .ini file.
|
||||||
|
INIFile(const char* filename);
|
||||||
|
~INIFile();
|
||||||
|
|
||||||
|
// Read methods
|
||||||
|
std::string Read(const char* section, const char* key);
|
||||||
|
int ReadInt(const char* section, const char* key);
|
||||||
|
bool ReadBool(const char* section, const char* key);
|
||||||
|
double ReadDouble(const char* section, const char* key);
|
||||||
|
|
||||||
|
// Write methods
|
||||||
|
void Write(const char * section, const char* key, const char* value);
|
||||||
|
void WriteInt(const char * section, const char* key, int value);
|
||||||
|
void WriteBool(const char * section, const char* key, bool value);
|
||||||
|
void WriteDouble(const char * section, const char* key, double value);
|
||||||
|
|
||||||
|
|
||||||
|
// Management
|
||||||
|
bool KeyExists(const char* section, const char* key);
|
||||||
|
|
||||||
|
void DeleteKey(const char* section, const char* key);
|
||||||
|
void DeleteSection(const char* section);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mbFileOpen;
|
||||||
|
|
||||||
|
std::string mFullPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // _INI_FILE_H_
|
||||||
@ -0,0 +1,414 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - Logger.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2019/06/24 (y/m/d)
|
||||||
|
* Mod Date - 2019/06/26 (y/m/d)
|
||||||
|
* Description - Main interface to the logging system. Manages a linked
|
||||||
|
* list of built-in and user-defined listerers.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
//namespace LogLevel
|
||||||
|
//{
|
||||||
|
// bool LevelIsSet(uint16_t buf, uint16_t mask)
|
||||||
|
// {
|
||||||
|
// return buf & mask;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// std::string FormatLevel(uint16_t level)
|
||||||
|
// {
|
||||||
|
// if (LevelIsSet(level, FATAL_ERROR))
|
||||||
|
// {
|
||||||
|
// return "[FATAL ERROR] ";
|
||||||
|
// }
|
||||||
|
// else if (LevelIsSet(level, ERROR))
|
||||||
|
// {
|
||||||
|
// return "[ERROR] ";
|
||||||
|
// }
|
||||||
|
// else if (LevelIsSet(level, WARNING))
|
||||||
|
// {
|
||||||
|
// return "[WARNING] ";
|
||||||
|
// }
|
||||||
|
// else if (LevelIsSet(level, INFO))
|
||||||
|
// {
|
||||||
|
// return "[INFO] ";
|
||||||
|
// }
|
||||||
|
// else if (LevelIsSet(level, INFO_VERBOSE))
|
||||||
|
// {
|
||||||
|
// return "[INFO_VERBOSE] ";
|
||||||
|
// }
|
||||||
|
// else if (LevelIsSet(level, OGL_DEBUG))
|
||||||
|
// {
|
||||||
|
// return "[OGL_DEBUG] ";
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return "[UNKNOWN] ";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//namespace LogCategory
|
||||||
|
//{
|
||||||
|
// bool CategoryIsSet(uint16_t buf, uint16_t mask)
|
||||||
|
// {
|
||||||
|
// return buf & mask;
|
||||||
|
// }
|
||||||
|
// std::string FormatCategory(uint16_t level)
|
||||||
|
// {
|
||||||
|
// if (CategoryIsSet(level, CORE))
|
||||||
|
// {
|
||||||
|
// return "[CORE] ";
|
||||||
|
// }
|
||||||
|
// else if (CategoryIsSet(level, WINDOW_CONTROLLER))
|
||||||
|
// {
|
||||||
|
// return "[WINDOW CONTROLLER] ";
|
||||||
|
// }
|
||||||
|
// else if (CategoryIsSet(level, GRAPHICS))
|
||||||
|
// {
|
||||||
|
// return "[GRAPHICS] ";
|
||||||
|
// }
|
||||||
|
// else if (CategoryIsSet(level, UTILITIES))
|
||||||
|
// {
|
||||||
|
// return "[UTILITIES] ";
|
||||||
|
// }
|
||||||
|
// else if (CategoryIsSet(level, USER_PROJECT))
|
||||||
|
// {
|
||||||
|
// return "[USER PROJECT] ";
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// return "[UNKNOWN] ";
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
LogListener::LogListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||||
|
: mAcceptedLogLevels(acceptedLogLevels), mAcceptedLogCategories(acceptedLogCategories), mMyName(myName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string & LogListener::GetName() const
|
||||||
|
{
|
||||||
|
return mMyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LogListener::CategoryIsSet(uint32_t id) const
|
||||||
|
{
|
||||||
|
return mAcceptedLogCategories & id;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LogListener::LevelIsSet(uint32_t id) const
|
||||||
|
{
|
||||||
|
return mAcceptedLogLevels & id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// Standard Listener
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
StandardListener::StandardListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||||
|
: LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StandardListener::Log(LogMessage& message)
|
||||||
|
{
|
||||||
|
if (!LevelIsSet(message.LogLevel) ||
|
||||||
|
!CategoryIsSet(message.LogCategory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::cout << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||||
|
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// Error Listener
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
ErrorListener::ErrorListener(uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||||
|
: LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ErrorListener::Log(LogMessage& message)
|
||||||
|
{
|
||||||
|
if (!LevelIsSet(message.LogLevel) ||
|
||||||
|
!CategoryIsSet(message.LogCategory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::cerr << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||||
|
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// File Listener
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
FileListener::FileListener(std::ofstream & of, uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
|
||||||
|
: mOF(of), LogListener(acceptedLogLevels, acceptedLogCategories, myName)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileListener::Log(LogMessage& message)
|
||||||
|
{
|
||||||
|
if (!LevelIsSet(message.LogLevel) ||
|
||||||
|
!CategoryIsSet(message.LogCategory))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
mOF << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
|
||||||
|
<< Logger::GetLevelName(message.LogLevel) << message.Message;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// Main Logger
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Logger* Logger::mInstance = nullptr;
|
||||||
|
uint32_t Logger::mNextCategoryID = 0x01;
|
||||||
|
uint32_t Logger::mNextLevelID = 0x01;
|
||||||
|
std::map<uint32_t, std::string> Logger::mCategoryNames;
|
||||||
|
std::map<uint32_t, std::string> Logger::mLevelNames;
|
||||||
|
|
||||||
|
std::string Logger::TimeStamp()
|
||||||
|
{
|
||||||
|
time_t t = time(0);
|
||||||
|
|
||||||
|
struct tm now;
|
||||||
|
localtime_s(&now, &t);
|
||||||
|
|
||||||
|
std::ostringstream oss("");
|
||||||
|
oss << "[" << (now.tm_year + 1900) << "/";
|
||||||
|
oss << std::setfill('0') << std::setw(2);
|
||||||
|
oss << (now.tm_mon + 1) << "/"
|
||||||
|
<< std::setw(2) << now.tm_mday << " -- "
|
||||||
|
<< std::setw(2) << now.tm_hour << ":"
|
||||||
|
<< std::setw(2) << now.tm_min << ":"
|
||||||
|
<< std::setw(2) << now.tm_sec << "] ";
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger::Logger()
|
||||||
|
{
|
||||||
|
|
||||||
|
// Register built-in levels
|
||||||
|
RegisterLevel("INFO");
|
||||||
|
RegisterLevel("WARNING");
|
||||||
|
RegisterLevel("ERROR");
|
||||||
|
RegisterLevel("FATAL_ERROR");
|
||||||
|
RegisterLevel("INFO_VERBOSE");
|
||||||
|
RegisterLevel("OGL_DEBUG");
|
||||||
|
|
||||||
|
RegisterCategory("CORE");
|
||||||
|
RegisterCategory("WINDOW_CONTROLLER");
|
||||||
|
RegisterCategory("GRAPHICS");
|
||||||
|
RegisterCategory("UTILITIES");
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger * Logger::GetInstance()
|
||||||
|
{
|
||||||
|
if (!Logger::mInstance)
|
||||||
|
{
|
||||||
|
Logger::mInstance = new Logger;
|
||||||
|
Logger::mInstance->mTimer.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Logger::mInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::FreeInstance()
|
||||||
|
{
|
||||||
|
delete mInstance;
|
||||||
|
mInstance = nullptr;
|
||||||
|
|
||||||
|
Logger::mNextCategoryID = 0x01;
|
||||||
|
Logger::mNextLevelID = 0x01;
|
||||||
|
|
||||||
|
Logger::mCategoryNames.clear();
|
||||||
|
Logger::mLevelNames.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Logger::RegisterCategory(const char * name)
|
||||||
|
{
|
||||||
|
Logger::mCategoryNames[mNextCategoryID] = name;
|
||||||
|
uint32_t id = mNextCategoryID;
|
||||||
|
mNextCategoryID = mNextCategoryID << 1;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Logger::RegisterLevel(const char * name)
|
||||||
|
{
|
||||||
|
Logger::mLevelNames[mNextLevelID] = name;
|
||||||
|
uint32_t id = mNextLevelID;
|
||||||
|
mNextLevelID = mNextLevelID << 1;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Logger::GetCategoryName(uint32_t id)
|
||||||
|
{
|
||||||
|
if (Logger::mCategoryNames.find(id) == Logger::mCategoryNames.end())
|
||||||
|
return "[]";
|
||||||
|
|
||||||
|
std::string name = "[";
|
||||||
|
name += Logger::mCategoryNames[id];
|
||||||
|
name += "] ";
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Logger::GetLevelName(uint32_t id)
|
||||||
|
{
|
||||||
|
if (Logger::mLevelNames.find(id) == Logger::mLevelNames.end())
|
||||||
|
return "[]";
|
||||||
|
|
||||||
|
std::string name = "[";
|
||||||
|
name += Logger::mLevelNames[id];
|
||||||
|
name += "] ";
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogListener* Logger::AddListener(LogListener * pl)
|
||||||
|
{
|
||||||
|
mListeners.push_back(pl);
|
||||||
|
return pl;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogListener* Logger::RemoveListener(LogListener * pl)
|
||||||
|
{
|
||||||
|
mListeners.remove(pl);
|
||||||
|
return pl;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogListener* Logger::RemoveListener(const char * withName)
|
||||||
|
{
|
||||||
|
LogListener* pl = nullptr;
|
||||||
|
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||||
|
{
|
||||||
|
if ((*iter)->GetName() == withName)
|
||||||
|
{
|
||||||
|
pl = (*iter);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mListeners.remove(pl);
|
||||||
|
return pl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::FreeAllListeners()
|
||||||
|
{
|
||||||
|
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||||
|
{
|
||||||
|
delete (*iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
mListeners.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::ClearBacklog()
|
||||||
|
{
|
||||||
|
mBacklog.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Logger::Log(uint32_t logCategory, uint32_t logLevel, const char * message, ...)
|
||||||
|
{
|
||||||
|
// clear the buffer
|
||||||
|
memset(mBuffer, 0, 1024);
|
||||||
|
|
||||||
|
// Fill the buffer with the formatted message
|
||||||
|
va_list args;
|
||||||
|
va_start(args, message);
|
||||||
|
vsprintf_s(mBuffer, BUFFER_SIZE, message, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
double timeStamp = mTimer.GetElapsedSeconds();
|
||||||
|
|
||||||
|
LogMessage lm;
|
||||||
|
lm.LogCategory = logCategory;
|
||||||
|
lm.LogLevel = logLevel;
|
||||||
|
lm.Message = mBuffer;
|
||||||
|
lm.Repeats = 0;
|
||||||
|
lm.RepeatAlertSent = false;
|
||||||
|
lm.SentTimeStamp = timeStamp;
|
||||||
|
|
||||||
|
bool send = true;
|
||||||
|
bool track = true;
|
||||||
|
|
||||||
|
// Check for repeats
|
||||||
|
for (int i = 0; i < mBacklog.size(); i++)
|
||||||
|
{
|
||||||
|
LogMessage& prevMsg = mBacklog[i];
|
||||||
|
if (prevMsg.Message == lm.Message)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (prevMsg.RepeatAlertSent)
|
||||||
|
{
|
||||||
|
send = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only suppress the messsage if it has been less than
|
||||||
|
// 1 second since it was last sent
|
||||||
|
double timeSinceLastSend = timeStamp - prevMsg.SentTimeStamp;
|
||||||
|
if (timeSinceLastSend <= 1.0)
|
||||||
|
{
|
||||||
|
prevMsg.Repeats += 1;
|
||||||
|
|
||||||
|
if (prevMsg.Repeats > 100 && !prevMsg.RepeatAlertSent)
|
||||||
|
{
|
||||||
|
lm.Message = lm.Message + " [This message has rapidly repeated over 100 times! No more repeats will be sent out!]";
|
||||||
|
prevMsg.RepeatAlertSent = true;
|
||||||
|
track = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
send = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevMsg.SentTimeStamp = timeStamp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!send)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Send to all listeners
|
||||||
|
for (auto iter = mListeners.begin(); iter != mListeners.end(); iter++)
|
||||||
|
{
|
||||||
|
if ((*iter)->Log(lm))
|
||||||
|
{
|
||||||
|
// Track which listeners handle the message
|
||||||
|
lm.HandledBy.push_back((*iter)->GetName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track)
|
||||||
|
mBacklog.push_back(lm);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<LogMessage>& Logger::GetBacklog() const
|
||||||
|
{
|
||||||
|
return mBacklog;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,182 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* File - Logger.h
|
||||||
|
* Author - Joey Pollack
|
||||||
|
* Date - 2019/06/24 (y/m/d)
|
||||||
|
* Mod Date - 2019/06/26 (y/m/d)
|
||||||
|
* Description - Main interface to the logging system. Manages a linked
|
||||||
|
* list of built-in and user-defined listerers.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LOGGER_H_
|
||||||
|
#define LOGGER_H_
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
// TODO: Remove the dependence on HighResTimer.h
|
||||||
|
// OR re-write HighResTimer with modern timer code
|
||||||
|
#include "HighResTimer.h"
|
||||||
|
|
||||||
|
// Conflict with a region flag in wingdi.h
|
||||||
|
#undef ERROR
|
||||||
|
|
||||||
|
namespace Lunarium
|
||||||
|
{
|
||||||
|
namespace LogLevel
|
||||||
|
{
|
||||||
|
const uint16_t ANY = 0xFFFF;
|
||||||
|
const uint16_t INFO = 0x0001;
|
||||||
|
const uint16_t WARNING = 0x0002;
|
||||||
|
const uint16_t ERROR = 0x0004;
|
||||||
|
const uint16_t FATAL_ERROR = 0x0008;
|
||||||
|
const uint16_t INFO_VERBOSE = 0x0010;
|
||||||
|
const uint16_t OGL_DEBUG = 0x0020;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace LogCategory
|
||||||
|
{
|
||||||
|
const uint16_t ANY = 0xFFFF;
|
||||||
|
const uint16_t CORE = 0x0001;
|
||||||
|
const uint16_t WINDOW_CONTROLLER = 0x0002;
|
||||||
|
const uint16_t GRAPHICS = 0x0004;
|
||||||
|
const uint16_t UTILITIES = 0x0008;
|
||||||
|
//const uint16_t USER_PROJECT = 0x0010;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LogMessage
|
||||||
|
{
|
||||||
|
// The ID of the category
|
||||||
|
uint32_t LogCategory;
|
||||||
|
|
||||||
|
// The ID of the Level
|
||||||
|
uint32_t LogLevel;
|
||||||
|
|
||||||
|
std::string Message;
|
||||||
|
std::vector<std::string> HandledBy;
|
||||||
|
uint32_t Repeats;
|
||||||
|
bool RepeatAlertSent;
|
||||||
|
double SentTimeStamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// LISTENER CLASSES
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Log Listener interface class
|
||||||
|
class LogListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LogListener(uint32_t acceptedLogLevels = LogLevel::ANY, uint32_t acceptedLogCategories = LogLevel::ANY, const char* myName = "UNKNOWN");
|
||||||
|
virtual bool Log(LogMessage& message) = 0;
|
||||||
|
|
||||||
|
const std::string& GetName() const;
|
||||||
|
|
||||||
|
bool CategoryIsSet(uint32_t id) const;
|
||||||
|
bool LevelIsSet(uint32_t id) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint32_t mAcceptedLogCategories;
|
||||||
|
uint32_t mAcceptedLogLevels;
|
||||||
|
std::string mMyName;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Outputs all (by default) messages to std::cout
|
||||||
|
// Adds a time stamp and the log level to the message.
|
||||||
|
class StandardListener : public LogListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StandardListener(uint32_t acceptedLogLevels = LogLevel::ANY,
|
||||||
|
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "StandardListener");
|
||||||
|
bool Log(LogMessage& message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Outputs Errors and Fatal Errors to std::err
|
||||||
|
// Adds a time stamp and the log level to the message.
|
||||||
|
class ErrorListener : public LogListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ErrorListener(uint32_t acceptedLogLevels = LogLevel::ERROR | LogLevel::FATAL_ERROR,
|
||||||
|
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "ErrorListener");
|
||||||
|
bool Log(LogMessage& message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Outputs all (by default) messages to the given std::ofstream.
|
||||||
|
// Adds a time stamp and the log level to the message.
|
||||||
|
class FileListener : public LogListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FileListener(std::ofstream& of, uint32_t acceptedLogLevels = LogLevel::ANY,
|
||||||
|
uint32_t acceptedLogCategories = LogCategory::ANY, const char* myName = "FileListener");
|
||||||
|
bool Log(LogMessage& message);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::ofstream& mOF;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
// ========================================================================
|
||||||
|
// MAIN LOGGERCLASS
|
||||||
|
// ========================================================================
|
||||||
|
// ////////////////////////////////////////////////////////////////////////
|
||||||
|
class Logger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static std::string TimeStamp();
|
||||||
|
static Logger* GetInstance();
|
||||||
|
static void FreeInstance();
|
||||||
|
|
||||||
|
static uint32_t RegisterCategory(const char* name);
|
||||||
|
static uint32_t RegisterLevel(const char* name);
|
||||||
|
static std::string GetCategoryName(uint32_t id);
|
||||||
|
static std::string GetLevelName(uint32_t id);
|
||||||
|
LogListener* AddListener(LogListener* pl);
|
||||||
|
|
||||||
|
// This method does NOT delete the listener's memory!
|
||||||
|
LogListener* RemoveListener(LogListener* pl);
|
||||||
|
|
||||||
|
// This method does NOT delete the listener's memory!
|
||||||
|
LogListener* RemoveListener(const char* withName);
|
||||||
|
|
||||||
|
// Calls delete on all listeners and clears the list
|
||||||
|
void FreeAllListeners();
|
||||||
|
|
||||||
|
void ClearBacklog();
|
||||||
|
|
||||||
|
// The message argument and the variable argument list work just like
|
||||||
|
// printf. Use the same formatters as printf when calling this function.
|
||||||
|
// Messages must be shorter than 1024 bytes.
|
||||||
|
void Log(uint32_t logCategory, uint32_t logLevel, const char* message, ...);
|
||||||
|
|
||||||
|
const std::vector<LogMessage>& GetBacklog() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Logger* mInstance;
|
||||||
|
static uint32_t mNextCategoryID;
|
||||||
|
static uint32_t mNextLevelID;
|
||||||
|
static std::map<uint32_t, std::string> mLevelNames;
|
||||||
|
static std::map<uint32_t, std::string> mCategoryNames;
|
||||||
|
std::list<LogListener*> mListeners;
|
||||||
|
std::vector<LogMessage> mBacklog;
|
||||||
|
char mBuffer[BUFFER_SIZE];
|
||||||
|
HighResTimer mTimer;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Logger();
|
||||||
|
Logger(const Logger&) = delete;
|
||||||
|
const Logger& operator=(const Logger&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LOGGER_H_
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
[section]
|
||||||
|
var=42
|
||||||
Loading…
Reference in New Issue