aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--src/core/application.cpp75
-rw-r--r--src/core/application.h48
-rw-r--r--src/core/assert.h20
-rw-r--r--src/core/log.h137
-rw-r--r--src/main.cpp17
6 files changed, 295 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 5a11b99..b5752d8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ Makefile
*.xcodeproj/
+.cache/
compile_commands.json
compile_flags.txt
diff --git a/src/core/application.cpp b/src/core/application.cpp
new file mode 100644
index 0000000..fd04e62
--- /dev/null
+++ b/src/core/application.cpp
@@ -0,0 +1,75 @@
+#include "core/application.h"
+
+#include "core/assert.h"
+#include "core/log.h"
+
+#include <chrono>
+
+namespace Hsdbg
+{
+ namespace
+ {
+ using Clock = std::chrono::steady_clock;
+
+ constexpr float MAX_DELTA_TIME = 0.25f;
+
+ // the run loop has nothing to block on until the window owns it, so it is
+ // time boxed for now to keep the app from spinning forever
+ constexpr float PLACEHOLDER_RUN_TIME = 1.0f;
+ }
+
+ Application* Application::s_instance = nullptr;
+
+ Application::Application(const ApplicationSpec& spec)
+ : m_spec(spec)
+ {
+ HSDBG_ASSERT(s_instance == nullptr, "an Application instance already exists");
+ s_instance = this;
+
+ Log::info("{}: starting up", m_spec.name);
+ }
+
+ Application::~Application()
+ {
+ Log::info("{}: shutting down after {} frames", m_spec.name, m_frame_count);
+
+ s_instance = nullptr;
+ }
+
+ auto Application::get() -> Application&
+ {
+ HSDBG_ASSERT(s_instance != nullptr, "no Application instance has been created");
+ return *s_instance;
+ }
+
+ auto Application::run() -> void
+ {
+ m_running = true;
+
+ auto last_frame_time = Clock::now();
+
+ while (m_running)
+ {
+ const auto now = Clock::now();
+ const float elapsed = std::chrono::duration<float>(now - last_frame_time).count();
+ last_frame_time = now;
+
+ m_delta_time = elapsed < MAX_DELTA_TIME ? elapsed : MAX_DELTA_TIME;
+ m_time += m_delta_time;
+ m_frame_count += 1;
+
+ update();
+ }
+ }
+
+ auto Application::close() -> void
+ {
+ m_running = false;
+ }
+
+ auto Application::update() -> void
+ {
+ if (m_time >= PLACEHOLDER_RUN_TIME)
+ close();
+ }
+}
diff --git a/src/core/application.h b/src/core/application.h
new file mode 100644
index 0000000..1e4a08d
--- /dev/null
+++ b/src/core/application.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+namespace Hsdbg
+{
+ struct ApplicationSpec
+ {
+ std::string name = "hsdbg";
+ uint32_t width = 1600;
+ uint32_t height = 900;
+ };
+
+ class Application
+ {
+ public:
+ explicit Application(const ApplicationSpec& spec);
+ ~Application();
+
+ Application(const Application&) = delete;
+ Application(Application&&) = delete;
+ auto operator=(const Application&) -> Application& = delete;
+ auto operator=(Application&&) -> Application& = delete;
+
+ static auto get() -> Application&;
+
+ auto run() -> void;
+ auto close() -> void;
+
+ auto spec() const -> const ApplicationSpec& { return m_spec; }
+ auto is_running() const -> bool { return m_running; }
+ auto delta_time() const -> float { return m_delta_time; }
+ auto time() const -> float { return m_time; }
+ auto frame_count() const -> uint64_t { return m_frame_count; }
+
+ private:
+ auto update() -> void;
+
+ static Application* s_instance;
+
+ ApplicationSpec m_spec;
+ bool m_running = false;
+ float m_delta_time = 0.0f;
+ float m_time = 0.0f;
+ uint64_t m_frame_count = 0;
+ };
+}
diff --git a/src/core/assert.h b/src/core/assert.h
new file mode 100644
index 0000000..eee1c96
--- /dev/null
+++ b/src/core/assert.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "core/log.h"
+
+#include <exception>
+
+#ifdef HSDBG_DIST
+ #define HSDBG_ASSERT(condition, message) ((void)0)
+#else
+ #define HSDBG_ASSERT(condition, message) \
+ do \
+ { \
+ if (!(condition)) \
+ { \
+ ::Hsdbg::Log::error("assertion failed: {}", #condition); \
+ ::Hsdbg::Log::error(" {}:{}: {}", __FILE__, __LINE__, message); \
+ std::terminate(); \
+ } \
+ } while (false)
+#endif
diff --git a/src/core/log.h b/src/core/log.h
new file mode 100644
index 0000000..db7440b
--- /dev/null
+++ b/src/core/log.h
@@ -0,0 +1,137 @@
+#pragma once
+
+#include <cstdint>
+#include <format>
+#include <iostream>
+#include <ostream>
+#include <print>
+#include <string_view>
+#include <utility>
+
+// there is no standard way to ask whether a stream is a terminal
+#ifdef HSDBG_WINDOWS
+ #include <io.h>
+#else
+ #include <unistd.h>
+#endif
+
+namespace Hsdbg::Log
+{
+ enum class Level : uint8_t
+ {
+ Trace,
+ Debug,
+ Info,
+ Warn,
+ Error,
+ };
+
+ namespace Detail
+ {
+ inline Level g_min_level =
+#ifdef HSDBG_DIST
+ Level::Info;
+#else
+ Level::Trace;
+#endif
+
+ inline auto label(Level level) -> std::string_view
+ {
+ switch (level)
+ {
+ case Level::Trace: return "trace";
+ case Level::Debug: return "debug";
+ case Level::Info: return "info ";
+ case Level::Warn: return "warn ";
+ case Level::Error: return "error";
+ }
+
+ return "?????";
+ }
+
+ inline auto color(Level level) -> std::string_view
+ {
+ switch (level)
+ {
+ case Level::Trace: return "\x1b[90m";
+ case Level::Debug: return "\x1b[36m";
+ case Level::Info: return "\x1b[32m";
+ case Level::Warn: return "\x1b[33m";
+ case Level::Error: return "\x1b[31m";
+ }
+
+ return "";
+ }
+
+ inline auto is_terminal(bool to_stderr) -> bool
+ {
+ constexpr int STDOUT_DESCRIPTOR = 1;
+ constexpr int STDERR_DESCRIPTOR = 2;
+
+ const int descriptor = to_stderr ? STDERR_DESCRIPTOR : STDOUT_DESCRIPTOR;
+
+#ifdef HSDBG_WINDOWS
+ return _isatty(descriptor) != 0;
+#else
+ return isatty(descriptor) != 0;
+#endif
+ }
+
+ inline auto write(Level level, std::string_view message) -> void
+ {
+ if (level < g_min_level)
+ return;
+
+ const bool to_stderr = level >= Level::Warn;
+ std::ostream& stream = to_stderr ? std::cerr : std::cout;
+
+ if (is_terminal(to_stderr))
+ std::println(stream, "{}{}\x1b[0m {}", color(level), label(level), message);
+ else
+ std::println(stream, "{} {}", label(level), message);
+
+ // never let a crash swallow the last lines that explain it
+ stream.flush();
+ }
+ }
+
+ inline auto set_min_level(Level level) -> void
+ {
+ Detail::g_min_level = level;
+ }
+
+ inline auto min_level() -> Level
+ {
+ return Detail::g_min_level;
+ }
+
+ template <typename... Args>
+ auto trace(std::format_string<Args...> fmt, Args&&... args) -> void
+ {
+ Detail::write(Level::Trace, std::format(fmt, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ auto debug(std::format_string<Args...> fmt, Args&&... args) -> void
+ {
+ Detail::write(Level::Debug, std::format(fmt, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ auto info(std::format_string<Args...> fmt, Args&&... args) -> void
+ {
+ Detail::write(Level::Info, std::format(fmt, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ auto warn(std::format_string<Args...> fmt, Args&&... args) -> void
+ {
+ Detail::write(Level::Warn, std::format(fmt, std::forward<Args>(args)...));
+ }
+
+ template <typename... Args>
+ auto error(std::format_string<Args...> fmt, Args&&... args) -> void
+ {
+ Detail::write(Level::Error, std::format(fmt, std::forward<Args>(args)...));
+ }
+}
diff --git a/src/main.cpp b/src/main.cpp
index d518fe6..bb72b0b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,6 +1,17 @@
-#include <print>
+#include "core/application.h"
-auto main() -> int
+auto main(int argc, char** argv) -> int
{
- std::println("Hachem's stupid debugger");
+ (void)argc;
+ (void)argv;
+
+ Hsdbg::ApplicationSpec spec;
+ spec.name = "hsdbg";
+ spec.width = 1600;
+ spec.height = 900;
+
+ Hsdbg::Application app(spec);
+ app.run();
+
+ return 0;
}