Set Up Base

This commit is contained in:
OusmBlueNinja 2025-05-18 13:29:55 -05:00
parent 5278c9fb43
commit 16a70b888d
12 changed files with 370 additions and 21 deletions

View File

@ -86,6 +86,7 @@ file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS
add_library(Core STATIC
${CORE_SOURCES}
src/core/systems/MACROS.h
)
target_include_directories(Core PUBLIC src/core)
@ -105,6 +106,8 @@ add_executable(Editor ${APP_SOURCES}
main.cpp
src/editor/Editor.cpp
src/editor/Editor.h
src/editor/Windows/LoggerWindow.cpp
src/editor/Windows/LoggerWindow.h
)
target_include_directories(Editor PRIVATE

View File

@ -10,10 +10,10 @@
int main()
{
OX::Core core("Application");
OX::Core core("Obsidian Editor - Onyx Engine (2025.1)(0.0.4)");
core.AddLayer(std::make_unique<OX::Editor>("Application"));
core.AddLayer(std::make_unique<OX::Editor>("Obsidian Editor"));
core.Init();

View File

@ -3,6 +3,9 @@
//
#include "Core.h"
#include "systems/MACROS.h"
namespace OX
{
@ -19,8 +22,8 @@ void Core::Init() {
for (auto& layer : m_layers) {
OX_ASSERT(!m_layers.empty(), "No Layers Attached");
for (const auto& layer : m_layers) {
Logger::LogDebug("Initializing Layer: '%s'", layer->GetName().c_str());
layer->Init(*this);
}
@ -35,7 +38,7 @@ void Core::Run() {
while (!window.ShouldClose()) {
Profiler::BeginFrame();
{
PROFILE_LABEL("Frame");
OX_PROFILE_LABEL("Frame");
Update();
window.BeginFrame();
@ -52,14 +55,14 @@ void Core::Run() {
}
void Core::Update() {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
for (auto& layer : m_layers) {
layer->Update(*this);
}
}
void Core::Draw() {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
for (auto& layer : m_layers) {
@ -82,4 +85,4 @@ void Core::Shutdown() {
Logger::LogOk("Core Shutdown Complete.");
}
}
}

View File

@ -12,6 +12,7 @@
#include "systems/Logger.h"
#include "systems/Profiler.h"
#include "systems/WindowManager.h"
#include "systems/MACROS.h"
namespace OX
{

View File

@ -3,6 +3,7 @@
#include <chrono>
#include <ctime>
#include <cstdarg>
namespace OX
{
std::vector<Message> Logger::m_messages;
@ -137,4 +138,19 @@ namespace OX
const std::vector<Message>& Logger::GetMessages() {
return m_messages;
}
std::string Logger::MessageTypeToString(const MessageType type) {
switch (type) {
case MessageType::Info: return "Info";
case MessageType::Warning: return "Warning";
case MessageType::Error: return "Error";
case MessageType::Debug: return "Debug";
case MessageType::Ok: return "Ok";
default: return "Unknown";
}
}
}

View File

@ -5,6 +5,8 @@
#include <cstdarg>
namespace OX
{
enum class MessageType {
Info,
Warning,
@ -30,6 +32,10 @@ public:
static void LogDebug(const char* format, ...);
static void LogOk(const char* format, ...);
static void Clear() {m_messages.clear();}
static std::string MessageTypeToString(const MessageType type);
static const std::vector<Message>& GetMessages();

48
src/core/systems/MACROS.h Normal file
View File

@ -0,0 +1,48 @@
//
// Created by spenc on 5/18/2025.
//
#ifndef MACROS_H
#define MACROS_H
#include <iostream>
#include <cstdlib>
#if defined(_WIN32)
#define OX_DEBUG_BREAK() __debugbreak()
#elif defined(__unix__) || defined(__APPLE__)
#include <signal.h>
#define OX_DEBUG_BREAK() raise(SIGTRAP)
#else
#define OX_DEBUG_BREAK() ((void)0)
#endif
// ========== ASSERT ==========
// In debug builds: breaks and logs.
// In release builds: removed entirely.
#ifdef _DEBUG
#define OX_ASSERT(condition, message) \
do { \
if (!(condition)) { \
std::cerr << "\n[ASSERTION] " << #condition << "\n" \
<< "Message: " << message << "\n" \
<< "File: " << __FILE__ << ":" << __LINE__ << "\n"; \
OX_DEBUG_BREAK(); \
} \
} while (0)
#else
#define OX_ASSERT(condition, message) ((void)0)
#endif
// ========== VERIFY ==========
// In debug builds: asserts.
// In release builds: just evaluates the condition.
#ifdef _DEBUG
#define OX_VERIFY(condition, message) OX_ASSERT(condition, message)
#else
#define OX_VERIFY(condition, message) ((void)(condition))
#endif
#endif //MACROS_H

View File

@ -58,13 +58,13 @@ namespace OX
#if defined(_DEBUG) || defined(DEBUG)
#define PROFILE_FUNCTION() ProfileScope __profile_scope__##__LINE__(__FUNC_NAME__)
#define PROFILE_LABEL(name) ProfileScope __profile_scope__##__LINE__(name)
#define OX_PROFILE_FUNCTION() ProfileScope __profile_scope__##__LINE__(__FUNC_NAME__)
#define OX_PROFILE_LABEL(name) ProfileScope __profile_scope__##__LINE__(name)
#else
#define PROFILE_FUNCTION()
#define PROFILE_LABEL(name)
#define OX_PROFILE_FUNCTION()
#define OX_PROFILE_LABEL(name)
#endif
}

View File

@ -49,7 +49,7 @@ bool WindowManager::Init(const std::string& title, int width, int height) {
void WindowManager::FramebufferSizeCallback(GLFWwindow* window, int width, int height) {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
auto* wm = static_cast<WindowManager*>(glfwGetWindowUserPointer(window));
if (wm) {
@ -58,7 +58,7 @@ void WindowManager::FramebufferSizeCallback(GLFWwindow* window, int width, int h
}
void WindowManager::SetSize(int width, int height) {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
m_width = width;
m_height = height;
@ -66,7 +66,7 @@ void WindowManager::SetSize(int width, int height) {
}
void WindowManager::PollEvents() const {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
glfwPollEvents();
}
@ -76,7 +76,7 @@ bool WindowManager::ShouldClose() const {
}
void WindowManager::BeginFrame() const {
PROFILE_FUNCTION();
OX_PROFILE_FUNCTION();
PollEvents();
glViewport(0, 0, m_width, m_height);
glClearColor(0.07f, 0.07f, 0.1f, 1.0f);
@ -84,10 +84,10 @@ void WindowManager::BeginFrame() const {
}
void WindowManager::EndFrame() const {
OX_PROFILE_FUNCTION();
glfwSwapBuffers(m_window);
{
glfwSwapBuffers(m_window);
}
}
void WindowManager::Shutdown() {

View File

@ -3,27 +3,132 @@
//
#include "Editor.h"
#include <functional>
#include <imgui.h>
#include <imgui_impl_opengl3.h>
#include <imgui_impl_glfw.h>
#include "Windows/LoggerWindow.h"
namespace OX {
void Editor::Init(Core& core)
{
Logger::LogOk("Editor::Init");
Logger::LogInfo("%s Init", m_name.c_str());
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
ImGui::StyleColorsDark();
ImGuiStyle& style = ImGui::GetStyle();
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
style.WindowRounding = 5.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
ImGui_ImplGlfw_InitForOpenGL(core.GetWindow().GetHandle(), true);
ImGui_ImplOpenGL3_Init("#version 330 core");
}
void Editor::Update(Core& core)
{
OX_PROFILE_FUNCTION();
}
void Editor::Draw(Core& core)
{
OX_PROFILE_FUNCTION();
ImGui_ImplOpenGL3_NewFrame();
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
// === Main Docking Space ===
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground;
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGui::Begin("DockSpace Root", nullptr, windowFlags);
ImGui::PopStyleVar(2);
ImGuiID dockspaceID = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(dockspaceID, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode);
LoggerWindow::Draw();
ImGui::Begin("Profiler");
const auto& tree = Profiler::GetSavedTree();
if (tree.empty()) {
ImGui::Text("No samples yet.");
} else {
std::function<void(const Profiler::SavedSample&, int)> DrawNode;
DrawNode = [&](const Profiler::SavedSample& node, int depth) {
// Indentation
ImGui::Indent(depth * 10.0f);
// Color based on time
ImVec4 color;
if (node.totalTime > 10.0f) color = ImVec4(1.0f, 0.2f, 0.2f, 1.0f); // red
else if (node.totalTime > 5.0f) color = ImVec4(1.0f, 0.5f, 0.0f, 1.0f); // orange
else if (node.totalTime > 1.0f) color = ImVec4(1.0f, 1.0f, 0.0f, 1.0f); // yellow
else color = ImVec4(0.2f, 1.0f, 0.2f, 1.0f); // green
ImGui::PushStyleColor(ImGuiCol_Text, color);
ImGui::Text("%s (%d): %.2f ms", node.name.c_str(), node.callCount, node.totalTime);
ImGui::PopStyleColor();
for (const auto& child : node.children) {
DrawNode(child, depth + 1);
}
ImGui::Unindent(depth * 10.0f);
};
for (const auto& root : tree) {
DrawNode(root, 0);
}
}
ImGui::End();
ImGui::End(); // DockSpace Root
// --- Render ImGui onto FBO 0 ---
{
OX_PROFILE_LABEL("VSYNC Wait");
ImGui::EndFrame();
ImGui::Render();
ImGui::UpdatePlatformWindows();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
}
}
void Editor::Shutdown(Core& core)
{
Logger::LogOk("Editor::Shutdown");
ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext();
}

View File

@ -0,0 +1,150 @@
//
// Created by spenc on 5/12/2025.
//
#include "LoggerWindow.h"
#include "Core.h"
#include <imgui.h>
#include <string>
namespace OX::LoggerWindow {
static bool s_AutoScroll = true;
static bool s_ShowOk = true;
static bool s_ShowInfo = true;
static bool s_ShowWarning = true;
static bool s_ShowError = true;
static bool s_ShowDebug = false;
static bool s_ShowVerbose = false;
static char s_FilterBuf[256] = "";
static ImVec4 GetColor(const MessageType level) {
switch (level) {
case MessageType::Ok: return {0.6f, 1.0f, 0.6f, 1.0f};
case MessageType::Info: return {0.3f, 0.6f, 1.0f, 1.0f};
case MessageType::Warning: return {1.0f, 0.8f, 0.2f, 1.0f};
case MessageType::Error: return {1.0f, 0.2f, 0.2f, 1.0f};
case MessageType::Debug: return {0.2f, 1.0f, 1.0f, 1.0f};
default: return {1, 1, 1, 1};
}
}
void Draw(const char* title)
{
OX_PROFILE_FUNCTION();
if (!ImGui::Begin(title)) {
ImGui::End();
return;
}
// Controls
if (ImGui::Button("Clear Log")) Logger::Clear();
ImGui::SameLine();
ImGui::Checkbox("Auto-scroll", &s_AutoScroll);
ImGui::SameLine();
ImGui::SetNextItemWidth(200);
ImGui::InputTextWithHint("##Filter", "Filter...", s_FilterBuf, sizeof(s_FilterBuf));
// Filter toggles
ImGui::Separator();
ImGui::Text("Levels: ");
ImGui::SameLine(); ImGui::Checkbox("Ok", &s_ShowOk);
ImGui::SameLine(); ImGui::Checkbox("Info", &s_ShowInfo);
ImGui::SameLine(); ImGui::Checkbox("Warning", &s_ShowWarning);
ImGui::SameLine(); ImGui::Checkbox("Error", &s_ShowError);
ImGui::SameLine(); ImGui::Checkbox("Debug", &s_ShowDebug);
ImGui::SameLine(); ImGui::Checkbox("Verbose", &s_ShowVerbose);
ImGui::Separator();
constexpr ImGuiTableFlags flags =
ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg |
ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter;
if (const float tableHeight = ImGui::GetContentRegionAvail().y - 10.0f; ImGui::BeginTable("LogTable", 3, flags, ImVec2(0, tableHeight))) {
ImGui::TableSetupColumn("Level", ImGuiTableColumnFlags_WidthFixed, 80.0f);
ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, 80.0f);
ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
for (const auto& message : Logger::GetMessages()) {
const MessageType level = message.type;
const std::string& text = message.text;
const std::string& timestamp = message.timestamp;
const bool show =
(level == MessageType::Ok && s_ShowOk) ||
(level == MessageType::Info && s_ShowInfo) ||
(level == MessageType::Warning && s_ShowWarning) ||
(level == MessageType::Error && s_ShowError) ||
(level == MessageType::Debug && s_ShowDebug);
if (!show)
continue;
if (s_FilterBuf[0] != '\0' &&
std::string(text).find(s_FilterBuf) == std::string::npos)
continue;
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImVec4 col = GetColor(level);
const ImVec2 cursor = ImGui::GetCursorScreenPos();
constexpr float barWidth = 4.0f;
const float textHeight = ImGui::GetTextLineHeight();
ImVec2 barStart = cursor;
auto barEnd = ImVec2(cursor.x + barWidth, cursor.y + textHeight);
ImGui::GetWindowDrawList()->AddRectFilled(barStart, barEnd, ImGui::ColorConvertFloat4ToU32(col), 1.0f);
ImGui::Dummy(ImVec2(barWidth + 6.0f, 0));
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, col);
ImGui::TextUnformatted(Logger::MessageTypeToString(level).c_str());
ImGui::PopStyleColor();
ImGui::TableSetColumnIndex(1);
ImGui::Text("%s",timestamp.c_str());
ImGui::TableSetColumnIndex(2);
ImGui::TextWrapped("%s", text.c_str());
if (s_AutoScroll) {
if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY() - 5.0f) {
ImGui::SetScrollHereY(1.0f);
}
}
}
ImGui::EndTable();
}
ImGui::End();
}
void ClearFilters() {
s_FilterBuf[0] = '\0';
s_ShowOk = s_ShowInfo = s_ShowWarning = s_ShowError = s_ShowDebug = s_ShowVerbose = true;
}
}
// CE

View File

@ -0,0 +1,17 @@
//
// Created by spenc on 5/18/2025.
//
#ifndef LOGGERWINDOW_H
#define LOGGERWINDOW_H
namespace OX {
namespace LoggerWindow {
void Draw(const char* title = "Console");
void ClearFilters();
};
} // OX
#endif //LOGGERWINDOW_H