diff --git a/MAGE/MAGE.vcxproj b/MAGE/MAGE.vcxproj
index 50c385169..fd2c99d7d 100644
--- a/MAGE/MAGE.vcxproj
+++ b/MAGE/MAGE.vcxproj
@@ -26,11 +26,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -52,9 +52,9 @@
-
-
-
+
+
+
diff --git a/MAGE/MAGE.vcxproj.filters b/MAGE/MAGE.vcxproj.filters
index 5da556bc5..93501d4ba 100644
--- a/MAGE/MAGE.vcxproj.filters
+++ b/MAGE/MAGE.vcxproj.filters
@@ -49,12 +49,6 @@
{23b667d5-379d-444b-8454-b21d92f99a67}
-
- {c7374162-a25a-4c28-8475-0b93646cf99c}
-
-
- {dbb452e9-4d9e-4ce3-9101-98b8782a0759}
-
{8463f1af-bd9e-4155-89f6-bb804a124c73}
@@ -73,6 +67,12 @@
{69b1cee0-5512-4d9b-ab9a-f0dbb346243b}
+
+ {dbb452e9-4d9e-4ce3-9101-98b8782a0759}
+
+
+ {c7374162-a25a-4c28-8475-0b93646cf99c}
+
@@ -87,21 +87,6 @@
Header Files\core
-
- Header Files\log
-
-
- Header Files\log
-
-
- Header Files\log
-
-
- Header Files\log
-
-
- Header Files\log
-
Header Files\math
@@ -162,20 +147,26 @@
Header Files\scripting
+
+ Header Files\logging
+
+
+ Header Files\logging
+
+
+ Header Files\logging
+
+
+ Header Files\logging
+
+
+ Header Files\logging
+
Source Files\core
-
- Source Files\log
-
-
- Source Files\log
-
-
- Source Files\log
-
Source Files\parallel
@@ -194,5 +185,14 @@
Source Files\scripting
+
+ Source Files\logging
+
+
+ Source Files\logging
+
+
+ Source Files\logging
+
\ No newline at end of file
diff --git a/MAGE/MAGE/src/core/engine.hpp b/MAGE/MAGE/src/core/engine.hpp
index 175ba7fb0..7d39ac1be 100644
--- a/MAGE/MAGE/src/core/engine.hpp
+++ b/MAGE/MAGE/src/core/engine.hpp
@@ -101,7 +101,7 @@ namespace mage {
#include "collection\collection.hpp"
#include "math\math.hpp"
#include "parallel\parallel.hpp"
-#include "log\log.hpp"
+#include "logging\logging.hpp"
#include "memory\memory.hpp"
#include "resource\resource.hpp"
#include "state\state.hpp"
diff --git a/MAGE/MAGE/src/logging/debug.hpp b/MAGE/MAGE/src/logging/debug.hpp
new file mode 100644
index 000000000..177544881
--- /dev/null
+++ b/MAGE/MAGE/src/logging/debug.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+//-----------------------------------------------------------------------------
+// System Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Defines
+//-----------------------------------------------------------------------------
+#pragma region
+
+#ifdef NDEBUG
+#define Assert(expr) (__noop)
+#else
+#define Assert(expr) ((expr) ? __noop : Severe("Assertion \"%s\" failed in %s, line %d", \
+ #expr, __FILE__, __LINE__))
+#endif
+
+#pragma endregion
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/error.cpp b/MAGE/MAGE/src/logging/error.cpp
new file mode 100644
index 000000000..2d52fa331
--- /dev/null
+++ b/MAGE/MAGE/src/logging/error.cpp
@@ -0,0 +1,148 @@
+//-----------------------------------------------------------------------------
+// System Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include "engine.hpp"
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Declarations and Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ /**
+ Finds the end of a word.
+
+ @param[in] buffer
+ Pointer to the first character.
+ @return Pointer to the end of the word.
+ This means the pointer points to a space
+ or null-terminating character.
+ */
+ const char *FindWordEnd(const char *buffer) {
+ while (*buffer != '\0' && !isspace(*buffer)) {
+ ++buffer;
+ }
+ return buffer;
+ }
+
+ /**
+ Process the given error.
+
+ @param[in] format
+ The format of the error string.
+ @param[in] args
+ The arguments of the format string.
+ @param[in] error_type
+ The type of the error.
+ @param[in] error_disposition
+ Disposition of the error.
+ */
+ void ProcessError(const char *format, const va_list args,
+ const string &error_type, int error_disposition) {
+
+ if (error_disposition == MAGE_ERROR_IGNORE) {
+ // MAGE_ERROR_IGNORE
+ return;
+ }
+
+ // MAGE_ERROR_CONTINUE and MAGE_ERROR_ABORT
+ // Print formatted error message
+ const int width = max(20, TerminalWidth() - 2);
+ string error_string = error_type + ": ";
+ size_t error_pos = error_string.size();
+
+ char error_buffer[2048];
+ // Write formatted output using a pointer to a list of arguments.
+ vsnprintf_s(error_buffer, sizeof(error_buffer), _TRUNCATE, format, args);
+
+ const char *msg_pos = error_buffer;
+ while (true) {
+ while (*msg_pos != '\0' && isspace(*msg_pos)) {
+ ++msg_pos;
+ }
+ if (*msg_pos == '\0') {
+ break;
+ }
+
+ // isspace(*msg_pos) == true
+
+ const char *word_end = FindWordEnd(msg_pos);
+ if (error_pos + word_end - msg_pos > width) {
+ error_string += "\n ";
+ error_pos = 4;
+ }
+ while (msg_pos != word_end) {
+ error_string += *msg_pos;
+ ++msg_pos;
+ ++error_pos;
+ }
+ error_string += ' ';
+ ++error_pos;
+ }
+
+ // Writes the error_string pointed by format to stderr.
+ fprintf(stderr, "%s\n", error_string.c_str());
+
+ if (error_disposition == MAGE_ERROR_ABORT) {
+ // MAGE_ERROR_ABORT
+ __debugbreak();
+ }
+ }
+
+ void Info(const char *format, ...) {
+ if (!general_configuration.IsVerbose() || general_configuration.IsQuiet()) {
+ // Do not process info in non-verbose mode.
+ // Do not process info in quiet mode.
+ return;
+ }
+ va_list args;
+ // Retrieve the additional arguments after format
+ va_start(args, format);
+ ProcessError(format, args, "Notice", MAGE_ERROR_CONTINUE);
+ // End using variable argument list
+ va_end(args);
+ }
+
+ void Warning(const char *format, ...) {
+ if (general_configuration.IsQuiet()) {
+ // Do not process warning in quiet mode.
+ return;
+ }
+ va_list args;
+ // Retrieve the additional arguments after format
+ va_start(args, format);
+ ProcessError(format, args, "Warning", MAGE_ERROR_CONTINUE);
+ // End using variable argument list
+ va_end(args);
+ }
+
+ void Error(const char *format, ...) {
+ va_list args;
+ // Retrieve the additional arguments after format
+ va_start(args, format);
+ ProcessError(format, args, "Error", MAGE_ERROR_CONTINUE);
+ // End using variable argument list
+ va_end(args);
+ }
+
+ void Severe(const char *format, ...) {
+ va_list args;
+ // Retrieve the additional arguments after format
+ va_start(args, format);
+ ProcessError(format, args, "Fatal Error", MAGE_ERROR_ABORT);
+ // End using variable argument list
+ va_end(args);
+ }
+}
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/error.hpp b/MAGE/MAGE/src/logging/error.hpp
new file mode 100644
index 000000000..03537e65a
--- /dev/null
+++ b/MAGE/MAGE/src/logging/error.hpp
@@ -0,0 +1,50 @@
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Engine Defines
+//-----------------------------------------------------------------------------
+#pragma region
+
+#define MAGE_ERROR_IGNORE 0
+#define MAGE_ERROR_CONTINUE 1
+#define MAGE_ERROR_ABORT 2
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Declarations and Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ /**
+ Notifies an info message.
+
+ @param[in] format
+ Pointer to the message format.
+ */
+ void Info(const char *format, ...);
+
+ /**
+ Notifies a warning message.
+
+ @param[in] format
+ Pointer to the message format.
+ */
+ void Warning(const char *format, ...);
+
+ /**
+ Notifies an error message.
+
+ @param[in] format
+ Pointer to the message format.
+ */
+ void Error(const char *format, ...);
+
+ /**
+ Notifies a severe message.
+
+ @param[in] format
+ Pointer to the message format.
+ */
+ void Severe(const char *format, ...);
+}
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/logging.hpp b/MAGE/MAGE/src/logging/logging.hpp
new file mode 100644
index 000000000..af18e9ae3
--- /dev/null
+++ b/MAGE/MAGE/src/logging/logging.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Engine Declarations and Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ /**
+ Returns the fixed terminal width.
+
+ @return The fixed terminal width.
+ */
+ inline int TerminalWidth() {
+ // Retrieve a handle to the standard output device.
+ const HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (h == INVALID_HANDLE_VALUE || h == NULL) {
+ // Print error message if the handle is invalid.
+ fprintf(stderr, "GetStdHandle() call failed");
+ return 80;
+ }
+ // Structure containing information about a console screen buffer.
+ CONSOLE_SCREEN_BUFFER_INFO buffer_info = { 0 };
+ GetConsoleScreenBufferInfo(h, &buffer_info);
+ // dwSize: a COORD structure that contains the size of the console
+ // screen buffer in character columns and rows.
+ return buffer_info.dwSize.X;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Engine Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include "logging\timer.hpp"
+#include "logging\progressreporter.hpp"
+#include "logging\error.hpp"
+#include "logging\debug.hpp"
+
+#pragma endregion
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/progressreporter.cpp b/MAGE/MAGE/src/logging/progressreporter.cpp
new file mode 100644
index 000000000..dff0b7381
--- /dev/null
+++ b/MAGE/MAGE/src/logging/progressreporter.cpp
@@ -0,0 +1,141 @@
+//-----------------------------------------------------------------------------
+// Engine Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include "engine.hpp"
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ ProgressReporter::ProgressReporter(uint32_t nb_work, const string &title, uint32_t bar_length)
+ : m_nb_work_total(nb_work), m_nb_work_done(0), m_nb_plusses_printed(0) {
+
+ if (bar_length == 0) {
+ bar_length = TerminalWidth() - 28;
+ }
+
+ m_mutex = Mutex::Create();
+
+ m_nb_plusses_total = max(2, bar_length - (uint32_t)title.size());
+
+ m_timer = new Timer();
+ m_timer->Start();
+
+ m_fout = stdout;
+
+ // Initialize progress string
+ const size_t buffer_length = title.size() + m_nb_plusses_total + 64;
+ m_buffer = new char[buffer_length];
+ // Composes a string with the same text that would be printed
+ // if format was used on printf, but instead of being printed,
+ // the content is stored in the buffer.
+ snprintf(m_buffer, buffer_length, "\r%s: [", title.c_str());
+
+ // A C string is as long as the number of characters between
+ // the beginning of the string and the terminating null character
+ // (without including the terminating null character itself).
+ m_current_pos = m_buffer + strlen(m_buffer);
+ char *s = m_current_pos;
+ for (uint32_t i = 0; i < m_nb_plusses_total; ++i) {
+ *s++ = ' ';
+ }
+ *s++ = ']';
+ *s++ = ' ';
+ *s++ = '\0';
+
+ if (general_configuration.IsQuiet()) {
+ // Do not output the progression in quiet mode.
+ return;
+ }
+
+ // Write the buffer to the output file stream.
+ fputs(m_buffer, m_fout);
+
+ // If the given stream was open for writing
+ // (or if it was open for updating and the last
+ // i/o operation was an output operation)
+ // any unwritten data in its output buffer is written
+ // to the output file stream.
+ fflush(m_fout);
+ }
+
+ ProgressReporter::~ProgressReporter() {
+ delete[] m_buffer;
+ delete m_timer;
+ Mutex::Destroy(m_mutex);
+ }
+
+ void ProgressReporter::Update(uint32_t nb_work) {
+ if (nb_work == 0 || general_configuration.IsQuiet()) {
+ // Do not output the progression in quiet mode.
+ return;
+ }
+
+ MutexLock lock(*m_mutex);
+
+ m_nb_work_done += nb_work;
+ const float percent_done = float(m_nb_work_done) / float(m_nb_work_total);
+ uint32_t plusses_needed = (uint32_t)round(percent_done * m_nb_plusses_total);
+ if (plusses_needed > m_nb_plusses_total) {
+ plusses_needed = m_nb_plusses_total;
+ }
+ while (m_nb_plusses_printed < plusses_needed) {
+ *m_current_pos++ = '+';
+ ++m_nb_plusses_printed;
+ }
+
+ // Write the buffer to the output file stream.
+ fputs(m_buffer, m_fout);
+ // Update elapsed time and estimated time to completion
+ const float seconds = (float)m_timer->Time();
+ const float estimation_remaining = seconds / percent_done - seconds;
+ if (percent_done == 1.0f) {
+ // Writes the string format to the output file stream.
+ fprintf(m_fout, " (%.1fs) ", seconds);
+ }
+ else {
+ // Writes the string format to the output file stream.
+ fprintf(m_fout, " (%.1fs|%.1fs) ", seconds, max(0.0f, estimation_remaining));
+ }
+
+ // If the given stream was open for writing
+ // (or if it was open for updating and the last
+ // i/o operation was an output operation)
+ // any unwritten data in its output buffer is written
+ // to the output file stream.
+ fflush(m_fout);
+ }
+
+ void ProgressReporter::Done() {
+ if (general_configuration.IsQuiet()) {
+ // Do not output the progression in quiet mode.
+ return;
+ }
+
+ MutexLock lock(*m_mutex);
+
+ while (m_nb_plusses_printed < m_nb_plusses_total) {
+ *m_current_pos++ = '+';
+ ++m_nb_plusses_printed;
+ }
+
+ // Write the buffer to the output file stream.
+ fputs(m_buffer, m_fout);
+ // Update elapsed time
+ const float seconds = (float)m_timer->Time();
+ // Writes the string format to the output file stream.
+ fprintf(m_fout, " (%.1fs) \n", seconds);
+
+ // If the given stream was open for writing
+ // (or if it was open for updating and the last
+ // i/o operation was an output operation)
+ // any unwritten data in its output buffer is written
+ // to the output file stream.
+ fflush(m_fout);
+ }
+}
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/progressreporter.hpp b/MAGE/MAGE/src/logging/progressreporter.hpp
new file mode 100644
index 000000000..39d067da6
--- /dev/null
+++ b/MAGE/MAGE/src/logging/progressreporter.hpp
@@ -0,0 +1,94 @@
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Engine Declarations and Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ /**
+ A class of progress reporters.
+ */
+ class ProgressReporter {
+
+ public:
+
+ /**
+ Constructs a progress reporter.
+
+ @param[in] nb_work
+ The number of parts of the total work.
+ @param[in] title
+ A reference to the title.
+ @param[in] bar_length
+ The length of the progress bar.
+ If 0 the default length will be chosen.
+ */
+ ProgressReporter(uint32_t nb_work, const string &title, uint32_t bar_length = 0);
+
+ /**
+ Destructs this progress reporter.
+ */
+ virtual ~ProgressReporter();
+
+ /**
+ Updates this progress reporter.
+
+ @param[in] nb_work
+ The number of parts of the total work
+ that are done.
+ */
+ void Update(uint32_t nb_work = 1);
+
+ /**
+ Finishes this progress reporter.
+ */
+ void Done();
+
+ private:
+
+ /**
+ The number of parts of the total work.
+ */
+ const uint32_t m_nb_work_total;
+
+ /**
+ The number of parts of the total work that are already done.
+ */
+ uint32_t m_nb_work_done;
+
+ /**
+ The total number of plusses to output.
+ */
+ uint32_t m_nb_plusses_total;
+
+ /**
+ The total number of plusses that are already outputted.
+ */
+ uint32_t m_nb_plusses_printed;
+
+ /**
+ The timer of this progress reporter.
+ */
+ Timer *m_timer;
+
+ /**
+ The output file stream of this progress reporter.
+ */
+ FILE *m_fout;
+
+ /**
+ The output buffer of this progress reporter.
+ */
+ char *m_buffer;
+
+ /**
+ The current (output) position of this progress reporter.
+ */
+ char *m_current_pos;
+
+ /**
+ The mutex needed for updating this progress reporter.
+ */
+ Mutex *m_mutex;
+ };
+}
diff --git a/MAGE/MAGE/src/logging/timer.cpp b/MAGE/MAGE/src/logging/timer.cpp
new file mode 100644
index 000000000..a8020796c
--- /dev/null
+++ b/MAGE/MAGE/src/logging/timer.cpp
@@ -0,0 +1,65 @@
+//-----------------------------------------------------------------------------
+// Engine Includes
+//-----------------------------------------------------------------------------
+#pragma region
+
+#include "engine.hpp"
+
+#pragma endregion
+
+//-----------------------------------------------------------------------------
+// Engine Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ Timer::Timer() : m_running(false), m_time0(0.0), m_elapsed(0.0) {
+ // Retrieve the frequency of the performance counter.
+ // The frequency of the performance counter is fixed at system boot
+ // and is consistent across all processors.
+ QueryPerformanceFrequency(&m_performance_frequency);
+ // Calculate the period of the performance counter.
+ m_performance_period = 1.0 / ((double)m_performance_frequency.QuadPart);
+ }
+
+ double Timer::time() {
+ // Retrieve the current value of the performance counter,
+ // which is a high resolution (< 1 µs) time stamp
+ // that can be used for time-interval measurements.
+ QueryPerformanceCounter(&m_performance_counter);
+ return (double)m_performance_counter.QuadPart * m_performance_period;
+ }
+
+ void Timer::Start() {
+ if (m_running) {
+ return;
+ }
+ m_running = true;
+ // Resets the initial time stamp.
+ m_time0 = time();
+ }
+
+ void Timer::Stop() {
+ if (!m_running) {
+ return;
+ }
+ m_running = false;
+ // Set the elapsed time.
+ m_elapsed += time() - m_time0;
+ }
+
+ void Timer::Reset() {
+ m_running = false;
+ // Resets the elapsed time.
+ m_elapsed = 0;
+ }
+
+ double Timer::Time() {
+ if (m_running) {
+ // Set the elapsed time.
+ m_elapsed += time() - m_time0;
+ // Resets the initial time stamp.
+ m_time0 = time();
+ }
+ return m_elapsed;
+ }
+}
\ No newline at end of file
diff --git a/MAGE/MAGE/src/logging/timer.hpp b/MAGE/MAGE/src/logging/timer.hpp
new file mode 100644
index 000000000..de182318c
--- /dev/null
+++ b/MAGE/MAGE/src/logging/timer.hpp
@@ -0,0 +1,96 @@
+#pragma once
+
+//-----------------------------------------------------------------------------
+// Engine Declarations and Definitions
+//-----------------------------------------------------------------------------
+namespace mage {
+
+ /**
+ A class of (high precision) timers.
+ */
+ class Timer {
+
+ public:
+
+ /**
+ Constructs a timer.
+ */
+ Timer();
+
+ /**
+ Destructs this timer.
+ */
+ virtual ~Timer() {}
+
+ /**
+ Starts this timer.
+ */
+ void Start();
+
+ /**
+ Stops this timer.
+ */
+ void Stop();
+
+ /**
+ Resets this timer.
+ */
+ void Reset();
+
+ /**
+ Restarts this timer.
+ */
+ void Restart() {
+ Reset();
+ Start();
+ }
+
+ /**
+ Returns the elapsed time of this timer.
+
+ @return The elapsed time of this timer.
+ */
+ double Time();
+
+ private:
+
+ /**
+ Returns the time of this timer.
+
+ @return The time of this timer.
+ @note This member method encapsulates the performance
+ of the underlying counter/frequency processing.
+ */
+ double time();
+
+ /**
+ The initial time stamp of this timer.
+ */
+ double m_time0;
+
+ /**
+ The elapsed time of this timer.
+ */
+ double m_elapsed;
+
+ /**
+ Flag indicating whether this timer is running.
+ */
+ bool m_running;
+
+ /**
+ The counter of this timer.
+ */
+ LARGE_INTEGER m_performance_counter;
+
+ /**
+ The frequency of this timer.
+ */
+ LARGE_INTEGER m_performance_frequency;
+
+ /**
+ The period of this timer.
+ */
+ double m_performance_period;
+ };
+}
\ No newline at end of file