#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 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(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 lock(m_MaterialMutex); m_PendingMaterials.push_back(material); //TODO disabled async int id = GetFreeMaterialIndex(); m_Materials[id] = material; //Log::Instance() << "Registered material " << reinterpret_cast(material) << "\n"; LOGLOG } void COpenGL430Renderer::UnregisterMaterial(CGL430Material* material) { std::lock_guard 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(material) << "\n"; *it = nullptr; } else { Log::ErrInstance() << "Invalid unregister operation on " << reinterpret_cast(material) << "\n"; } } int COpenGL430Renderer::GetMaterialIndex(CGL430Material* material) { std::lock_guard 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(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(material) << " !\n"; LOGLOG } void COpenGL430Renderer::V_Update() { //S_Default.Bind(); bool forceReupload = false; COMPONENT_CALL_GET(forceReupload, CConVarManager, GetConVarValue("forcereupload")); if(forceReupload) { for(auto mat : m_Materials) { if(!mat) { continue; } ReuploadMaterial(mat); } COMPONENT_CALL(CConVarManager, SetConVarValue("forcereupload", false)); } std::vector m_PendingCopy; { std::lock_guard lock(m_MaterialMutex); m_PendingCopy.swap(m_PendingMaterials); } for(auto mat : m_PendingCopy) { m_materialsToUpload.push_back(mat); } std::vector 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 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 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 COpenGL430Renderer::CreateAnimatedDrawable() const { return std::make_shared(); } std::string COpenGL430Renderer::GetModelType() const { return "gl430model"; } std::string COpenGL430Renderer::GetMaterialType() const { return "gl430material"; } LINK_RENDERER_TO_CLASS(COpenGL430Renderer, gl430);