Compare commits
8 Commits
36b821eb64
...
91f8eff00d
Author | SHA1 | Date | |
---|---|---|---|
|
91f8eff00d | ||
|
4e2f6b8cfd | ||
|
6225c07dbd | ||
|
f298c48564 | ||
|
5758f841ed | ||
|
6074fdc492 | ||
|
f6e80b5ad0 | ||
|
623aa4694b |
2
.idea/.name
generated
2
.idea/.name
generated
@ -1 +1 @@
|
||||
CreatePBR
|
||||
Onyx
|
@ -27,8 +27,6 @@ set(CMAKE_C_EXTENSIONS OFF)
|
||||
|
||||
include_directories(${CMAKE_BINARY_DIR}/generated)
|
||||
|
||||
# Optional message
|
||||
message(STATUS "Generated Onyx version: ${FULL_VERSION}")
|
||||
|
||||
|
||||
# --- Output directories for multi-config builds ---
|
||||
@ -103,6 +101,14 @@ file(GLOB_RECURSE CORE_SOURCES CONFIGURE_DEPENDS
|
||||
add_library(Core STATIC
|
||||
${CORE_SOURCES}
|
||||
src/core/systems/MACROS.h
|
||||
src/core/renderer/Renderer.cpp
|
||||
src/core/renderer/Renderer.h
|
||||
src/core/systems/AssetManager.cpp
|
||||
src/core/systems/AssetManager.h
|
||||
src/core/systems/Asset.cpp
|
||||
src/core/systems/Asset.h
|
||||
src/core/systems/assets/Texture2D.cpp
|
||||
src/core/systems/assets/Texture2D.h
|
||||
)
|
||||
|
||||
target_include_directories(Core PUBLIC src/core)
|
||||
@ -124,6 +130,10 @@ add_executable(Editor ${APP_SOURCES}
|
||||
src/editor/Editor.h
|
||||
src/editor/Windows/LoggerWindow.cpp
|
||||
src/editor/Windows/LoggerWindow.h
|
||||
src/editor/Windows/Viewport.cpp
|
||||
src/editor/Windows/Viewport.h
|
||||
src/editor/Windows/FileBrowser.cpp
|
||||
src/editor/Windows/FileBrowser.h
|
||||
)
|
||||
|
||||
target_include_directories(Editor PRIVATE
|
||||
@ -137,6 +147,7 @@ target_link_libraries(Editor PRIVATE
|
||||
glfw
|
||||
assimp::assimp
|
||||
GLEW::GLEW
|
||||
yaml-cpp
|
||||
${CMAKE_DL_LIBS}
|
||||
)
|
||||
|
||||
|
8
main.cpp
8
main.cpp
@ -8,13 +8,11 @@
|
||||
|
||||
int main()
|
||||
{
|
||||
OX::Core core{};
|
||||
|
||||
constexpr const char* VERSION = "0.0.7"; // Format: 0.<release><commit_count>
|
||||
constexpr const char* TITLE = "Obsidian Editor - Onyx Engine (2025.1)";
|
||||
core.AddLayer(std::make_unique<OX::Editor>(OX_EDITOR_VERSION));
|
||||
|
||||
OX::Core core(std::string(TITLE) + " (" + VERSION + ")");
|
||||
|
||||
core.AddLayer(std::make_unique<OX::Editor>("Obsidian Editor"));
|
||||
//core.AddLayer(std::make_unique<OX::DummyLayer>("Dummy Layer"));
|
||||
|
||||
core.Init();
|
||||
core.Run();
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "Core.h"
|
||||
|
||||
#include "systems/MACROS.h"
|
||||
#include "systems/AssetManager.h"
|
||||
|
||||
namespace OX
|
||||
{
|
||||
@ -21,25 +22,34 @@ namespace OX
|
||||
if (!window.Init(m_name, 1280, 720))
|
||||
return;
|
||||
|
||||
|
||||
OX_ASSERT(!m_layers.empty(), "No Layers Attached");
|
||||
for (const auto &layer: m_layers) {
|
||||
|
||||
std::string layerTitle;
|
||||
for (size_t i = 0; i < m_layers.size(); ++i) {
|
||||
if (i > 0)
|
||||
layerTitle += " - ";
|
||||
layerTitle += m_layers[i]->GetName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (const auto &layer : m_layers) {
|
||||
|
||||
Logger::LogDebug("Initializing Layer: '%s'", layer->GetName().c_str());
|
||||
layer->Init(*this);
|
||||
}
|
||||
|
||||
|
||||
std::string fullTitle = layerTitle + " - " + m_name;
|
||||
window.SetWindowTitle(fullTitle);
|
||||
|
||||
Logger::LogOk("Core Initialization Complete.");
|
||||
|
||||
Logger::LogInfo("Info: This is an informational message.");
|
||||
Logger::LogWarning("Warning: Something might be wrong.");
|
||||
Logger::LogError("Error: Something went wrong!");
|
||||
Logger::LogDebug("Debug: Internal debug information.");
|
||||
Logger::LogVerbose("Verbose: Extra detailed logs.");
|
||||
Logger::LogOk("Ok: Everything succeeded!");
|
||||
AssetManager::Init("C:/Users/spenc/OneDrive/Desktop/OnyxProject");
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Core::Run()
|
||||
{
|
||||
m_running = true;
|
||||
@ -60,6 +70,7 @@ namespace OX
|
||||
void Core::Update()
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
AssetManager::Tick();
|
||||
for (auto &layer: m_layers) {
|
||||
layer->Update(*this);
|
||||
}
|
||||
@ -86,6 +97,7 @@ namespace OX
|
||||
}
|
||||
|
||||
m_layers.clear();
|
||||
AssetManager::Shutdown();
|
||||
|
||||
window.Shutdown();
|
||||
|
||||
|
@ -9,41 +9,80 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "Layer.h"
|
||||
#include "renderer/Renderer.h"
|
||||
#include "systems/Logger.h"
|
||||
#include "systems/Profiler.h"
|
||||
#include "systems/WindowManager.h"
|
||||
#include "systems/MACROS.h"
|
||||
|
||||
#define OX_ENGINE_VERSION "Onyx Engine (2025.1)"
|
||||
|
||||
namespace OX
|
||||
{
|
||||
class Core {
|
||||
class Core
|
||||
{
|
||||
public:
|
||||
Core(std::string name) : m_name(std::move(name)) {};
|
||||
Core(std::string name) : m_name(std::move(name))
|
||||
{
|
||||
};
|
||||
|
||||
Core() : m_name(OX_ENGINE_VERSION)
|
||||
{
|
||||
};
|
||||
|
||||
~Core() = default;
|
||||
|
||||
void Init();
|
||||
|
||||
void Run();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
|
||||
WindowManager& GetWindow() {return window;}
|
||||
|
||||
|
||||
|
||||
WindowManager &GetWindow() { return window; }
|
||||
Renderer &GetRenderer() { return renderer; }
|
||||
|
||||
void AddLayer(std::unique_ptr<Layer> layer);
|
||||
|
||||
private:
|
||||
void Update();
|
||||
|
||||
void Draw();
|
||||
|
||||
|
||||
std::vector<std::unique_ptr<Layer>> m_layers;
|
||||
std::vector<std::unique_ptr<Layer> > m_layers;
|
||||
WindowManager window;
|
||||
Renderer renderer;
|
||||
|
||||
bool m_running = false;
|
||||
std::string m_name = "Application";
|
||||
};
|
||||
|
||||
class DummyLayer : public Layer
|
||||
{
|
||||
public:
|
||||
explicit DummyLayer(const std::string &name = "Dummy Layer")
|
||||
: Layer(name)
|
||||
{
|
||||
}
|
||||
|
||||
void Init(Core &core) override
|
||||
{
|
||||
Logger::LogDebug("%s Init", m_name.c_str());
|
||||
}
|
||||
|
||||
void Update(Core &core) override
|
||||
{
|
||||
}
|
||||
|
||||
void Draw(Core &core) override
|
||||
{
|
||||
}
|
||||
|
||||
void Shutdown(Core &core) override
|
||||
{
|
||||
Logger::LogDebug("%s Shutdown", m_name.c_str());
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // CORE_H
|
||||
|
||||
|
9
src/core/renderer/Renderer.cpp
Normal file
9
src/core/renderer/Renderer.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#include "Renderer.h"
|
||||
|
||||
namespace OX {
|
||||
|
||||
} // OX
|
26
src/core/renderer/Renderer.h
Normal file
26
src/core/renderer/Renderer.h
Normal file
@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#ifndef RENDERER_H
|
||||
#define RENDERER_H
|
||||
|
||||
#include "glfw/glfw3.h"
|
||||
#include "glm/glm.hpp"
|
||||
|
||||
namespace OX {
|
||||
|
||||
class Renderer {
|
||||
public:
|
||||
Renderer() = default;
|
||||
~Renderer() = default;
|
||||
|
||||
[[nodiscard]] GLuint GetRenderTarget() const {return m_renderTarget; }
|
||||
|
||||
private:
|
||||
GLuint m_renderTarget;
|
||||
};
|
||||
|
||||
} // OX
|
||||
|
||||
#endif //RENDERER_H
|
8
src/core/systems/Asset.cpp
Normal file
8
src/core/systems/Asset.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#include "Asset.h"
|
||||
|
||||
namespace OX {
|
||||
} // OX
|
20
src/core/systems/Asset.h
Normal file
20
src/core/systems/Asset.h
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#ifndef ASSET_H
|
||||
#define ASSET_H
|
||||
#include "Logger.h"
|
||||
|
||||
namespace OX {
|
||||
|
||||
class Asset {
|
||||
public:
|
||||
virtual ~Asset() = default;
|
||||
virtual std::string GetTypeName() const = 0;
|
||||
virtual bool LoadFromFile(const std::string& path) = 0;
|
||||
};
|
||||
|
||||
} // OX
|
||||
|
||||
#endif //ASSET_H
|
196
src/core/systems/AssetManager.cpp
Normal file
196
src/core/systems/AssetManager.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
#include "AssetManager.h"
|
||||
#include "assets/Texture2D.h"
|
||||
#include "Logger.h"
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace OX
|
||||
{
|
||||
std::unordered_map<std::string, std::shared_ptr<Asset> > AssetManager::s_LoadedAssets;
|
||||
std::unordered_map<std::string, AssetManager::AssetMetadata> AssetManager::s_MetadataMap;
|
||||
std::shared_ptr<ResourceTreeNode> AssetManager::s_FileTree = std::make_shared<ResourceTreeNode>();
|
||||
|
||||
std::mutex AssetManager::s_QueueMutex;
|
||||
std::queue<std::string> AssetManager::s_DeferredLoadQueue;
|
||||
|
||||
fs::path AssetManager::s_ProjectRoot;
|
||||
std::atomic<bool> AssetManager::s_Scanning = false;
|
||||
std::thread AssetManager::s_ScanThread;
|
||||
|
||||
void AssetManager::Init(const std::string &projectRoot)
|
||||
{
|
||||
s_ProjectRoot = fs::absolute(projectRoot);
|
||||
s_Scanning = true;
|
||||
s_FileTree = std::make_shared<ResourceTreeNode>();
|
||||
s_FileTree->name = "res://";
|
||||
s_FileTree->path = "res://";
|
||||
s_FileTree->isDirectory = true;
|
||||
|
||||
s_ScanThread = std::thread([=]
|
||||
{
|
||||
BackgroundScan(s_ProjectRoot);
|
||||
s_Scanning = false;
|
||||
});
|
||||
}
|
||||
|
||||
void AssetManager::Shutdown()
|
||||
{
|
||||
if (s_ScanThread.joinable())
|
||||
s_ScanThread.join();
|
||||
}
|
||||
|
||||
void AssetManager::Tick()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(s_QueueMutex);
|
||||
if (!s_DeferredLoadQueue.empty()) {
|
||||
auto resPath = s_DeferredLoadQueue.front();
|
||||
s_DeferredLoadQueue.pop();
|
||||
LoadAsset(resPath);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AssetManager::SaveAssetPack(const std::string& outputPath)
|
||||
{
|
||||
YAML::Emitter out;
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "assets" << YAML::Value << YAML::BeginSeq;
|
||||
|
||||
for (const auto& [resPath, meta] : s_MetadataMap) {
|
||||
fs::path relative = fs::relative(meta.absolutePath, s_ProjectRoot);
|
||||
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "id" << YAML::Value << resPath;
|
||||
out << YAML::Key << "type" << YAML::Value << meta.type;
|
||||
out << YAML::Key << "path" << YAML::Value << relative.generic_string();
|
||||
out << YAML::EndMap;
|
||||
}
|
||||
|
||||
out << YAML::EndSeq;
|
||||
out << YAML::EndMap;
|
||||
|
||||
std::ofstream fout(outputPath);
|
||||
fout << out.c_str();
|
||||
fout.close();
|
||||
|
||||
Logger::LogInfo("Saved asset pack: %s", outputPath.c_str());
|
||||
}
|
||||
|
||||
|
||||
void AssetManager::Rescan()
|
||||
{
|
||||
if (s_Scanning) return;
|
||||
s_Scanning = true;
|
||||
s_FileTree = std::make_shared<ResourceTreeNode>();
|
||||
s_FileTree->name = "res://";
|
||||
s_FileTree->path = "res://";
|
||||
s_FileTree->isDirectory = true;
|
||||
|
||||
s_ScanThread = std::thread([=]
|
||||
{
|
||||
BackgroundScan(s_ProjectRoot);
|
||||
s_Scanning = false;
|
||||
});
|
||||
}
|
||||
|
||||
void AssetManager::BackgroundScan(const fs::path &root)
|
||||
{
|
||||
for (const auto &entry: fs::recursive_directory_iterator(root)) {
|
||||
const auto &path = entry.path();
|
||||
std::string resPath = MakeVirtualPath(path);
|
||||
|
||||
if (entry.is_directory()) {
|
||||
AddToTree(resPath, true);
|
||||
} else {
|
||||
AddToTree(resPath, false);
|
||||
|
||||
std::string type = DetectAssetType(path);
|
||||
if (!type.empty()) {
|
||||
std::lock_guard<std::mutex> lock(s_QueueMutex);
|
||||
s_MetadataMap[resPath] = {type, path.string()};
|
||||
s_DeferredLoadQueue.push(resPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AssetManager::AddToTree(const std::string &resPath, bool isDir)
|
||||
{
|
||||
std::vector<std::string> parts;
|
||||
size_t pos = 0, next;
|
||||
while ((next = resPath.find('/', pos)) != std::string::npos) {
|
||||
if (next != pos) parts.push_back(resPath.substr(pos, next - pos));
|
||||
pos = next + 1;
|
||||
}
|
||||
if (pos < resPath.length()) parts.push_back(resPath.substr(pos));
|
||||
|
||||
auto current = s_FileTree;
|
||||
for (size_t i = 1; i < parts.size(); ++i) {
|
||||
auto &name = parts[i];
|
||||
auto it = std::find_if(current->children.begin(), current->children.end(), [&](auto &child)
|
||||
{
|
||||
return child->name == name;
|
||||
});
|
||||
|
||||
if (it == current->children.end()) {
|
||||
auto newNode = std::make_shared<ResourceTreeNode>();
|
||||
newNode->name = name;
|
||||
newNode->path = current->path + "/" + name;
|
||||
newNode->isDirectory = (i < parts.size() - 1) || isDir;
|
||||
current->children.push_back(newNode);
|
||||
current = newNode;
|
||||
} else {
|
||||
current = *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string AssetManager::MakeVirtualPath(const fs::path &full)
|
||||
{
|
||||
fs::path rel = fs::relative(full, s_ProjectRoot);
|
||||
return "res://" + rel.generic_string();
|
||||
}
|
||||
|
||||
std::string AssetManager::DetectAssetType(const fs::path &ext)
|
||||
{
|
||||
auto e = ext.extension().string();
|
||||
if (e == ".png" || e == ".jpg") return "texture2D";
|
||||
if (e == ".ogg" || e == ".wav") return "audio";
|
||||
return "";
|
||||
}
|
||||
|
||||
std::shared_ptr<Asset> AssetManager::Get(const std::string &resPath)
|
||||
{
|
||||
auto it = s_LoadedAssets.find(resPath);
|
||||
return (it != s_LoadedAssets.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
bool AssetManager::LoadAsset(const std::string &resPath)
|
||||
{
|
||||
auto it = s_MetadataMap.find(resPath);
|
||||
if (it == s_MetadataMap.end()) return false;
|
||||
|
||||
const auto &meta = it->second;
|
||||
std::shared_ptr<Asset> asset;
|
||||
|
||||
if (meta.type == "texture2D")
|
||||
asset = std::make_shared<Texture2D>();
|
||||
|
||||
if (asset && asset->LoadFromFile(meta.absolutePath)) {
|
||||
s_LoadedAssets[resPath] = asset;
|
||||
Logger::LogDebug("Loaded asset: %s", resPath.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
Logger::LogError("Failed to load: %s", resPath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<ResourceTreeNode> AssetManager::GetFileTree()
|
||||
{
|
||||
return s_FileTree;
|
||||
}
|
||||
} // namespace OX
|
61
src/core/systems/AssetManager.h
Normal file
61
src/core/systems/AssetManager.h
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <queue>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
namespace OX {
|
||||
|
||||
class Asset;
|
||||
|
||||
struct ResourceTreeNode {
|
||||
std::string name;
|
||||
std::string path; // res://...
|
||||
bool isDirectory = false;
|
||||
std::vector<std::shared_ptr<ResourceTreeNode>> children;
|
||||
};
|
||||
|
||||
class AssetManager {
|
||||
public:
|
||||
static void Init(const std::string& projectRoot);
|
||||
static void Shutdown();
|
||||
static void Tick(); // Call every frame
|
||||
|
||||
static void SaveAssetPack(const std::string& outputPath);
|
||||
|
||||
|
||||
static std::shared_ptr<Asset> Get(const std::string& resPath);
|
||||
static std::shared_ptr<ResourceTreeNode> GetFileTree();
|
||||
static bool LoadAsset(const std::string& resPath);
|
||||
static void Rescan(); // Rebuilds file tree (slow)
|
||||
|
||||
private:
|
||||
struct AssetMetadata {
|
||||
std::string type;
|
||||
std::string absolutePath;
|
||||
};
|
||||
|
||||
static void BackgroundScan(const std::filesystem::path& root);
|
||||
static void AddToTree(const std::string& virtualPath, bool isDir);
|
||||
static std::string DetectAssetType(const std::filesystem::path& ext);
|
||||
static std::string MakeVirtualPath(const std::filesystem::path& full);
|
||||
|
||||
static std::unordered_map<std::string, std::shared_ptr<Asset>> s_LoadedAssets;
|
||||
static std::unordered_map<std::string, AssetMetadata> s_MetadataMap;
|
||||
static std::shared_ptr<ResourceTreeNode> s_FileTree;
|
||||
|
||||
static std::mutex s_QueueMutex;
|
||||
static std::queue<std::string> s_DeferredLoadQueue;
|
||||
|
||||
static std::filesystem::path s_ProjectRoot;
|
||||
static std::atomic<bool> s_Scanning;
|
||||
static std::thread s_ScanThread;
|
||||
};
|
||||
|
||||
} // namespace OX
|
@ -48,31 +48,32 @@ namespace OX
|
||||
Color color;
|
||||
switch (type) {
|
||||
case MessageType::Info:
|
||||
color.r = 0.25f; color.g = 0.5f; color.b = 0.95f; // Calmer blue
|
||||
color = { 0.0f, 0.478f, 1.0f }; // Standard blue (iOS info blue / material blue)
|
||||
break;
|
||||
case MessageType::Warning:
|
||||
color.r = 1.0f; color.g = 0.75f; color.b = 0.1f; // Amber/goldenrod
|
||||
color = { 1.0f, 0.647f, 0.0f }; // Orange / amber (alert warning)
|
||||
break;
|
||||
case MessageType::Error:
|
||||
color.r = 0.9f; color.g = 0.2f; color.b = 0.3f; // Strong crimson red
|
||||
color = { 0.863f, 0.078f, 0.235f }; // Crimson / alert red
|
||||
break;
|
||||
case MessageType::Debug:
|
||||
color.r = 0.6f; color.g = 0.6f; color.b = 0.7f; // Neutral cool gray
|
||||
color = { 0.56f, 0.56f, 0.58f }; // Slate gray
|
||||
break;
|
||||
case MessageType::Ok:
|
||||
color.r = 0.3f; color.g = 0.85f; color.b = 0.4f; // Balanced green
|
||||
color = { 0.0f, 0.8f, 0.4f }; // Vibrant green / success
|
||||
break;
|
||||
case MessageType::Verbose:
|
||||
color.r = 0.7f; color.g = 0.7f; color.b = 0.9f; // Soft lavender/gray
|
||||
color = { 0.6f, 0.6f, 0.7f }; // Dim blue-gray
|
||||
break;
|
||||
default:
|
||||
color = Color::White(); // Default white
|
||||
color = { 1.0f, 1.0f, 1.0f }; // Default white
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Logger::LogInternal(const std::string& text, MessageType type) {
|
||||
glm::vec3 color = Logger::GetRGBColor(type);
|
||||
float r = color.r;
|
||||
|
@ -4,101 +4,120 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "Profiler.h"
|
||||
|
||||
namespace OX
|
||||
{
|
||||
bool WindowManager::Init(const std::string& title, int width, int height) {
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
bool WindowManager::Init(const std::string &title, int width, int height)
|
||||
{
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
|
||||
if (!glfwInit()) {
|
||||
Logger::LogError("Failed to initialize GLFW");
|
||||
return false;
|
||||
if (!glfwInit()) {
|
||||
Logger::LogError("Failed to initialize GLFW");
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
//glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // REM title bar
|
||||
|
||||
|
||||
m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
|
||||
if (!m_window) {
|
||||
Logger::LogError("Failed to create GLFW window");
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(m_window);
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK) {
|
||||
Logger::LogError("Failed to initialize GLEW: %s", reinterpret_cast<const char *>(glewGetErrorString(err)));
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetFramebufferSizeCallback(m_window, FramebufferSizeCallback);
|
||||
glfwSetWindowUserPointer(m_window, this);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
|
||||
//glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); // REM title bar
|
||||
void WindowManager::SetWindowTitle(const std::string &title) const
|
||||
{
|
||||
if (m_window) {
|
||||
glfwSetWindowTitle(m_window, title.c_str());
|
||||
}
|
||||
else {
|
||||
Logger::LogWarning("Failed to set Window Title: 'Not Initialized'");
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::FramebufferSizeCallback(GLFWwindow *window, int width, int height)
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
m_window = glfwCreateWindow(width, height, title.c_str(), nullptr, nullptr);
|
||||
if (!m_window) {
|
||||
Logger::LogError("Failed to create GLFW window");
|
||||
auto *wm = static_cast<WindowManager *>(glfwGetWindowUserPointer(window));
|
||||
if (wm) {
|
||||
wm->SetSize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::SetSize(int width, int height)
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
void WindowManager::PollEvents() const
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
bool WindowManager::ShouldClose() const
|
||||
{
|
||||
return glfwWindowShouldClose(m_window);
|
||||
}
|
||||
|
||||
void WindowManager::BeginFrame() const
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
PollEvents();
|
||||
glViewport(0, 0, m_width, m_height);
|
||||
glClearColor(0.07f, 0.07f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void WindowManager::EndFrame() const
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
glfwSwapBuffers(m_window);
|
||||
}
|
||||
|
||||
void WindowManager::Shutdown()
|
||||
{
|
||||
if (m_window) {
|
||||
glfwDestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
glfwTerminate();
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwMakeContextCurrent(m_window);
|
||||
glfwSwapInterval(1); // Enable vsync
|
||||
|
||||
glewExperimental = GL_TRUE;
|
||||
GLenum err = glewInit();
|
||||
if (err != GLEW_OK) {
|
||||
Logger::LogError("Failed to initialize GLEW: %s", reinterpret_cast<const char*>(glewGetErrorString(err)));
|
||||
return false;
|
||||
}
|
||||
|
||||
glfwSetFramebufferSizeCallback(m_window, FramebufferSizeCallback);
|
||||
glfwSetWindowUserPointer(m_window, this);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void WindowManager::FramebufferSizeCallback(GLFWwindow* window, int width, int height) {
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
auto* wm = static_cast<WindowManager*>(glfwGetWindowUserPointer(window));
|
||||
if (wm) {
|
||||
wm->SetSize(width, height);
|
||||
WindowManager::~WindowManager()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
void WindowManager::SetSize(int width, int height) {
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
glViewport(0, 0, width, height);
|
||||
}
|
||||
|
||||
void WindowManager::PollEvents() const {
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
|
||||
bool WindowManager::ShouldClose() const {
|
||||
return glfwWindowShouldClose(m_window);
|
||||
}
|
||||
|
||||
void WindowManager::BeginFrame() const {
|
||||
OX_PROFILE_FUNCTION();
|
||||
PollEvents();
|
||||
glViewport(0, 0, m_width, m_height);
|
||||
glClearColor(0.07f, 0.07f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
|
||||
void WindowManager::EndFrame() const {
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
glfwSwapBuffers(m_window);
|
||||
|
||||
}
|
||||
|
||||
void WindowManager::Shutdown() {
|
||||
if (m_window) {
|
||||
glfwDestroyWindow(m_window);
|
||||
m_window = nullptr;
|
||||
}
|
||||
glfwTerminate();
|
||||
}
|
||||
|
||||
WindowManager::~WindowManager() {
|
||||
Shutdown();
|
||||
}
|
||||
}
|
@ -15,6 +15,7 @@ namespace OX
|
||||
|
||||
void PollEvents() const;
|
||||
[[nodiscard]] bool ShouldClose() const;
|
||||
void SetWindowTitle(const std::string& title) const;
|
||||
|
||||
void BeginFrame() const;
|
||||
void EndFrame() const;
|
||||
|
48
src/core/systems/assets/Texture2D.cpp
Normal file
48
src/core/systems/assets/Texture2D.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
|
||||
#include "Texture2D.h"
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb/stb_image.h>
|
||||
#include <GL/glew.h>
|
||||
|
||||
namespace OX
|
||||
{
|
||||
Texture2D::Texture2D() = default;
|
||||
|
||||
Texture2D::~Texture2D()
|
||||
{
|
||||
if (m_TextureID != 0) {
|
||||
glDeleteTextures(1, &m_TextureID);
|
||||
}
|
||||
}
|
||||
|
||||
bool Texture2D::LoadFromFile(const std::string &path)
|
||||
{
|
||||
stbi_set_flip_vertically_on_load(1);
|
||||
int channels;
|
||||
unsigned char *data = stbi_load(path.c_str(), &m_Width, &m_Height, &channels, 0);
|
||||
|
||||
if (!data) {
|
||||
Logger::LogError("Failed to load texture: %s", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum format = (channels == 4) ? GL_RGBA : GL_RGB;
|
||||
|
||||
glGenTextures(1, &m_TextureID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_TextureID);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, format, m_Width, m_Height, 0, format, GL_UNSIGNED_BYTE, data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
stbi_image_free(data);
|
||||
return true;
|
||||
}
|
||||
} // namespace OX
|
33
src/core/systems/assets/Texture2D.h
Normal file
33
src/core/systems/assets/Texture2D.h
Normal file
@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "systems/Asset.h"
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace OX
|
||||
{
|
||||
class Texture2D : public Asset
|
||||
{
|
||||
public:
|
||||
Texture2D();
|
||||
|
||||
~Texture2D();
|
||||
|
||||
bool LoadFromFile(const std::string &path) override;
|
||||
|
||||
std::string GetTypeName() const override { return "texture2D"; }
|
||||
|
||||
uint32_t GetID() const { return m_TextureID; }
|
||||
int GetWidth() const { return m_Width; }
|
||||
int GetHeight() const { return m_Height; }
|
||||
|
||||
private:
|
||||
uint32_t m_TextureID = 0;
|
||||
int m_Width = 0;
|
||||
int m_Height = 0;
|
||||
};
|
||||
} // OX
|
@ -7,25 +7,27 @@
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_opengl3.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
||||
#include "Windows/LoggerWindow.h"
|
||||
#include "Windows/Viewport.h"
|
||||
#include "Windows/FileBrowser.h"
|
||||
|
||||
|
||||
namespace OX {
|
||||
|
||||
void Editor::Init(Core& core)
|
||||
namespace OX
|
||||
{
|
||||
void Editor::Init(Core &core)
|
||||
{
|
||||
Logger::LogInfo("%s Init", m_name.c_str());
|
||||
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
||||
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
|
||||
style.WindowRounding = 5.0f;
|
||||
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
|
||||
@ -33,17 +35,17 @@ namespace OX {
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(core.GetWindow().GetHandle(), true);
|
||||
ImGui_ImplOpenGL3_Init("#version 330 core");
|
||||
|
||||
primaryViewport = new Viewport(); // The first time ive ever use the new keywork...
|
||||
}
|
||||
|
||||
void Editor::Update(Core& core)
|
||||
void Editor::Update(Core &core)
|
||||
{
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
}
|
||||
|
||||
void Editor::Draw(Core& core)
|
||||
void Editor::Draw(Core &core)
|
||||
{
|
||||
|
||||
OX_PROFILE_FUNCTION();
|
||||
|
||||
|
||||
@ -52,65 +54,93 @@ namespace OX {
|
||||
ImGui::NewFrame();
|
||||
|
||||
|
||||
|
||||
// === Main Docking Space ===
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBackground;
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking |
|
||||
ImGuiWindowFlags_NoBackground;
|
||||
|
||||
const ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
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_WindowPadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
||||
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoMove;
|
||||
windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||
|
||||
ImGui::Begin("DockSpace Root", nullptr, windowFlags);
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::PopStyleVar(3);
|
||||
|
||||
ImGuiID dockspaceID = ImGui::GetID("MyDockSpace");
|
||||
ImGui::DockSpace(dockspaceID, ImVec2(0.0f, 0.0f), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||
|
||||
LoggerWindow::Draw();
|
||||
FileBrowser::Draw();
|
||||
primaryViewport->Draw(core);
|
||||
|
||||
|
||||
ImGui::Begin("Profiler");
|
||||
|
||||
const auto& tree = Profiler::GetSavedTree();
|
||||
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);
|
||||
if (ImGui::BeginTable("ProfilerTable", 3,
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInnerV)) {
|
||||
ImGui::TableSetupColumn("Section");
|
||||
ImGui::TableSetupColumn("Calls", ImGuiTableColumnFlags_WidthFixed, 60.0f);
|
||||
ImGui::TableSetupColumn("Total Time (ms)", ImGuiTableColumnFlags_WidthFixed, 120.0f);
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
// 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
|
||||
std::function<void(const Profiler::SavedSample &)> DrawNode;
|
||||
DrawNode = [&](const Profiler::SavedSample &node)
|
||||
{
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
// === Section name with Tree UI ===
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Text("%s (%d): %.2f ms", node.name.c_str(), node.callCount, node.totalTime);
|
||||
// Color based on total 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.4f, 1.0f, 0.4f, 1.0f); // green
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
for (const auto& child : node.children) {
|
||||
DrawNode(child, depth + 1);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
bool open = ImGui::TreeNodeEx(node.name.c_str(),
|
||||
ImGuiTreeNodeFlags_SpanAllColumns | ImGuiTreeNodeFlags_DefaultOpen);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// === Call count ===
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%d", node.callCount);
|
||||
|
||||
// === Total time ===
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%.2f", node.totalTime);
|
||||
|
||||
// === Recurse if open ===
|
||||
if (open) {
|
||||
for (const auto &child: node.children) {
|
||||
DrawNode(child);
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
};
|
||||
|
||||
for (const auto &root: tree) {
|
||||
DrawNode(root);
|
||||
}
|
||||
|
||||
ImGui::Unindent(depth * 10.0f);
|
||||
};
|
||||
|
||||
for (const auto& root : tree) {
|
||||
DrawNode(root, 0);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
|
||||
|
||||
ImGui::End(); // DockSpace Root
|
||||
|
||||
// --- Render ImGui onto FBO 0 ---
|
||||
@ -122,17 +152,17 @@ namespace OX {
|
||||
ImGui::UpdatePlatformWindows();
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Editor::Shutdown(Core& core)
|
||||
void Editor::Shutdown(Core &core)
|
||||
{
|
||||
delete primaryViewport;
|
||||
primaryViewport = nullptr;
|
||||
|
||||
|
||||
Logger::LogOk("Editor::Shutdown");
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
ImGui::DestroyContext();
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // OX
|
||||
} // OX
|
||||
|
@ -4,24 +4,31 @@
|
||||
|
||||
#ifndef EDITOR_H
|
||||
#define EDITOR_H
|
||||
#define OX_EDITOR_VERSION "Obsidian Editor (0.1.5)"
|
||||
#include "Layer.h"
|
||||
#include "Core.h"
|
||||
namespace OX {
|
||||
|
||||
|
||||
namespace OX
|
||||
{
|
||||
class Viewport;
|
||||
|
||||
class Editor final : public Layer {
|
||||
public:
|
||||
using Layer::Layer;
|
||||
class Editor final : public Layer
|
||||
{
|
||||
public:
|
||||
using Layer::Layer;
|
||||
|
||||
void Init(Core& core) override;
|
||||
void Update(Core& core) override;
|
||||
void Draw(Core& core) override;
|
||||
void Shutdown(Core& core) override;
|
||||
};
|
||||
void Init(Core &core) override;
|
||||
|
||||
void Update(Core &core) override;
|
||||
|
||||
void Draw(Core &core) override;
|
||||
|
||||
void Shutdown(Core &core) override;
|
||||
|
||||
private:
|
||||
Viewport* primaryViewport;
|
||||
};
|
||||
} // OX
|
||||
|
||||
#endif //EDITOR_H
|
||||
|
70
src/editor/Windows/FileBrowser.cpp
Normal file
70
src/editor/Windows/FileBrowser.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
#include "FileBrowser.h"
|
||||
#include "systems/AssetManager.h"
|
||||
#include "imgui.h"
|
||||
#include <filesystem>
|
||||
|
||||
namespace OX {
|
||||
|
||||
static std::string s_CurrentPath = "res://";
|
||||
|
||||
static void DrawGrid(const std::shared_ptr<ResourceTreeNode>& node) {
|
||||
const int columns = 4;
|
||||
int itemIndex = 0;
|
||||
|
||||
ImGui::BeginChild("FileGrid", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
|
||||
ImGui::Columns(columns, nullptr, false);
|
||||
|
||||
for (const auto& child : node->children) {
|
||||
std::string label = (child->isDirectory ? "[folder] " : "[file] ") + child->name;
|
||||
|
||||
if (ImGui::Selectable(label.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick, ImVec2(0, 64))) {
|
||||
if (child->isDirectory && ImGui::IsMouseDoubleClicked(0)) {
|
||||
s_CurrentPath = child->path;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::NextColumn();
|
||||
++itemIndex;
|
||||
}
|
||||
|
||||
ImGui::Columns(1);
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
static std::shared_ptr<ResourceTreeNode> FindNode(const std::shared_ptr<ResourceTreeNode>& root, const std::string& targetPath) {
|
||||
if (root->path == targetPath) return root;
|
||||
|
||||
for (const auto& child : root->children) {
|
||||
if (child->isDirectory) {
|
||||
auto found = FindNode(child, targetPath);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void FileBrowser::Draw() {
|
||||
ImGui::Begin("File Browser");
|
||||
|
||||
ImGui::Text("Current Path: %s", s_CurrentPath.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
auto root = AssetManager::GetFileTree();
|
||||
auto currentNode = FindNode(root, s_CurrentPath);
|
||||
if (currentNode) {
|
||||
DrawGrid(currentNode);
|
||||
} else {
|
||||
ImGui::Text("Path not found: %s", s_CurrentPath.c_str());
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
} // namespace OX
|
12
src/editor/Windows/FileBrowser.h
Normal file
12
src/editor/Windows/FileBrowser.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace OX {
|
||||
|
||||
class FileBrowser {
|
||||
public:
|
||||
static void Draw();
|
||||
};
|
||||
|
||||
} // namespace OX
|
37
src/editor/Windows/Viewport.cpp
Normal file
37
src/editor/Windows/Viewport.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#include "Viewport.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace OX
|
||||
{
|
||||
int Viewport::s_nextID = 0;
|
||||
|
||||
void Viewport::Draw(Core &core) const
|
||||
{
|
||||
// Construct title
|
||||
std::string title = m_name + " (" + std::to_string(m_id) + ")";
|
||||
|
||||
// Remove window padding
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
|
||||
// Begin full viewport window
|
||||
ImGui::Begin(title.c_str(), nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
|
||||
// Get size of available region
|
||||
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
||||
|
||||
// === Fullscreen image ===
|
||||
GLuint textureID = core.GetRenderer().GetRenderTarget(); // You must define this method
|
||||
if (textureID != 0) {
|
||||
ImGui::Image(textureID, viewportSize, ImVec2(0, 1), ImVec2(1, 0));
|
||||
} else {
|
||||
ImGui::Text("No Render Target.");
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
ImGui::PopStyleVar(); // Restore padding
|
||||
}
|
||||
};
|
36
src/editor/Windows/Viewport.h
Normal file
36
src/editor/Windows/Viewport.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// Created by spenc on 5/21/2025.
|
||||
//
|
||||
|
||||
#ifndef VIEWPORT_H
|
||||
#define VIEWPORT_H
|
||||
|
||||
#include <string>
|
||||
#include "Core.h"
|
||||
|
||||
namespace OX
|
||||
{
|
||||
class Viewport
|
||||
{
|
||||
public:
|
||||
explicit Viewport(std::string name = "Viewport")
|
||||
: m_name(std::move(name))
|
||||
{
|
||||
m_id = s_nextID++;
|
||||
}
|
||||
|
||||
void Draw(Core& core) const;
|
||||
|
||||
[[nodiscard]] int GetID() const { return m_id; }
|
||||
[[nodiscard]] const std::string& GetName() const { return m_name; }
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
std::string m_name;
|
||||
|
||||
static int s_nextID;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user