// src/Renderer.cpp #include "Renderer.h" #include #include #include Renderer::Renderer() = default; void Renderer::Initialize() { // Nothing specific for now; ensure GLAD is loaded before this call glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); } void Renderer::Shutdown() { // Cleanup if needed } void Renderer::BeginFrame() { stats_.draw_calls = 0; stats_.vertices_rendered = 0; stats_.triangles_rendered = 0; frame_start_time_ = GetTime(); } void Renderer::EndFrame() { float frame_end = GetTime(); stats_.frame_time = frame_end - frame_start_time_; } void Renderer::Clear(const glm::vec4& color) { glClearColor(color.r, color.g, color.b, color.a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } void Renderer::SetViewport(int x, int y, int width, int height) { viewport_size_ = { width, height }; glViewport(x, y, width, height); } void Renderer::SetCullFace(CullFace c) { if (c == CullFace::None) glDisable(GL_CULL_FACE); else { glEnable(GL_CULL_FACE); glCullFace(static_cast(c)); } current_cull_face_ = c; } void Renderer::SetBlendMode(BlendMode mode) { if (mode == BlendMode::None) { glDisable(GL_BLEND); } else { glEnable(GL_BLEND); switch (mode) { case BlendMode::Alpha: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; case BlendMode::Additive: glBlendFunc(GL_SRC_ALPHA, GL_ONE); break; case BlendMode::Multiply: glBlendFunc(GL_DST_COLOR, GL_ZERO); break; default: break; } } current_blend_mode_ = mode; } void Renderer::SetDepthTest(DepthTest dt) { if (dt == DepthTest::None) glDisable(GL_DEPTH_TEST); else { glEnable(GL_DEPTH_TEST); GLenum func = GL_LESS; switch (dt) { case DepthTest::Less: func = GL_LESS; break; case DepthTest::LessEqual: func = GL_LEQUAL; break; case DepthTest::Greater: func = GL_GREATER; break; case DepthTest::GreaterEqual:func = GL_GEQUAL; break; case DepthTest::Equal: func = GL_EQUAL; break; case DepthTest::NotEqual: func = GL_NOTEQUAL; break; case DepthTest::Always: func = GL_ALWAYS; break; case DepthTest::Never: func = GL_NEVER; break; default: break; } glDepthFunc(func); } current_depth_test_ = dt; } void Renderer::SetWireframe(bool enable) { glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL); wireframe_enabled_ = enable; } void Renderer::PrintRenderInfo() const { std::cout << "OpenGL Version: " << GetOpenGLVersion() << "\n"; std::cout << "Viewport: " << viewport_size_.x << "x" << viewport_size_.y << "\n"; std::cout << "Draw Calls: " << stats_.draw_calls << "\n"; std::cout << "Vertices: " << stats_.vertices_rendered << "\n"; std::cout << "Triangles: " << stats_.triangles_rendered << "\n"; } void Renderer::ResetStats() { stats_ = RenderStats{}; } std::string Renderer::GetOpenGLVersion() { return reinterpret_cast(glGetString(GL_VERSION)); } std::string Renderer::GetGPUInfo() { return reinterpret_cast(glGetString(GL_RENDERER)); } bool Renderer::CheckOpenGLError(const std::string& op) { GLenum err; bool hasError = false; while ((err = glGetError()) != GL_NO_ERROR) { std::cerr << "OpenGL Error"; if (!op.empty()) std::cerr << " in " << op; std::cerr << ": " << err << "\n"; hasError = true; } return !hasError; } float Renderer::GetTime() const { using clock = std::chrono::high_resolution_clock; return std::chrono::duration(clock::now().time_since_epoch()).count(); }