← Back to file list Raw

src/COpenGL430Renderer.cpp

#include "COpenGL430Renderer.h"
#include "CEngine.h"
#include "CLogger.h"
#include "CWindowManager.h"
#include "U_General.h"
#include "U_Log.h"
#include "U_Files.h"
#include "CGL430Drawable.h"
#include "CConVarManager.h"
#include "CWrapable.h"
#include <boost/stacktrace.hpp>
COpenGL430Renderer::COpenGL430Renderer()
{
}
COpenGL430Renderer::~COpenGL430Renderer()
{
if(Context)
{
SDL_GL_DestroyContext(Context);
Context = nullptr;
}
}
void GLAPIENTRY debugMessageCallback(
GLenum source,
GLenum type,
GLuint id,
GLenum severity,
GLsizei length,
const GLchar* message,
const void* userParam
)
{
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) { return; }
auto& log = std::cout;
log << "OpenGL Debug Message:\n";
log << " Source: ";
switch (source)
{
case GL_DEBUG_SOURCE_API: log << "API"; break;
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: log << "Window System"; break;
case GL_DEBUG_SOURCE_SHADER_COMPILER: log << "Shader Compiler"; break;
case GL_DEBUG_SOURCE_THIRD_PARTY: log << "Third Party"; break;
case GL_DEBUG_SOURCE_APPLICATION: log << "Application"; break;
case GL_DEBUG_SOURCE_OTHER: log << "Other"; break;
default: log << "Unknown (0x" << std::hex << source << ")"; break;
}
log << "\n";
log << " Type: ";
switch (type)
{
case GL_DEBUG_TYPE_ERROR: log << "Error"; break;
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: log << "Deprecated Behavior"; break;
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: log << "Undefined Behavior"; break;
case GL_DEBUG_TYPE_PORTABILITY: log << "Portability"; break;
case GL_DEBUG_TYPE_PERFORMANCE: log << "Performance"; break;
case GL_DEBUG_TYPE_MARKER: log << "Marker"; break;
case GL_DEBUG_TYPE_PUSH_GROUP: log << "Push Group"; break;
case GL_DEBUG_TYPE_POP_GROUP: log << "Pop Group"; break;
case GL_DEBUG_TYPE_OTHER: log << "Other"; break;
default: log << "Unknown (0x" << std::hex << type << ")"; break;
}
log << "\n";
log << " Severity: ";
switch (severity)
{
case GL_DEBUG_SEVERITY_HIGH: log << "High"; break;
case GL_DEBUG_SEVERITY_MEDIUM: log << "Medium"; break;
case GL_DEBUG_SEVERITY_LOW: log << "Low"; break;
case GL_DEBUG_SEVERITY_NOTIFICATION: log << "Notification"; break;
default: log << "Unknown(0x" << std::hex << severity << ")"; break;
}
log << "\n";
log << " ID: 0x" << std::hex << id << "\n";
log << " Message: " << message << "\n\n";
//std::cout << "stacktrace:\n";
//std::cout << boost::stacktrace::stacktrace();
//std::cout << std::endl;
}
void COpenGL430Renderer::BindMaterialsSSBO(GLuint binding)
{
m_MaterialsSSBO.Bind();
}
void COpenGL430Renderer::Init(SDL_Window* window)
{
COMPONENT_CALL(CConVarManager, AddConVar("forcereupload", new CWrapable<bool>(false)));
Log::Instance() << "COpenGL430Renderer::Init\n";
Window = window;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
Context = SDL_GL_CreateContext(window);
SDL_GL_MakeCurrent(Window, Context);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
SDL_GL_SetSwapInterval(0); //TODO toggle vsync ability
glewExperimental = true;
if (glewInit() != GLEW_OK) { COMPONENT_CALL(CLogger, Err(L"Can't initialize GLEW. Rendering will not be possible.")); }
glEnable(GL_DEBUG_OUTPUT);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
glDebugMessageCallback(debugMessageCallback, nullptr);
glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE);
GLint flags;
glGetIntegerv(GL_CONTEXT_FLAGS, &flags);
if (flags & GL_CONTEXT_FLAG_DEBUG_BIT)
{
std::cout << "Debug Context is active\n";
}
else
{
std::cout << "Debug Context is NOT active\n";
}
//TODO this entire block code below is temporary
glEnable(GL_DEPTH_TEST);
//glEnable(GL_TEXTURE_2D);
glClearColor(0.0f, 0.1f, 0.1f, 0.0f);
glClearDepth(1.0);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
//glBlendFuncSeparate(GL_ONE, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
//glBlendEquation(GL_FUNC_ADD);
glm::ivec2 winsize;
COMPONENT_CALL_GET(winsize, CWindowManager, GetWindowSize());
glViewport(0, 0, winsize.x, winsize.y);
auto file_vs = FileUtils::find_first_by_name(FileUtils::get_executable_path() / "resources" / "shaders", "default.vs");
auto file_fs = FileUtils::find_first_by_name(FileUtils::get_executable_path() / "resources" / "shaders", "default.fs");
Log::Instance() << "Vertex shader is \"" << file_vs.value().string() << "\"\n";
Log::Instance() << "Fragment shader is \"" << file_fs.value().string() << "\"\n";
if(file_vs.has_value() && file_fs.has_value()) { S_Default.LoadFromFile(file_vs.value().string(), file_fs.value().string()); }
else { Log::ErrInstance() << "Renderer couldn't load default shaders\n"; }
//S_Default.LoadFromFile("default.vs", "default.fs"); //TODO hardcoded and no filesystem paths
//S_Default.LoadFromFile("resources\\shaders\\default.vs", "resources\\shaders\\default.fs");
S_Default.Bind();
constexpr size_t MaterialsAmount = 2048;
m_Materials.resize(MaterialsAmount); //TODO hardcoded materials amount
m_MaterialsSSBO.Create(MaterialsAmount * sizeof(CMaterialGPU), GL_DYNAMIC_DRAW, 3);
m_MaterialsSSBO.ReflectStructArray(S_Default.GetShaderID(), "MaterialBuffer", "materials");
m_MaterialsSSBO.Bind();
}
void COpenGL430Renderer::Display()
{
SDL_GL_SwapWindow(Window);
}
void COpenGL430Renderer::ClearWindow()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //TODO does color buffer need to be cleared?
}
size_t COpenGL430Renderer::GetGenericFlag() const
{
return SDL_WINDOW_OPENGL;
}
int COpenGL430Renderer::GetFreeMaterialIndex()
{
for(int i = 0; i < m_Materials.size(); i++)
{
if(!m_Materials.at(i)) { return i; }
}
return -1;
}
void COpenGL430Renderer::RegisterMaterial(CGL430Material* material)
{
std::lock_guard<std::mutex> lock(m_MaterialMutex);
m_PendingMaterials.push_back(material); //TODO disabled async
int id = GetFreeMaterialIndex();
m_Materials[id] = material;
//Log::Instance() << "Registered material " << reinterpret_cast<uintptr_t>(material) << "\n"; LOGLOG
}
void COpenGL430Renderer::UnregisterMaterial(CGL430Material* material)
{
std::lock_guard<std::mutex> lock(m_MaterialMutex);
auto it = std::find(m_Materials.begin(), m_Materials.end(), material);
if (it != m_Materials.end())
{
Log::ErrInstance() << "Unregistered material " << reinterpret_cast<uintptr_t>(material) << "\n";
*it = nullptr;
}
else
{
Log::ErrInstance() << "Invalid unregister operation on " << reinterpret_cast<uintptr_t>(material) << "\n";
}
}
int COpenGL430Renderer::GetMaterialIndex(CGL430Material* material)
{
std::lock_guard<std::mutex> lock(m_MaterialMutex);
auto it = std::find(m_Materials.begin(), m_Materials.end(), material);
if (it != m_Materials.end())
{
return std::distance(m_Materials.begin(), it);
}
return -1;
}
COpenGL430Renderer::CMaterialGPU COpenGL430Renderer::BuildMaterialForGPU(CGL430Material* material)
{
CMaterialGPU ret;
ret.diffuse = REINTERPRET_AS(material->DiffuseTextureHandle, glm::uvec2);
ret.shininess = material->Shininess;
return ret;
}
void COpenGL430Renderer::ReuploadMaterial(CGL430Material* material)
{
//Log::Instance() << "Reuploading " << reinterpret_cast<size_t>(material) << Log::Endl; LOGLOG
int index = GetMaterialIndex(material);
if(index < 0) { return; }
CMaterialGPU gpu_mat = BuildMaterialForGPU(material);
GLint offset = index * sizeof(CMaterialGPU);
m_MaterialsSSBO.UploadData(offset, sizeof(CMaterialGPU), &gpu_mat);
//Log::Instance() << "Reuploaded " << reinterpret_cast<size_t>(material) << " !\n"; LOGLOG
}
void COpenGL430Renderer::V_Update()
{
//S_Default.Bind();
bool forceReupload = false;
COMPONENT_CALL_GET(forceReupload, CConVarManager, GetConVarValue<bool>("forcereupload"));
if(forceReupload)
{
for(auto mat : m_Materials)
{
if(!mat) { continue; }
ReuploadMaterial(mat);
}
COMPONENT_CALL(CConVarManager, SetConVarValue<bool>("forcereupload", false));
}
std::vector<CGL430Material*> m_PendingCopy;
{
std::lock_guard<std::mutex> lock(m_MaterialMutex);
m_PendingCopy.swap(m_PendingMaterials);
}
for(auto mat : m_PendingCopy)
{
m_materialsToUpload.push_back(mat);
}
std::vector<CGL430Material*> uploaded;
for(auto mat : m_materialsToUpload)
{
if(mat->LoadingStatus != CResource::CLoadingStatus::Done) { continue; }
//int id = GetFreeMaterialIndex();
//m_Materials[id] = mat;
ReuploadMaterial(mat);
uploaded.push_back(mat);
}
for(auto mat : uploaded)
{
std::erase(m_materialsToUpload, mat);
}
}
void COpenGL430Renderer::SetupCamera(std::shared_ptr<CCamera> camera)
{
//S_Default.Bind(); //TODO unnecessary binding
bool view = camera->AcknowledgeViewChange();
bool proj = camera->AcknowledgeProjChange();
if(view) { S_Default.setUniform("view", camera->GetViewMatrix()); }
if(proj) { S_Default.setUniform("proj", camera->GetProjectionMatrix()); }
}
void COpenGL430Renderer::DrawModel(std::shared_ptr<CModelBase> model, const CTransform& transform)
{
//S_Default.Bind(); //TODO unnecessary binding
bool mdl = transform.AcknowledgeChange();
//if(mdl) { /*Log::Instance() << "Uploaded model uniform\n";*/ S_Default.setUniform("model", transform.GetModelMatrix()); }
//if transform of other model changes, but this model remains unchanged
//then model matrix is never being reuploaded, so transform
//simply being duplicated from prev drawcall
S_Default.setUniform("model", transform.GetModelMatrix());
model->V_Draw();
}
std::shared_ptr<CDrawable> COpenGL430Renderer::CreateAnimatedDrawable() const
{
return std::make_shared<CGL430Drawable>();
}
std::string COpenGL430Renderer::GetModelType() const { return "gl430model"; }
std::string COpenGL430Renderer::GetMaterialType() const { return "gl430material"; }
LINK_RENDERER_TO_CLASS(COpenGL430Renderer, gl430);