Compare commits
3 Commits
1a928159e5
...
f7e0882597
Author | SHA1 | Date | |
---|---|---|---|
|
f7e0882597 | ||
|
4194764d7a | ||
|
375af6829c |
@ -99,6 +99,7 @@ add_library(Core STATIC
|
|||||||
src/core/systems/Asset.h
|
src/core/systems/Asset.h
|
||||||
src/core/systems/assets/Texture2D.cpp
|
src/core/systems/assets/Texture2D.cpp
|
||||||
src/core/systems/assets/Texture2D.h
|
src/core/systems/assets/Texture2D.h
|
||||||
|
src/core/systems/Shader.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(Core PUBLIC src/core)
|
target_include_directories(Core PUBLIC src/core)
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "systems/MACROS.h"
|
#include "systems/MACROS.h"
|
||||||
#include "systems/AssetManager.h"
|
#include "systems/AssetManager.h"
|
||||||
|
#include "systems/assets/Texture2D.h"
|
||||||
|
|
||||||
namespace OX
|
namespace OX
|
||||||
{
|
{
|
||||||
@ -32,9 +33,7 @@ namespace OX
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (const auto &layer: m_layers) {
|
||||||
for (const auto &layer : m_layers) {
|
|
||||||
|
|
||||||
Logger::LogDebug("Initializing Layer: '%s'", layer->GetName().c_str());
|
Logger::LogDebug("Initializing Layer: '%s'", layer->GetName().c_str());
|
||||||
layer->Init(*this);
|
layer->Init(*this);
|
||||||
}
|
}
|
||||||
@ -42,6 +41,7 @@ namespace OX
|
|||||||
|
|
||||||
std::string fullTitle = layerTitle + " - " + m_name;
|
std::string fullTitle = layerTitle + " - " + m_name;
|
||||||
window.SetWindowTitle(fullTitle);
|
window.SetWindowTitle(fullTitle);
|
||||||
|
renderer.Init(800, 600);
|
||||||
|
|
||||||
Logger::LogOk("Core Initialization Complete.");
|
Logger::LogOk("Core Initialization Complete.");
|
||||||
|
|
||||||
@ -49,7 +49,6 @@ namespace OX
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Core::Run()
|
void Core::Run()
|
||||||
{
|
{
|
||||||
m_running = true;
|
m_running = true;
|
||||||
@ -80,6 +79,18 @@ namespace OX
|
|||||||
{
|
{
|
||||||
OX_PROFILE_FUNCTION();
|
OX_PROFILE_FUNCTION();
|
||||||
|
|
||||||
|
Camera2D cam(0, 800, 0, 600);
|
||||||
|
renderer.BeginScene(cam);
|
||||||
|
|
||||||
|
if (auto asset = AssetManager::Get("res://Assets/tile_001.png"); asset && asset->GetTypeName() == "texture2D") {
|
||||||
|
const auto tex = std::static_pointer_cast<Texture2D>(asset);
|
||||||
|
renderer.DrawSprite({tex->GetID(), {100, 100}, {64, 64}});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
renderer.EndScene();
|
||||||
|
|
||||||
|
|
||||||
for (auto &layer: m_layers) {
|
for (auto &layer: m_layers) {
|
||||||
layer->Draw(*this);
|
layer->Draw(*this);
|
||||||
|
@ -1,9 +1,194 @@
|
|||||||
//
|
// File: src/Renderer.cpp
|
||||||
// Created by spenc on 5/21/2025.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace OX {
|
namespace OX
|
||||||
|
{
|
||||||
|
// ——— Camera2D implementation (unchanged) ———
|
||||||
|
Camera2D::Camera2D(float left, float right, float bottom, float top)
|
||||||
|
: _left(left), _right(right), _bottom(bottom), _top(top)
|
||||||
|
{
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
} // OX
|
void Camera2D::SetPosition(const glm::vec2 &pos)
|
||||||
|
{
|
||||||
|
_position = pos;
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera2D::SetZoom(float z)
|
||||||
|
{
|
||||||
|
_zoom = z;
|
||||||
|
Recalculate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera2D::Recalculate()
|
||||||
|
{
|
||||||
|
float halfW = (_right - _left) * 0.5f / _zoom;
|
||||||
|
float halfH = (_top - _bottom) * 0.5f / _zoom;
|
||||||
|
glm::mat4 proj = glm::ortho(-halfW, halfW, -halfH, halfH, -1.0f, 1.0f);
|
||||||
|
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(-_position, 0.0f));
|
||||||
|
_viewProj = proj * view;
|
||||||
|
}
|
||||||
|
|
||||||
|
const glm::mat4 &Camera2D::GetViewProjection() const { return _viewProj; }
|
||||||
|
|
||||||
|
// ——— Renderer ———
|
||||||
|
Renderer::~Renderer()
|
||||||
|
{
|
||||||
|
if (m_quadVAO)
|
||||||
|
glDeleteVertexArrays(1, &m_quadVAO);
|
||||||
|
if (m_quadVBO)
|
||||||
|
glDeleteBuffers(1, &m_quadVBO);
|
||||||
|
if (m_fbo)
|
||||||
|
glDeleteFramebuffers(1, &m_fbo);
|
||||||
|
if (m_colorTex) glDeleteTextures(1, &m_colorTex);
|
||||||
|
if (m_depthRBO)
|
||||||
|
glDeleteRenderbuffers(1, &m_depthRBO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::Init(int targetWidth, int targetHeight)
|
||||||
|
{
|
||||||
|
// create offscreen FBO & attachments
|
||||||
|
CreateFramebuffer(targetWidth, targetHeight);
|
||||||
|
|
||||||
|
// compile our sprite shader
|
||||||
|
static const char *vs = R"GLSL(
|
||||||
|
#version 330 core
|
||||||
|
layout(location = 0) in vec2 aPos;
|
||||||
|
layout(location = 1) in vec2 aUV;
|
||||||
|
uniform mat4 u_ViewProj;
|
||||||
|
uniform vec2 u_Offset;
|
||||||
|
uniform vec2 u_Scale;
|
||||||
|
out vec2 vUV;
|
||||||
|
void main(){
|
||||||
|
vUV = aUV;
|
||||||
|
vec2 pos = aPos * u_Scale + u_Offset;
|
||||||
|
gl_Position = u_ViewProj * vec4(pos,0,1);
|
||||||
|
}
|
||||||
|
)GLSL";
|
||||||
|
static const char *fs = R"GLSL(
|
||||||
|
#version 330 core
|
||||||
|
in vec2 vUV;
|
||||||
|
out vec4 FragColor;
|
||||||
|
uniform sampler2D u_Texture;
|
||||||
|
void main(){
|
||||||
|
FragColor = texture(u_Texture, vUV);
|
||||||
|
}
|
||||||
|
)GLSL";
|
||||||
|
|
||||||
|
m_shader.LoadFromSource(vs, fs);
|
||||||
|
|
||||||
|
CreateQuad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::CreateFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
|
size = {width, height};
|
||||||
|
|
||||||
|
// cleanup old
|
||||||
|
if (m_fbo)
|
||||||
|
glDeleteFramebuffers(1, &m_fbo);
|
||||||
|
if (m_colorTex) glDeleteTextures(1, &m_colorTex);
|
||||||
|
if (m_depthRBO)
|
||||||
|
glDeleteRenderbuffers(1, &m_depthRBO);
|
||||||
|
|
||||||
|
// color texture
|
||||||
|
glGenTextures(1, &m_colorTex);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, m_colorTex);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
|
||||||
|
0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
// depth renderbuffer
|
||||||
|
glGenRenderbuffers(1, &m_depthRBO);
|
||||||
|
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRBO);
|
||||||
|
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||||
|
|
||||||
|
// framebuffer
|
||||||
|
glGenFramebuffers(1, &m_fbo);
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
GL_TEXTURE_2D, m_colorTex, 0);
|
||||||
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||||
|
GL_RENDERBUFFER, m_depthRBO);
|
||||||
|
|
||||||
|
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
std::cerr << "[Renderer] Framebuffer not complete!\n";
|
||||||
|
|
||||||
|
// unbind
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::ResizeTarget(int width, int height)
|
||||||
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
|
if (size == Vec2i{width, height}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CreateFramebuffer(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::BeginScene(const Camera2D &camera)
|
||||||
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
|
// bind offscreen
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
|
||||||
|
// clear
|
||||||
|
glViewport(0, 0, size.x, size.y);
|
||||||
|
glClearColor(0.1f, 0.1f, 0.1f, 1);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
// setup shader & camera
|
||||||
|
m_viewProj = camera.GetViewProjection();
|
||||||
|
m_shader.Use();
|
||||||
|
m_shader.SetMat4("u_ViewProj", m_viewProj);
|
||||||
|
m_shader.SetInt("u_Texture", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::DrawSprite(const Sprite &s)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, s.textureID);
|
||||||
|
|
||||||
|
m_shader.SetVec2("u_Offset", s.position);
|
||||||
|
m_shader.SetVec2("u_Scale", s.size);
|
||||||
|
|
||||||
|
glBindVertexArray(m_quadVAO);
|
||||||
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::EndScene()
|
||||||
|
{
|
||||||
|
// unbind FBO → subsequent draws go to default framebuffer
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::CreateQuad()
|
||||||
|
{
|
||||||
|
float verts[] = {
|
||||||
|
-0.5f, -0.5f, 0, 0,
|
||||||
|
0.5f, -0.5f, 1, 0,
|
||||||
|
0.5f, 0.5f, 1, 1,
|
||||||
|
-0.5f, 0.5f, 0, 1
|
||||||
|
};
|
||||||
|
unsigned int idx[] = {0, 1, 2, 2, 3, 0};
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &m_quadVAO);
|
||||||
|
glGenBuffers(1, &m_quadVBO);
|
||||||
|
|
||||||
|
glBindVertexArray(m_quadVAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 2,GL_FLOAT,GL_FALSE, 4 * sizeof(float), (void *) 0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 2,GL_FLOAT,GL_FALSE, 4 * sizeof(float), (void *) (2 * sizeof(float)));
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
} // namespace OX
|
||||||
|
@ -1,26 +1,74 @@
|
|||||||
//
|
// File: src/Renderer.h
|
||||||
// Created by spenc on 5/21/2025.
|
#pragma once
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef RENDERER_H
|
|
||||||
#define RENDERER_H
|
|
||||||
|
|
||||||
#include "glfw/glfw3.h"
|
|
||||||
#include "glm/glm.hpp"
|
#include "glm/glm.hpp"
|
||||||
|
#include "systems/Shader.h"
|
||||||
|
#include <gl/glew.h>
|
||||||
|
#include "types/vec2.h"
|
||||||
namespace OX {
|
namespace OX {
|
||||||
|
|
||||||
class Renderer {
|
struct Sprite {
|
||||||
public:
|
GLuint textureID;
|
||||||
Renderer() = default;
|
glm::vec2 position;
|
||||||
~Renderer() = default;
|
glm::vec2 size;
|
||||||
|
};
|
||||||
|
|
||||||
[[nodiscard]] GLuint GetRenderTarget() const {return m_renderTarget; }
|
class Camera2D {
|
||||||
|
public:
|
||||||
|
Camera2D(float left, float right, float bottom, float top);
|
||||||
|
void SetPosition(const glm::vec2& pos);
|
||||||
|
void SetZoom(float zoom);
|
||||||
|
const glm::mat4& GetViewProjection() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLuint m_renderTarget;
|
void Recalculate();
|
||||||
};
|
glm::vec2 _position{0.0f};
|
||||||
|
float _zoom{1.0f};
|
||||||
|
float _left, _right, _bottom, _top;
|
||||||
|
glm::mat4 _viewProj{1.0f};
|
||||||
|
};
|
||||||
|
|
||||||
} // OX
|
class Renderer {
|
||||||
|
public:
|
||||||
|
Renderer() = default;
|
||||||
|
~Renderer();
|
||||||
|
|
||||||
#endif //RENDERER_H
|
/// Must call once after OpenGL context + GLEW init.
|
||||||
|
/// Provide the desired offscreen target size here.
|
||||||
|
void Init(int targetWidth, int targetHeight);
|
||||||
|
|
||||||
|
/// Call at start of each scene (binds FBO and sets camera).
|
||||||
|
void BeginScene(const Camera2D& camera);
|
||||||
|
|
||||||
|
/// Draw one sprite into the current scene.
|
||||||
|
void DrawSprite(const Sprite& sprite);
|
||||||
|
|
||||||
|
/// Finish rendering, unbinds FBO.
|
||||||
|
void EndScene();
|
||||||
|
|
||||||
|
/// Access the color‐attachment texture ID that holds the rendered scene.
|
||||||
|
GLuint GetRenderTexture() const { return m_colorTex; }
|
||||||
|
|
||||||
|
/// If window resized, call this to resize the offscreen target.
|
||||||
|
void ResizeTarget(int width, int height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// offscreen
|
||||||
|
Vec2i size;
|
||||||
|
GLuint m_fbo = 0;
|
||||||
|
GLuint m_colorTex = 0;
|
||||||
|
GLuint m_depthRBO = 0;
|
||||||
|
|
||||||
|
// quad geometry
|
||||||
|
GLuint m_quadVAO = 0, m_quadVBO = 0;
|
||||||
|
|
||||||
|
// shader
|
||||||
|
Shader m_shader;
|
||||||
|
glm::mat4 m_viewProj{1.0f};
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
void CreateQuad();
|
||||||
|
void CreateFramebuffer(int width, int height);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace OX
|
||||||
|
@ -18,6 +18,7 @@ namespace OX
|
|||||||
// Map from actual file path to virtual ID
|
// Map from actual file path to virtual ID
|
||||||
std::unordered_map<std::string, std::string> AssetManager::s_PathToID;
|
std::unordered_map<std::string, std::string> AssetManager::s_PathToID;
|
||||||
std::mutex AssetManager::s_AssetMutex;
|
std::mutex AssetManager::s_AssetMutex;
|
||||||
|
std::mutex AssetManager::s_TreeMutex;
|
||||||
|
|
||||||
std::shared_ptr<ResourceTreeNode> AssetManager::s_FileTree = std::make_shared<ResourceTreeNode>();
|
std::shared_ptr<ResourceTreeNode> AssetManager::s_FileTree = std::make_shared<ResourceTreeNode>();
|
||||||
|
|
||||||
@ -96,7 +97,7 @@ namespace OX
|
|||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(s_AssetMutex);
|
std::lock_guard<std::mutex> lock(s_AssetMutex);
|
||||||
// now fill in the real metadata
|
// now fill in the real metadata
|
||||||
s_MetadataMap[resPath] = { type, path.string() };
|
s_MetadataMap[resPath] = {type, path.string()};
|
||||||
}
|
}
|
||||||
std::lock_guard<std::mutex> qlock(s_QueueMutex);
|
std::lock_guard<std::mutex> qlock(s_QueueMutex);
|
||||||
s_TextureQueue.push({resPath, w, h, ch, data});
|
s_TextureQueue.push({resPath, w, h, ch, data});
|
||||||
@ -138,7 +139,6 @@ namespace OX
|
|||||||
// Also map original file path to this ID
|
// Also map original file path to this ID
|
||||||
auto meta = s_MetadataMap[pending.id];
|
auto meta = s_MetadataMap[pending.id];
|
||||||
s_PathToID[meta.absolutePath] = pending.id;
|
s_PathToID[meta.absolutePath] = pending.id;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,6 +224,7 @@ namespace OX
|
|||||||
pos = next + 1;
|
pos = next + 1;
|
||||||
}
|
}
|
||||||
if (pos < resPath.size()) parts.push_back(resPath.substr(pos));
|
if (pos < resPath.size()) parts.push_back(resPath.substr(pos));
|
||||||
|
std::lock_guard<std::mutex> lock(AssetManager::s_TreeMutex);
|
||||||
|
|
||||||
auto current = s_FileTree;
|
auto current = s_FileTree;
|
||||||
for (size_t i = 1; i < parts.size(); ++i) {
|
for (size_t i = 1; i < parts.size(); ++i) {
|
||||||
|
@ -37,6 +37,9 @@ namespace OX {
|
|||||||
static std::shared_ptr<ResourceTreeNode> GetFileTree();
|
static std::shared_ptr<ResourceTreeNode> GetFileTree();
|
||||||
static void SaveAssetPack(const std::string& outputPath);
|
static void SaveAssetPack(const std::string& outputPath);
|
||||||
|
|
||||||
|
static std::mutex s_TreeMutex;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct AssetMetadata {
|
struct AssetMetadata {
|
||||||
std::string type;
|
std::string type;
|
||||||
@ -69,6 +72,6 @@ namespace OX {
|
|||||||
|
|
||||||
// texture upload queue
|
// texture upload queue
|
||||||
static std::queue<PendingTexture> s_TextureQueue;
|
static std::queue<PendingTexture> s_TextureQueue;
|
||||||
static std::mutex s_QueueMutex;
|
static std::mutex s_QueueMutex;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
180
src/core/systems/Shader.cpp
Normal file
180
src/core/systems/Shader.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#include "Shader.h"
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include "systems/Logger.h"
|
||||||
|
|
||||||
|
namespace OX
|
||||||
|
{
|
||||||
|
|
||||||
|
Shader::Shader(const std::string &vertexPath, const std::string &fragmentPath)
|
||||||
|
{
|
||||||
|
LoadFromFiles(vertexPath, fragmentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Shader::LoadFromFiles(const std::string &vertexPath, const std::string &fragmentPath)
|
||||||
|
{
|
||||||
|
m_vertexPath = vertexPath;
|
||||||
|
m_fragmentPath = fragmentPath;
|
||||||
|
|
||||||
|
std::string vertexSrc = ReadFile(vertexPath);
|
||||||
|
std::string fragmentSrc = ReadFile(fragmentPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_vertTimestamp = std::filesystem::last_write_time(vertexPath);
|
||||||
|
m_fragTimestamp = std::filesystem::last_write_time(fragmentPath);
|
||||||
|
} catch (...) {
|
||||||
|
std::cerr << "[Shader] Warning: Could not get file timestamps.\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return LoadFromSource(vertexSrc, fragmentSrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Shader::LoadFromSource(const std::string &vertexSrc, const std::string &fragmentSrc)
|
||||||
|
{
|
||||||
|
GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSrc);
|
||||||
|
GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSrc);
|
||||||
|
|
||||||
|
if (!vertexShader || !fragmentShader) return false;
|
||||||
|
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
glAttachShader(program, vertexShader);
|
||||||
|
glAttachShader(program, fragmentShader);
|
||||||
|
glLinkProgram(program);
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
char info[512];
|
||||||
|
glGetProgramInfoLog(program, 512, nullptr, info);
|
||||||
|
std::cerr << "[Shader] Linking failed:\n" << info << '\n';
|
||||||
|
glDeleteProgram(program);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_programID)
|
||||||
|
glDeleteProgram(m_programID);
|
||||||
|
|
||||||
|
m_programID = program;
|
||||||
|
m_uniformCache.clear();
|
||||||
|
|
||||||
|
glDeleteShader(vertexShader);
|
||||||
|
glDeleteShader(fragmentShader);
|
||||||
|
Logger::LogOk("Shader Loaded (%s,%s)", m_vertexPath.c_str(), m_fragmentPath.c_str());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::Reload()
|
||||||
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
|
LoadFromFiles(m_vertexPath, m_fragmentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::Use() const
|
||||||
|
{
|
||||||
|
glUseProgram(m_programID);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint Shader::CompileShader(GLenum type, const std::string &source)
|
||||||
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
const char *src = source.c_str();
|
||||||
|
glShaderSource(shader, 1, &src, nullptr);
|
||||||
|
glCompileShader(shader);
|
||||||
|
|
||||||
|
GLint success;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||||
|
if (!success) {
|
||||||
|
char info[512];
|
||||||
|
glGetShaderInfoLog(shader, 512, nullptr, info);
|
||||||
|
|
||||||
|
Logger::LogError("Failed to Compile Shader '%s', '%s'", m_fragmentPath.c_str(), info);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::CheckHotReload()
|
||||||
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
|
|
||||||
|
if (m_vertexPath.empty() || m_fragmentPath.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
OX_PROFILE_LABEL("Get Write Time");
|
||||||
|
auto vertTime = std::filesystem::last_write_time(m_vertexPath);
|
||||||
|
auto fragTime = std::filesystem::last_write_time(m_fragmentPath);
|
||||||
|
|
||||||
|
if (vertTime != m_vertTimestamp || fragTime != m_fragTimestamp) {
|
||||||
|
std::cout << "[Shader] Reloading shader: " << m_vertexPath << " / " << m_fragmentPath << "\n";
|
||||||
|
Reload();
|
||||||
|
}
|
||||||
|
} catch (const std::exception &e) {
|
||||||
|
Logger::LogError("Failed to Reload Shader '%s', %s", m_vertexPath.c_str(), e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string Shader::ReadFile(const std::string &path)
|
||||||
|
{
|
||||||
|
if (!std::filesystem::exists(path)) {
|
||||||
|
std::ofstream file(path, std::ios::app);
|
||||||
|
}
|
||||||
|
std::ifstream file(path);
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << file.rdbuf();
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint Shader::GetUniformLocation(const std::string &name)
|
||||||
|
{
|
||||||
|
if (m_uniformCache.contains(name))
|
||||||
|
return m_uniformCache[name];
|
||||||
|
|
||||||
|
GLint location = glGetUniformLocation(m_programID, name.c_str());
|
||||||
|
m_uniformCache[name] = location;
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetInt(const std::string &name, int value)
|
||||||
|
{
|
||||||
|
glUniform1i(GetUniformLocation(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetFloat(const std::string &name, float value)
|
||||||
|
{
|
||||||
|
glUniform1f(GetUniformLocation(name), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetVec2(const std::string &name, const glm::vec2 &value)
|
||||||
|
{
|
||||||
|
glUniform2fv(GetUniformLocation(name), 1, &value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetVec3(const std::string &name, const glm::vec3 &value)
|
||||||
|
{
|
||||||
|
glUniform3fv(GetUniformLocation(name), 1, &value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetVec4(const std::string &name, const glm::vec4 &value)
|
||||||
|
{
|
||||||
|
glUniform4fv(GetUniformLocation(name), 1, &value[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::SetMat4(const std::string &name, const glm::mat4 &value)
|
||||||
|
{
|
||||||
|
glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, &value[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Shader::SetBool(const std::string &name, bool value)
|
||||||
|
{
|
||||||
|
glUniform1i(GetUniformLocation(name), (int) value);
|
||||||
|
}
|
||||||
|
}
|
61
src/core/systems/Shader.h
Normal file
61
src/core/systems/Shader.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <GL/glew.h>
|
||||||
|
#include <filesystem>
|
||||||
|
#include "systems/Profiler.h"
|
||||||
|
|
||||||
|
namespace OX
|
||||||
|
{
|
||||||
|
class Shader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Shader() = default;
|
||||||
|
|
||||||
|
Shader(const std::string &vertexPath, const std::string &fragmentPath);
|
||||||
|
|
||||||
|
bool LoadFromFiles(const std::string &vertexPath, const std::string &fragmentPath);
|
||||||
|
|
||||||
|
bool LoadFromSource(const std::string &vertexSrc, const std::string &fragmentSrc);
|
||||||
|
|
||||||
|
void Reload();
|
||||||
|
|
||||||
|
void Use() const;
|
||||||
|
|
||||||
|
void CheckHotReload();
|
||||||
|
|
||||||
|
GLuint GetID() const { return m_programID; }
|
||||||
|
|
||||||
|
void SetInt(const std::string &name, int value);
|
||||||
|
|
||||||
|
void SetFloat(const std::string &name, float value);
|
||||||
|
|
||||||
|
void SetVec2(const std::string &name, const glm::vec2 &value);
|
||||||
|
|
||||||
|
void SetVec3(const std::string &name, const glm::vec3 &value);
|
||||||
|
|
||||||
|
void SetVec4(const std::string &name, const glm::vec4 &value);
|
||||||
|
|
||||||
|
void SetMat4(const std::string &name, const glm::mat4 &value);
|
||||||
|
|
||||||
|
void SetBool(const std::string &name, const bool value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint m_programID = 0;
|
||||||
|
std::string m_vertexPath;
|
||||||
|
std::string m_fragmentPath;
|
||||||
|
|
||||||
|
std::unordered_map<std::string, GLint> m_uniformCache;
|
||||||
|
|
||||||
|
std::filesystem::file_time_type m_vertTimestamp;
|
||||||
|
std::filesystem::file_time_type m_fragTimestamp;
|
||||||
|
|
||||||
|
GLuint CompileShader(GLenum type, const std::string &source);
|
||||||
|
|
||||||
|
std::string ReadFile(const std::string &path);
|
||||||
|
|
||||||
|
GLint GetUniformLocation(const std::string &name);
|
||||||
|
};
|
||||||
|
}
|
@ -146,7 +146,7 @@ namespace OX
|
|||||||
|
|
||||||
// --- Render ImGui onto FBO 0 ---
|
// --- Render ImGui onto FBO 0 ---
|
||||||
{
|
{
|
||||||
OX_PROFILE_LABEL("VSYNC Wait");
|
|
||||||
|
|
||||||
ImGui::EndFrame();
|
ImGui::EndFrame();
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// File: src/FileBrowser.cpp
|
// File: src/FileBrowser.cpp
|
||||||
#include "FileBrowser.h"
|
#include "FileBrowser.h"
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include "systems/Profiler.h"
|
||||||
|
|
||||||
namespace OX
|
namespace OX
|
||||||
{
|
{
|
||||||
@ -13,6 +14,7 @@ namespace OX
|
|||||||
|
|
||||||
void FileBrowser::Draw(const char *title)
|
void FileBrowser::Draw(const char *title)
|
||||||
{
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
ImGui::Begin(title);
|
ImGui::Begin(title);
|
||||||
|
|
||||||
// --- toolbar now contains back button, inline path, filter & view toggle all on one row ---
|
// --- toolbar now contains back button, inline path, filter & view toggle all on one row ---
|
||||||
@ -86,6 +88,7 @@ namespace OX
|
|||||||
// ——— Polished grid view ———
|
// ——— Polished grid view ———
|
||||||
void FileBrowser::DrawGridView(const std::shared_ptr<ResourceTreeNode> &node)
|
void FileBrowser::DrawGridView(const std::shared_ptr<ResourceTreeNode> &node)
|
||||||
{
|
{
|
||||||
|
OX_PROFILE_FUNCTION();
|
||||||
const float cellW = _cfg.thumbnailSize + _cfg.padding * 2;
|
const float cellW = _cfg.thumbnailSize + _cfg.padding * 2;
|
||||||
ImVec2 avail = ImGui::GetContentRegionAvail();
|
ImVec2 avail = ImGui::GetContentRegionAvail();
|
||||||
int cols = std::max(1, int(avail.x / cellW));
|
int cols = std::max(1, int(avail.x / cellW));
|
||||||
@ -93,9 +96,15 @@ namespace OX
|
|||||||
ImGui::BeginChild("GridRegion", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
|
ImGui::BeginChild("GridRegion", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
|
||||||
ImGui::Columns(cols, nullptr, false);
|
ImGui::Columns(cols, nullptr, false);
|
||||||
|
|
||||||
for (auto &c: node->children) {
|
std::vector<std::shared_ptr<ResourceTreeNode> > children; {
|
||||||
if (!_filter.empty() && !PassesFilter(c->name)) continue;
|
std::lock_guard<std::mutex> lock(AssetManager::s_TreeMutex); // assume you add this mutex
|
||||||
|
children = node->children;
|
||||||
|
}
|
||||||
|
for (auto &c: children) {
|
||||||
if (!c) return;
|
if (!c) return;
|
||||||
|
|
||||||
|
if (!_filter.empty() && !PassesFilter(c->name)) continue;
|
||||||
|
|
||||||
ImGui::PushID(c->path.c_str());
|
ImGui::PushID(c->path.c_str());
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ namespace OX
|
|||||||
{
|
{
|
||||||
// Construct title
|
// Construct title
|
||||||
std::string title = m_name + " (" + std::to_string(m_id) + ")";
|
std::string title = m_name + " (" + std::to_string(m_id) + ")";
|
||||||
|
GLuint textureID = core.GetRenderer().GetRenderTexture(); // You must define this method
|
||||||
|
|
||||||
|
|
||||||
// Remove window padding
|
// Remove window padding
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||||
@ -24,14 +26,17 @@ namespace OX
|
|||||||
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
// === Fullscreen image ===
|
// === Fullscreen image ===
|
||||||
GLuint textureID = core.GetRenderer().GetRenderTarget(); // You must define this method
|
|
||||||
if (textureID != 0) {
|
if (textureID != 0) {
|
||||||
ImGui::Image(textureID, viewportSize, ImVec2(0, 1), ImVec2(1, 0));
|
ImGui::Image(textureID, viewportSize, ImVec2(0, 1), ImVec2(1, 0));
|
||||||
} else {
|
} else {
|
||||||
ImGui::Text("No Render Target.");
|
ImGui::Text("No Render Target.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
ImGui::PopStyleVar(); // Restore padding
|
ImGui::PopStyleVar(); // Restore padding
|
||||||
|
|
||||||
|
core.GetRenderer().ResizeTarget(viewportSize.x, viewportSize.y);
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user