Improves renderer and adds shader support

Adds shader class to core and modifies the renderer to use it,
while also adding profiling macros and fixing resize issues.
The changes ensure the render target is resized only when the
requested size is different from the current size and also clears
the screen to a dark gray color.
This commit is contained in:
OusmBlueNinja 2025-05-21 22:05:10 -05:00
parent 4194764d7a
commit f7e0882597
6 changed files with 149 additions and 114 deletions

View File

@ -99,6 +99,7 @@ add_library(Core STATIC
src/core/systems/Asset.h
src/core/systems/assets/Texture2D.cpp
src/core/systems/assets/Texture2D.h
src/core/systems/Shader.cpp
)
target_include_directories(Core PUBLIC src/core)

View File

@ -3,41 +3,59 @@
#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();
}
// ——— Camera2D implementation (unchanged) ———
Camera2D::Camera2D(float left, float right, float bottom, float top)
: _left(left), _right(right), _bottom(bottom), _top(top)
{ Recalculate(); }
void Camera2D::SetPosition(const glm::vec2 &pos)
{
_position = pos;
Recalculate();
}
void Camera2D::SetPosition(const glm::vec2& pos) { _position = pos; Recalculate(); }
void Camera2D::SetZoom(float z) { _zoom = z; 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;
}
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; }
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);
}
// ——— 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);
void Renderer::Init(int targetWidth, int targetHeight)
{
// create offscreen FBO & attachments
CreateFramebuffer(targetWidth, targetHeight);
// compile our sprite shader
static const char* vs = R"GLSL(
// 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;
@ -51,7 +69,7 @@ void Renderer::Init(int targetWidth, int targetHeight) {
gl_Position = u_ViewProj * vec4(pos,0,1);
}
)GLSL";
static const char* fs = R"GLSL(
static const char *fs = R"GLSL(
#version 330 core
in vec2 vUV;
out vec4 FragColor;
@ -61,102 +79,116 @@ void Renderer::Init(int targetWidth, int targetHeight) {
}
)GLSL";
m_shader.LoadFromSource(vs, fs);
m_shader.LoadFromSource(vs, fs);
CreateQuad();
}
CreateQuad();
}
void Renderer::CreateFramebuffer(int width, int height) {
// cleanup old
if (m_fbo) glDeleteFramebuffers(1, &m_fbo);
if (m_colorTex) glDeleteTextures(1, &m_colorTex);
if (m_depthRBO) glDeleteRenderbuffers(1, &m_depthRBO);
void Renderer::CreateFramebuffer(int width, int height)
{
size = {width, height};
// 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);
// cleanup old
if (m_fbo)
glDeleteFramebuffers(1, &m_fbo);
if (m_colorTex) glDeleteTextures(1, &m_colorTex);
if (m_depthRBO)
glDeleteRenderbuffers(1, &m_depthRBO);
// depth renderbuffer
glGenRenderbuffers(1, &m_depthRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// 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);
// 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);
// depth renderbuffer
glGenRenderbuffers(1, &m_depthRBO);
glBindRenderbuffer(GL_RENDERBUFFER, m_depthRBO);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cerr << "[Renderer] Framebuffer not complete!\n";
// 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);
// unbind
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cerr << "[Renderer] Framebuffer not complete!\n";
void Renderer::ResizeTarget(int width, int height) {
CreateFramebuffer(width, height);
}
// unbind
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
void Renderer::BeginScene(const Camera2D& camera) {
// bind offscreen
glBindFramebuffer(GL_FRAMEBUFFER, m_fbo);
// clear
glViewport(0, 0, /*width*/0, /*height*/0); // you may want to track size
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
void Renderer::ResizeTarget(int width, int height)
{
OX_PROFILE_FUNCTION();
if (size == Vec2i{width, height}) {
return;
}
CreateFramebuffer(width, height);
}
// 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::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);
void Renderer::DrawSprite(const Sprite& s) {
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, s.textureID);
// setup shader & camera
m_viewProj = camera.GetViewProjection();
m_shader.Use();
m_shader.SetMat4("u_ViewProj", m_viewProj);
m_shader.SetInt("u_Texture", 0);
}
m_shader.SetVec2("u_Offset", s.position);
m_shader.SetVec2("u_Scale", s.size);
void Renderer::DrawSprite(const Sprite &s)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, s.textureID);
glBindVertexArray(m_quadVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}
m_shader.SetVec2("u_Offset", s.position);
m_shader.SetVec2("u_Scale", s.size);
void Renderer::EndScene() {
// unbind FBO → subsequent draws go to default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glBindVertexArray(m_quadVAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr);
}
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};
void Renderer::EndScene()
{
// unbind FBO → subsequent draws go to default framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
glGenVertexArrays(1, &m_quadVAO);
glGenBuffers(1, &m_quadVBO);
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};
glBindVertexArray(m_quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glGenVertexArrays(1, &m_quadVAO);
glGenBuffers(1, &m_quadVBO);
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(m_quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, m_quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW);
glBindVertexArray(0);
}
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

View File

@ -4,7 +4,7 @@
#include "glm/glm.hpp"
#include "systems/Shader.h"
#include <gl/glew.h>
#include "types/vec2.h"
namespace OX {
struct Sprite {
@ -54,6 +54,7 @@ namespace OX {
private:
// offscreen
Vec2i size;
GLuint m_fbo = 0;
GLuint m_colorTex = 0;
GLuint m_depthRBO = 0;

View File

@ -24,7 +24,7 @@ namespace OX
void Use() const;
void CheckHotReload(); // 🔥
void CheckHotReload();
GLuint GetID() const { return m_programID; }

View File

@ -146,7 +146,7 @@ namespace OX
// --- Render ImGui onto FBO 0 ---
{
OX_PROFILE_LABEL("VSYNC Wait");
ImGui::EndFrame();
ImGui::Render();

View File

@ -1,6 +1,7 @@
// File: src/FileBrowser.cpp
#include "FileBrowser.h"
#include <filesystem>
#include "systems/Profiler.h"
namespace OX
{
@ -13,6 +14,7 @@ namespace OX
void FileBrowser::Draw(const char *title)
{
OX_PROFILE_FUNCTION();
ImGui::Begin(title);
// --- toolbar now contains back button, inline path, filter & view toggle all on one row ---
@ -86,6 +88,7 @@ namespace OX
// ——— Polished grid view ———
void FileBrowser::DrawGridView(const std::shared_ptr<ResourceTreeNode> &node)
{
OX_PROFILE_FUNCTION();
const float cellW = _cfg.thumbnailSize + _cfg.padding * 2;
ImVec2 avail = ImGui::GetContentRegionAvail();
int cols = std::max(1, int(avail.x / cellW));
@ -93,13 +96,11 @@ namespace OX
ImGui::BeginChild("GridRegion", ImVec2(0, 0), false, ImGuiWindowFlags_AlwaysUseWindowPadding);
ImGui::Columns(cols, nullptr, false);
std::vector<std::shared_ptr<ResourceTreeNode> > children;
{
std::vector<std::shared_ptr<ResourceTreeNode> > children; {
std::lock_guard<std::mutex> lock(AssetManager::s_TreeMutex); // assume you add this mutex
children = node->children;
}
for (auto& c : children) {
for (auto &c: children) {
if (!c) return;
if (!_filter.empty() && !PassesFilter(c->name)) continue;