45 if (tex->LoadFromMemory(data, w, h, fmt))
return tex;
60 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
61 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
62 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
63 SDL_GL_CONTEXT_PROFILE_CORE);
64 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
65 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
67 m_GLContext = SDL_GL_CreateContext(m_Window->GetSDLWindow());
69 SDL_Log(
"Failed to create OpenGL context: %s", SDL_GetError());
73 if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
74 SDL_Log(
"Failed to initialize Glad (OpenGL loader)");
79 SDL_GetWindowSize(m_Window->GetSDLWindow(), &
width, &
height);
82 glEnable(GL_DEPTH_TEST);
84 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
87 SDL_GL_SetSwapInterval(
m_vsync ? 1 : 0);
91 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
100 m_Initialized =
true;
105 CreateGBufferResources();
108 SLEAK_INFO(
"OpenGL renderer has been initialized successfully!");
110 (
const char*)glGetString(GL_VERSION));
115void OpenGLRenderer::SetupVertexLayout() {
116 glGenVertexArrays(1, &m_VAO);
126 if (m_hasPendingLightVP) {
127 memcpy(m_lightVP, m_pendingLightVP,
sizeof(m_lightVP));
137 glBindFramebuffer(GL_FRAMEBUFFER, m_gbufferFBO);
138 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
139 glDrawBuffers(3, drawBuffers);
140 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
141 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
144 m_inGeometryPass =
true;
148 glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFBO);
150 glBindFramebuffer(GL_FRAMEBUFFER, 0);
152 glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
156 glBindVertexArray(m_VAO);
159 ImGui_ImplOpenGL3_NewFrame();
160 ImGui_ImplSDL3_NewFrame();
168 if (m_msaaFBO != 0 && !IsDeferredEnabled()) {
170 SDL_GetWindowSize(m_Window->GetSDLWindow(), &
width, &
height);
171 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_msaaFBO);
172 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
175 GL_COLOR_BUFFER_BIT, GL_NEAREST);
176 glBindFramebuffer(GL_FRAMEBUFFER, 0);
181 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
184 glBindVertexArray(0);
185 SDL_GL_SwapWindow(m_Window->GetSDLWindow());
192 CleanupGBufferResources();
193 if (m_shadowTransformUBO) { glDeleteBuffers(1, &m_shadowTransformUBO); m_shadowTransformUBO = 0; }
194 if (m_shadowUBO) { glDeleteBuffers(1, &m_shadowUBO); m_shadowUBO = 0; }
195 if (m_shadowDepthTex) { glDeleteTextures(1, &m_shadowDepthTex); m_shadowDepthTex = 0; }
196 if (m_shadowFBO) { glDeleteFramebuffers(1, &m_shadowFBO); m_shadowFBO = 0; }
197 m_shadowMapCreated =
false;
198 m_shadowUBOCreated =
false;
199 CleanupMSAAFramebuffer();
201 ImGui_ImplOpenGL3_Shutdown();
202 ImGui_ImplSDL3_Shutdown();
203 ImGui::DestroyContext();
207 glDeleteVertexArrays(1, &m_VAO);
211 SDL_GL_DestroyContext(m_GLContext);
212 m_GLContext =
nullptr;
214 m_Initialized =
false;
221 if (m_msaaFBO != 0) {
222 CleanupMSAAFramebuffer();
223 CreateMSAAFramebuffer();
226 if (m_gbufferCreated) {
227 RecreateGBufferOnResize(
static_cast<int>(
width),
static_cast<int>(
height));
234 GLenum mode = m_debugLineMode ? GL_LINES : GL_TRIANGLES;
235 glDrawArrays(mode,
static_cast<GLint
>(firstVertex), vertexCount);
245 int32_t baseVertex) {
246 GLenum mode = m_debugLineMode ? GL_LINES : GL_TRIANGLES;
247 const void* offset =
reinterpret_cast<const void*
>(
248 static_cast<uintptr_t
>(firstIndex) *
sizeof(uint32_t));
249 glDrawElementsBaseVertex(mode, indexCount, GL_UNSIGNED_INT, offset,
256 uint32_t vertexPerInstance) {
257 GLenum mode = m_debugLineMode ? GL_LINES : GL_TRIANGLES;
258 glDrawArraysInstanced(mode, 0, vertexPerInstance,
265 uint32_t indexPerInstance) {
270 uint32_t indexPerInstance,
272 int32_t baseVertex) {
273 GLenum mode = m_debugLineMode ? GL_LINES : GL_TRIANGLES;
274 const void* offset =
reinterpret_cast<const void*
>(
275 static_cast<uintptr_t
>(firstIndex) *
sizeof(uint32_t));
276 glDrawElementsInstancedBaseVertex(mode, indexPerInstance, GL_UNSIGNED_INT,
277 offset, instanceCount, baseVertex);
283 m_debugLineMode =
true;
287 m_debugLineMode =
false;
292 ConfigureRenderFace();
297 ConfigureRenderMode();
301 float height,
float minDepth,
303 glViewport(
static_cast<GLint
>(x),
static_cast<GLint
>(y),
304 static_cast<GLsizei
>(
width),
305 static_cast<GLsizei
>(
height));
306 glDepthRangef(minDepth, maxDepth);
311 glClearColor(r, g, b, a);
312 glClear(GL_COLOR_BUFFER_BIT);
316 float depth, uint8_t stencil) {
319 glClearDepthf(depth);
320 mask |= GL_DEPTH_BUFFER_BIT;
323 glClearStencil(stencil);
324 mask |= GL_STENCIL_BUFFER_BIT;
326 if (mask) glClear(mask);
330 glDepthMask(enabled ? GL_TRUE : GL_FALSE);
334 GLenum glFunc = GL_LESS;
350 glEnable(GL_CULL_FACE);
352 glDisable(GL_CULL_FACE);
365 glBindBuffer(GL_ARRAY_BUFFER, glBuf->GetGLBuffer());
368 const uint32_t customFormat = buffer->GetVertexFormat();
374 const GLsizei stride =
static_cast<GLsizei
>(customDesc->
stride);
375 uint32_t enabledMask = 0;
376 for (
const auto& attr : customDesc->
attributes) {
377 const void* off =
reinterpret_cast<const void*
>(
378 static_cast<uintptr_t
>(attr.offset));
379 glEnableVertexAttribArray(attr.location);
380 switch (attr.format) {
382 glVertexAttribPointer(attr.location, 1, GL_FLOAT, GL_FALSE, stride, off);
385 glVertexAttribPointer(attr.location, 2, GL_FLOAT, GL_FALSE, stride, off);
388 glVertexAttribPointer(attr.location, 3, GL_FLOAT, GL_FALSE, stride, off);
391 glVertexAttribPointer(attr.location, 4, GL_FLOAT, GL_FALSE, stride, off);
394 glVertexAttribIPointer(attr.location, 1, GL_UNSIGNED_INT, stride, off);
397 glVertexAttribIPointer(attr.location, 1, GL_INT, stride, off);
400 if (attr.location < 32) enabledMask |= (1u << attr.location);
403 constexpr uint32_t TRACKED_ATTRIB_SLOTS = 8;
404 for (uint32_t loc = 0; loc < TRACKED_ATTRIB_SLOTS; ++loc) {
405 if (!(enabledMask & (1u << loc))) glDisableVertexAttribArray(loc);
410 glEnableVertexAttribArray(0);
411 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
412 (
void*)offsetof(
Vertex, px));
415 glEnableVertexAttribArray(1);
416 glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
417 (
void*)offsetof(
Vertex, nx));
420 glEnableVertexAttribArray(2);
421 glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
422 (
void*)offsetof(
Vertex, tx));
425 glEnableVertexAttribArray(3);
426 glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
427 (
void*)offsetof(
Vertex, r));
430 glEnableVertexAttribArray(4);
431 glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
432 (
void*)offsetof(
Vertex, u));
435 glEnableVertexAttribArray(5);
436 glVertexAttribIPointer(5, 4, GL_INT,
sizeof(
Vertex),
437 (
void*)offsetof(
Vertex, boneIDs));
440 glEnableVertexAttribArray(6);
441 glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE,
sizeof(
Vertex),
442 (
void*)offsetof(
Vertex, boneWeights));
451 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, glBuf->GetGLBuffer());
460 if (m_inShadowPass && slot == 0 && glBuf->GetCPUShadowCopySize() >= 128) {
461 const float* srcWorld =
reinterpret_cast<const float*
>(
462 static_cast<const char*
>(glBuf->GetCPUShadowCopy()) + 64);
465 for (
int r = 0; r < 4; ++r) {
466 for (
int c = 0; c < 4; ++c) {
468 for (
int k = 0; k < 4; ++k) {
469 sum += srcWorld[r * 4 + k] * m_lightVP[k * 4 + c];
471 shadowPC[r * 4 + c] = sum;
474 memcpy(&shadowPC[16], srcWorld,
sizeof(
float) * 16);
477 if (m_shadowTransformUBO == 0) {
478 glGenBuffers(1, &m_shadowTransformUBO);
479 glBindBuffer(GL_UNIFORM_BUFFER, m_shadowTransformUBO);
480 glBufferData(GL_UNIFORM_BUFFER, 128,
nullptr, GL_DYNAMIC_DRAW);
481 glBindBuffer(GL_UNIFORM_BUFFER, 0);
484 glBindBuffer(GL_UNIFORM_BUFFER, m_shadowTransformUBO);
485 glBufferSubData(GL_UNIFORM_BUFFER, 0,
sizeof(shadowPC), shadowPC);
486 glBindBuffer(GL_UNIFORM_BUFFER, 0);
487 glBindBufferBase(GL_UNIFORM_BUFFER, slot, m_shadowTransformUBO);
491 glBindBufferBase(GL_UNIFORM_BUFFER, slot, glBuf->GetGLBuffer());
501 if (!buffer->Initialize(data)) {
510 if (shader->compile(shaderSource)) {
519 if (texture->LoadFromFile(TexturePath)) {
538void OpenGLRenderer::CreateMSAAFramebuffer() {
545 glGenFramebuffers(1, &m_msaaFBO);
546 glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFBO);
549 glGenRenderbuffers(1, &m_msaaColorRBO);
550 glBindRenderbuffer(GL_RENDERBUFFER, m_msaaColorRBO);
553 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
554 GL_RENDERBUFFER, m_msaaColorRBO);
557 glGenRenderbuffers(1, &m_msaaDepthRBO);
558 glBindRenderbuffer(GL_RENDERBUFFER, m_msaaDepthRBO);
561 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
562 GL_RENDERBUFFER, m_msaaDepthRBO);
564 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
565 SLEAK_ERROR(
"OpenGL MSAA framebuffer is not complete!");
567 glBindFramebuffer(GL_FRAMEBUFFER, 0);
570void OpenGLRenderer::CleanupMSAAFramebuffer() {
571 if (m_msaaDepthRBO) { glDeleteRenderbuffers(1, &m_msaaDepthRBO); m_msaaDepthRBO = 0; }
572 if (m_msaaColorRBO) { glDeleteRenderbuffers(1, &m_msaaColorRBO); m_msaaColorRBO = 0; }
573 if (m_msaaFBO) { glDeleteFramebuffers(1, &m_msaaFBO); m_msaaFBO = 0; }
582 CleanupMSAAFramebuffer();
583 CreateMSAAFramebuffer();
592 SDL_GL_SetSwapInterval(
m_vsync ? 1 : 0);
599 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
602 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
605 glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
608 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
616 glDisable(GL_CULL_FACE);
619 glEnable(GL_CULL_FACE);
623 glEnable(GL_CULL_FACE);
624 glCullFace(GL_FRONT);
627 glDisable(GL_CULL_FACE);
634 if (texture->LoadCubemap(facePaths)) {
643 if (texture->LoadEquirectangular(panoramaPath)) {
651 IMGUI_CHECKVERSION();
652 ImGui::CreateContext();
653 ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
654 ImGui::StyleColorsDark();
656 if (!ImGui_ImplSDL3_InitForOpenGL(m_Window->GetSDLWindow(),
660 if (!ImGui_ImplOpenGL3_Init(
"#version 450"))
667void OpenGLRenderer::SetLightVP(
const float* mat) {
669 memcpy(m_pendingLightVP, mat,
sizeof(m_pendingLightVP));
670 m_hasPendingLightVP =
true;
674bool OpenGLRenderer::CreateShadowUBO() {
675 if (m_shadowUBOCreated)
return true;
676 glGenBuffers(1, &m_shadowUBO);
677 glBindBuffer(GL_UNIFORM_BUFFER, m_shadowUBO);
678 glBufferData(GL_UNIFORM_BUFFER,
sizeof(RenderEngine::PCSSShadowGPUData),
nullptr, GL_DYNAMIC_DRAW);
679 glBindBuffer(GL_UNIFORM_BUFFER, 0);
680 m_shadowUBOCreated =
true;
684void OpenGLRenderer::UpdateShadowLightUBO(
const void* data, uint32_t size) {
685 if (!m_shadowUBOCreated && !CreateShadowUBO())
return;
688 const auto* ubo =
static_cast<const RenderEngine::ShadowLightUBO*
>(data);
690 RenderEngine::PCSSShadowGPUData shadowData{};
691 memcpy(shadowData.LightVP, ubo->LightVP,
sizeof(
float) * 16);
692 memcpy(shadowData.NdcToShadow, ubo->NdcToShadow,
sizeof(
float) * 16);
693 shadowData.ShadowBias = ubo->ShadowBias;
694 shadowData.ShadowStrength = ubo->ShadowStrength;
695 shadowData.ShadowTexelSize = ubo->ShadowTexelSize;
696 shadowData.ShadowLightSize = ubo->LightSize;
700 glBindBuffer(GL_UNIFORM_BUFFER, m_shadowUBO);
701 glBufferSubData(GL_UNIFORM_BUFFER, 0,
sizeof(shadowData), &shadowData);
702 glBindBuffer(GL_UNIFORM_BUFFER, 0);
705 glBindBufferBase(GL_UNIFORM_BUFFER, 5, m_shadowUBO);
708bool OpenGLRenderer::CreateShadowMapResources() {
709 if (m_shadowMapCreated)
return true;
712 glGenTextures(1, &m_shadowDepthTex);
713 glBindTexture(GL_TEXTURE_2D, m_shadowDepthTex);
714 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F,
716 GL_DEPTH_COMPONENT, GL_FLOAT,
nullptr);
717 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
718 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
719 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
720 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
721 float borderColor[] = {1.0f, 1.0f, 1.0f, 1.0f};
722 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
723 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
724 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
725 glBindTexture(GL_TEXTURE_2D, 0);
728 glGenFramebuffers(1, &m_shadowFBO);
729 glBindFramebuffer(GL_FRAMEBUFFER, m_shadowFBO);
730 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_shadowDepthTex, 0);
731 glDrawBuffer(GL_NONE);
732 glReadBuffer(GL_NONE);
733 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
735 glBindFramebuffer(GL_FRAMEBUFFER, 0);
738 glBindFramebuffer(GL_FRAMEBUFFER, 0);
740 m_shadowMapCreated =
true;
746void OpenGLRenderer::RenderShadowPass() {
749 if (!queue || !queue->HasCachedShadowDraws())
return;
751 if (!m_shadowMapCreated) {
752 if (!CreateShadowMapResources())
return;
756 GLint savedViewport[4];
757 glGetIntegerv(GL_VIEWPORT, savedViewport);
760 glBindFramebuffer(GL_FRAMEBUFFER, m_shadowFBO);
762 glClear(GL_DEPTH_BUFFER_BIT);
765 glEnable(GL_POLYGON_OFFSET_FILL);
766 glPolygonOffset(2.0f, 4.0f);
771 glEnable(GL_CULL_FACE);
775 glBindVertexArray(m_VAO);
778 m_inShadowPass =
true;
780 queue->ExecuteShadowPass(
this);
782 m_inShadowPass =
false;
785 glDisable(GL_POLYGON_OFFSET_FILL);
786 glEnable(GL_CULL_FACE);
787 ConfigureRenderFace();
791 glBindFramebuffer(GL_FRAMEBUFFER, m_msaaFBO);
793 glBindFramebuffer(GL_FRAMEBUFFER, 0);
795 glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]);
798 glActiveTexture(GL_TEXTURE3);
799 glBindTexture(GL_TEXTURE_2D, m_shadowDepthTex);
800 glActiveTexture(GL_TEXTURE0);
811bool OpenGLRenderer::CreateGBufferResources() {
812 if (m_gbufferCreated)
return true;
815 SDL_GetWindowSize(m_Window->GetSDLWindow(), &w, &h);
820 glGenFramebuffers(1, &m_gbufferFBO);
821 glBindFramebuffer(GL_FRAMEBUFFER, m_gbufferFBO);
823 auto makeColorTex = [](GLuint& tex, GLenum internalFmt,
int w,
int h) {
824 glGenTextures(1, &tex);
825 glBindTexture(GL_TEXTURE_2D, tex);
826 GLenum fmt = GL_RGBA;
827 GLenum type = GL_UNSIGNED_BYTE;
828 if (internalFmt == GL_RGBA16F || internalFmt == GL_RGBA32F) {
831 glTexImage2D(GL_TEXTURE_2D, 0, internalFmt, w, h, 0, fmt, type,
nullptr);
832 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
833 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
834 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
835 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
839 makeColorTex(m_gbufferAlbedoAO, GL_RGBA8, w, h);
840 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_gbufferAlbedoAO, 0);
843 makeColorTex(m_gbufferNormalRough, GL_RGBA16F, w, h);
844 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, m_gbufferNormalRough, 0);
847 makeColorTex(m_gbufferMetalEmit, GL_RGBA8, w, h);
848 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, m_gbufferMetalEmit, 0);
854 glGenTextures(1, &m_gbufferDepth);
855 glBindTexture(GL_TEXTURE_2D, m_gbufferDepth);
856 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, w, h, 0,
857 GL_DEPTH_COMPONENT, GL_FLOAT,
nullptr);
858 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
859 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
860 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
861 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
862 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_gbufferDepth, 0);
864 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
865 GL_COLOR_ATTACHMENT2 };
866 glDrawBuffers(3, drawBuffers);
868 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
869 SLEAK_ERROR(
"OpenGL GBuffer FBO is not complete!");
870 glBindFramebuffer(GL_FRAMEBUFFER, 0);
873 glBindFramebuffer(GL_FRAMEBUFFER, 0);
877 if (!m_gbufferShader->compile(
"assets/shaders/gbuffer_gl.vert",
878 "assets/shaders/gbuffer_gl.frag")) {
879 SLEAK_ERROR(
"Failed to compile GBuffer geometry shader!");
880 delete m_gbufferShader;
881 m_gbufferShader =
nullptr;
882 CleanupGBufferResources();
888 if (!m_lightingShader->compile(
"assets/shaders/lighting_pass_gl.vert",
889 "assets/shaders/lighting_pass_gl.frag")) {
890 SLEAK_ERROR(
"Failed to compile deferred lighting pass shader!");
891 delete m_lightingShader;
892 m_lightingShader =
nullptr;
893 CleanupGBufferResources();
898 glGenVertexArrays(1, &m_lightingVAO);
901 glGenBuffers(1, &m_deferredCBUBO);
902 glBindBuffer(GL_UNIFORM_BUFFER, m_deferredCBUBO);
903 glBufferData(GL_UNIFORM_BUFFER,
sizeof(RenderEngine::DeferredCBData),
nullptr, GL_DYNAMIC_DRAW);
904 glBindBuffer(GL_UNIFORM_BUFFER, 0);
905 glBindBufferBase(GL_UNIFORM_BUFFER, 6, m_deferredCBUBO);
906 m_deferredCBCreated =
true;
908 m_gbufferCreated =
true;
909 SLEAK_INFO(
"OpenGL GBuffer created ({}x{}) — deferred rendering active", w, h);
911 if (!CreateSSAOResources()) {
912 SLEAK_WARN(
"OpenGL SSAO resources failed to initialize — SSAO disabled");
917void OpenGLRenderer::CleanupGBufferResources() {
918 CleanupSSAOResources();
920 if (m_gbufferAlbedoAO) { glDeleteTextures(1, &m_gbufferAlbedoAO); m_gbufferAlbedoAO = 0; }
921 if (m_gbufferNormalRough) { glDeleteTextures(1, &m_gbufferNormalRough); m_gbufferNormalRough = 0; }
922 if (m_gbufferMetalEmit) { glDeleteTextures(1, &m_gbufferMetalEmit); m_gbufferMetalEmit = 0; }
923 if (m_gbufferDepth) { glDeleteTextures(1, &m_gbufferDepth); m_gbufferDepth = 0; }
924 if (m_gbufferFBO) { glDeleteFramebuffers(1, &m_gbufferFBO); m_gbufferFBO = 0; }
925 if (m_lightingVAO) { glDeleteVertexArrays(1, &m_lightingVAO); m_lightingVAO = 0; }
926 if (m_deferredCBUBO) { glDeleteBuffers(1, &m_deferredCBUBO); m_deferredCBUBO = 0; }
927 delete m_gbufferShader; m_gbufferShader =
nullptr;
928 delete m_lightingShader; m_lightingShader =
nullptr;
929 m_gbufferCreated =
false;
930 m_deferredCBCreated =
false;
935void OpenGLRenderer::EnsureIBL() {
938 auto* game = app->GetGame();
940 auto* scene = game->GetActiveScene();
942 auto* skybox = scene->GetSkybox();
943 if (!skybox || !skybox->IsInitialized())
return;
944 auto* cube = skybox->GetCubemapTexture();
946 auto* glCube =
dynamic_cast<OpenGLCubemapTexture*
>(cube);
949 GLuint cubeHandle = glCube->GetGLTexture();
950 if (cubeHandle == 0)
return;
953 if (cubeHandle != m_iblBoundCubemap) {
955 if (m_ibl->Initialize(cubeHandle)) {
956 m_iblBoundCubemap = cubeHandle;
958 m_iblBoundCubemap = 0;
962 if (m_iblSettingsUBO == 0) {
963 glGenBuffers(1, &m_iblSettingsUBO);
964 glBindBuffer(GL_UNIFORM_BUFFER, m_iblSettingsUBO);
965 glBufferData(GL_UNIFORM_BUFFER,
966 sizeof(IBLSettingsGPUData),
967 nullptr, GL_DYNAMIC_DRAW);
968 glBindBuffer(GL_UNIFORM_BUFFER, 0);
972void OpenGLRenderer::CleanupIBL() {
973 if (m_ibl) {
delete m_ibl; m_ibl =
nullptr; }
974 if (m_iblSettingsUBO) {
975 glDeleteBuffers(1, &m_iblSettingsUBO);
976 m_iblSettingsUBO = 0;
978 m_iblBoundCubemap = 0;
981void OpenGLRenderer::RecreateGBufferOnResize(
int width,
int height) {
982 if (!m_gbufferCreated)
return;
984 m_gbufferWidth =
width;
988 glBindTexture(GL_TEXTURE_2D, m_gbufferAlbedoAO);
989 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
width,
height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
992 glBindTexture(GL_TEXTURE_2D, m_gbufferNormalRough);
993 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
width,
height, 0, GL_RGBA, GL_FLOAT,
nullptr);
996 glBindTexture(GL_TEXTURE_2D, m_gbufferMetalEmit);
997 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
width,
height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
nullptr);
1000 glBindTexture(GL_TEXTURE_2D, m_gbufferDepth);
1001 glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F,
width,
height, 0,
1002 GL_DEPTH_COMPONENT, GL_FLOAT,
nullptr);
1004 glBindTexture(GL_TEXTURE_2D, 0);
1012 if (m_gbufferShader) {
1015 glBindFramebuffer(GL_FRAMEBUFFER, m_gbufferFBO);
1016 GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1,
1017 GL_COLOR_ATTACHMENT2 };
1018 glDrawBuffers(3, drawBuffers);
1020 glEnable(GL_DEPTH_TEST);
1021 glDepthMask(GL_TRUE);
1026 glActiveTexture(GL_TEXTURE3);
1027 glBindTexture(GL_TEXTURE_2D, 0);
1028 glActiveTexture(GL_TEXTURE0);
1030 m_gbufferShader->bind();
1031 glBindVertexArray(m_VAO);
1033 static bool warned =
false;
1035 SLEAK_ERROR(
"BindGBufferShader: m_gbufferShader is NULL!");
1041void OpenGLRenderer::BindPBRMaterial(Sleak::Material* material) {
1045 BindGBufferShader();
1049void OpenGLRenderer::UpdateDeferredCB(
const void* data, uint32_t size) {
1050 if (!m_deferredCBCreated)
return;
1051 glBindBuffer(GL_UNIFORM_BUFFER, m_deferredCBUBO);
1052 glBufferSubData(GL_UNIFORM_BUFFER, 0, size, data);
1053 glBindBuffer(GL_UNIFORM_BUFFER, 0);
1054 glBindBufferBase(GL_UNIFORM_BUFFER, 6, m_deferredCBUBO);
1058 m_inGeometryPass =
false;
1060 if (!m_gbufferCreated || !m_lightingShader)
return;
1073 constexpr GLuint targetFBO = 0;
1074 glBindFramebuffer(GL_FRAMEBUFFER, targetFBO);
1077 glClearColor(0.39f, 0.58f, 0.93f, 1.0f);
1078 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1083 glEnable(GL_DEPTH_TEST);
1084 glDepthFunc(GL_ALWAYS);
1085 glDepthMask(GL_TRUE);
1086 glDisable(GL_BLEND);
1089 m_lightingShader->bind();
1092 glActiveTexture(GL_TEXTURE8); glBindTexture(GL_TEXTURE_2D, m_gbufferAlbedoAO);
1093 glActiveTexture(GL_TEXTURE9); glBindTexture(GL_TEXTURE_2D, m_gbufferNormalRough);
1094 glActiveTexture(GL_TEXTURE10); glBindTexture(GL_TEXTURE_2D, m_gbufferMetalEmit);
1095 glActiveTexture(GL_TEXTURE11); glBindTexture(GL_TEXTURE_2D, m_gbufferDepth);
1097 glActiveTexture(GL_TEXTURE13);
1098 glBindTexture(GL_TEXTURE_2D, m_ssaoCreated ? m_ssaoBlurTex : 0);
1100 GLint ssaoLoc = glGetUniformLocation(
1101 m_lightingShader->GetProgram(),
"uSSAOEnabled");
1103 glUniform1i(ssaoLoc, (
m_ssaoEnabled && m_ssaoCreated) ? 1 : 0);
1105 glActiveTexture(GL_TEXTURE0);
1109 if (m_shadowMapCreated) {
1110 glActiveTexture(GL_TEXTURE3);
1111 glBindTexture(GL_TEXTURE_2D, m_shadowDepthTex);
1112 glActiveTexture(GL_TEXTURE0);
1117 bool iblReady = (m_ibl && m_ibl->IsInitialized());
1118 if (iblReady) m_ibl->Bind();
1119 if (m_iblSettingsUBO) {
1120 IBLSettingsGPUData ibl{};
1125 glBindBuffer(GL_UNIFORM_BUFFER, m_iblSettingsUBO);
1126 glBufferSubData(GL_UNIFORM_BUFFER, 0,
sizeof(ibl), &ibl);
1127 glBindBuffer(GL_UNIFORM_BUFFER, 0);
1128 glBindBufferBase(GL_UNIFORM_BUFFER, 10, m_iblSettingsUBO);
1132 glBindVertexArray(m_lightingVAO);
1133 glDrawArrays(GL_TRIANGLES, 0, 3);
1136 glDepthFunc(GL_LESS);
1138 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1141 glBindVertexArray(m_VAO);
1145 m_inForwardTransparentPass =
true;
1148 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1152 m_inForwardTransparentPass =
false;
1161bool OpenGLRenderer::CreateSSAOResources() {
1162 if (m_ssaoCreated)
return true;
1163 if (!m_gbufferCreated)
return false;
1165 int w = m_gbufferWidth;
1166 int h = m_gbufferHeight;
1168 auto makeR8Tex = [](GLuint& tex,
int w,
int h) {
1169 glGenTextures(1, &tex);
1170 glBindTexture(GL_TEXTURE_2D, tex);
1171 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, w, h, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1172 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1173 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1174 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1175 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1179 makeR8Tex(m_ssaoTexture, w, h);
1180 glGenFramebuffers(1, &m_ssaoFBO);
1181 glBindFramebuffer(GL_FRAMEBUFFER, m_ssaoFBO);
1182 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1183 GL_TEXTURE_2D, m_ssaoTexture, 0);
1184 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
1186 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1187 CleanupSSAOResources();
1192 makeR8Tex(m_ssaoBlurTex, w, h);
1193 glGenFramebuffers(1, &m_ssaoBlurFBO);
1194 glBindFramebuffer(GL_FRAMEBUFFER, m_ssaoBlurFBO);
1195 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1196 GL_TEXTURE_2D, m_ssaoBlurTex, 0);
1197 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
1199 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1200 CleanupSSAOResources();
1203 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1206 SSAOKernel kernelGen;
1207 kernelGen.Generate();
1209 glGenTextures(1, &m_ssaoNoiseTex);
1210 glBindTexture(GL_TEXTURE_2D, m_ssaoNoiseTex);
1211 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F,
1213 GL_RGBA, GL_FLOAT, kernelGen.noiseData.data());
1214 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1215 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1216 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1217 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1221 if (!m_ssaoShader->compile(
"assets/shaders/ssao_gl.vert",
1222 "assets/shaders/ssao_gl.frag")) {
1224 CleanupSSAOResources();
1228 if (!m_ssaoBlurShader->compile(
"assets/shaders/ssao_blur_gl.vert",
1229 "assets/shaders/ssao_blur_gl.frag")) {
1230 SLEAK_ERROR(
"Failed to compile SSAO blur shader");
1231 CleanupSSAOResources();
1237 glGenBuffers(1, &m_ssaoSettingsUBO);
1238 glBindBuffer(GL_UNIFORM_BUFFER, m_ssaoSettingsUBO);
1239 glBufferData(GL_UNIFORM_BUFFER,
sizeof(SSAOSettingsGPUData),
nullptr, GL_DYNAMIC_DRAW);
1242 glGenBuffers(1, &m_ssaoKernelUBO);
1243 glBindBuffer(GL_UNIFORM_BUFFER, m_ssaoKernelUBO);
1244 glBufferData(GL_UNIFORM_BUFFER,
1246 kernelGen.samples.data(), GL_STATIC_DRAW);
1249 glGenBuffers(1, &m_ssaoCameraUBO);
1250 glBindBuffer(GL_UNIFORM_BUFFER, m_ssaoCameraUBO);
1251 glBufferData(GL_UNIFORM_BUFFER,
sizeof(
float) * 16 * 3,
nullptr, GL_DYNAMIC_DRAW);
1253 glBindBuffer(GL_UNIFORM_BUFFER, 0);
1255 m_ssaoCreated =
true;
1256 SLEAK_INFO(
"OpenGL SSAO ready ({}x{})", w, h);
1260void OpenGLRenderer::CleanupSSAOResources() {
1261 if (m_ssaoFBO) { glDeleteFramebuffers(1, &m_ssaoFBO); m_ssaoFBO = 0; }
1262 if (m_ssaoBlurFBO) { glDeleteFramebuffers(1, &m_ssaoBlurFBO); m_ssaoBlurFBO = 0; }
1263 if (m_ssaoTexture) { glDeleteTextures(1, &m_ssaoTexture); m_ssaoTexture = 0; }
1264 if (m_ssaoBlurTex) { glDeleteTextures(1, &m_ssaoBlurTex); m_ssaoBlurTex = 0; }
1265 if (m_ssaoNoiseTex) { glDeleteTextures(1, &m_ssaoNoiseTex); m_ssaoNoiseTex = 0; }
1266 if (m_ssaoSettingsUBO) { glDeleteBuffers(1, &m_ssaoSettingsUBO); m_ssaoSettingsUBO = 0; }
1267 if (m_ssaoKernelUBO) { glDeleteBuffers(1, &m_ssaoKernelUBO); m_ssaoKernelUBO = 0; }
1268 if (m_ssaoCameraUBO) { glDeleteBuffers(1, &m_ssaoCameraUBO); m_ssaoCameraUBO = 0; }
1269 delete m_ssaoShader; m_ssaoShader =
nullptr;
1270 delete m_ssaoBlurShader; m_ssaoBlurShader =
nullptr;
1271 m_ssaoCreated =
false;
1274void OpenGLRenderer::RecreateSSAOOnResize(
int width,
int height) {
1275 if (!m_ssaoCreated)
return;
1277 glBindTexture(GL_TEXTURE_2D, m_ssaoTexture);
1278 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
width,
height, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1280 glBindTexture(GL_TEXTURE_2D, m_ssaoBlurTex);
1281 glTexImage2D(GL_TEXTURE_2D, 0, GL_R8,
width,
height, 0, GL_RED, GL_UNSIGNED_BYTE,
nullptr);
1283 glBindTexture(GL_TEXTURE_2D, 0);
1286void OpenGLRenderer::ExecuteSSAOPass() {
1287 if (!m_ssaoCreated || !m_ssaoShader || !m_ssaoBlurShader)
return;
1292 glBindFramebuffer(GL_FRAMEBUFFER, m_ssaoBlurFBO);
1293 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1294 glClear(GL_COLOR_BUFFER_BIT);
1295 glBindFramebuffer(GL_FRAMEBUFFER, 0);
1300 SSAOSettingsGPUData s{};
1305 s.ScreenWidth =
static_cast<float>(m_gbufferWidth);
1306 s.ScreenHeight =
static_cast<float>(m_gbufferHeight);
1309 s.FarPlane = 2000.0f;
1311 glBindBuffer(GL_UNIFORM_BUFFER, m_ssaoSettingsUBO);
1312 glBufferSubData(GL_UNIFORM_BUFFER, 0,
sizeof(s), &s);
1317 float camData[16 * 3];
1318 std::memcpy(camData, &P(0,0),
sizeof(
float) * 16);
1319 std::memcpy(camData + 16, &V(0,0),
sizeof(
float) * 16);
1326 const float* m = &VP(0,0);
1327 float i0 = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15] + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
1328 float i4 = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15] - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
1329 float i8 = m[4]*m[9] *m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15] + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
1330 float i12 = -m[4]*m[9] *m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14] - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
1331 float det = m[0]*i0 + m[1]*i4 + m[2]*i8 + m[3]*i12;
1332 if (std::fabs(det) < 1e-8f) {
1333 std::memset(invP, 0,
sizeof(invP));
1334 invP[0] = invP[5] = invP[10] = invP[15] = 1.0f;
1336 float id = 1.0f / det;
1337 invP[0] = i0 * id; invP[4] = i4 * id; invP[8] = i8 * id; invP[12] = i12 * id;
1338 invP[1] = (-m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15] - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10]) *
id;
1339 invP[5] = ( m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15] + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10]) *
id;
1340 invP[9] = (-m[0]*m[9] *m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15] - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9] ) *
id;
1341 invP[13] = ( m[0]*m[9] *m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14] + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9] ) *
id;
1342 invP[2] = ( m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15] + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6]) *
id;
1343 invP[6] = (-m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15] - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6]) *
id;
1344 invP[10] = ( m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15] + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5]) *
id;
1345 invP[14] = (-m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14] - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5]) *
id;
1346 invP[3] = (-m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11] - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6]) *
id;
1347 invP[7] = ( m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11] + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6]) *
id;
1348 invP[11] = (-m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11] - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5]) *
id;
1349 invP[15] = ( m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10] + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5]) *
id;
1352 std::memcpy(camData + 32, invP,
sizeof(
float) * 16);
1354 glBindBuffer(GL_UNIFORM_BUFFER, m_ssaoCameraUBO);
1355 glBufferSubData(GL_UNIFORM_BUFFER, 0,
sizeof(camData), camData);
1356 glBindBuffer(GL_UNIFORM_BUFFER, 0);
1361 glBindBufferBase(GL_UNIFORM_BUFFER, 7, m_ssaoSettingsUBO);
1362 glBindBufferBase(GL_UNIFORM_BUFFER, 8, m_ssaoKernelUBO);
1363 glBindBufferBase(GL_UNIFORM_BUFFER, 9, m_ssaoCameraUBO);
1366 glBindFramebuffer(GL_FRAMEBUFFER, m_ssaoFBO);
1367 glViewport(0, 0, m_gbufferWidth, m_gbufferHeight);
1368 glDisable(GL_DEPTH_TEST);
1369 glDepthMask(GL_FALSE);
1370 glDisable(GL_BLEND);
1371 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1372 glClear(GL_COLOR_BUFFER_BIT);
1374 m_ssaoShader->bind();
1375 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_gbufferDepth);
1376 glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, m_gbufferNormalRough);
1377 glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, m_ssaoNoiseTex);
1378 glActiveTexture(GL_TEXTURE0);
1380 glBindVertexArray(m_lightingVAO);
1381 glDrawArrays(GL_TRIANGLES, 0, 3);
1384 glBindFramebuffer(GL_FRAMEBUFFER, m_ssaoBlurFBO);
1385 glClear(GL_COLOR_BUFFER_BIT);
1387 m_ssaoBlurShader->bind();
1388 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_ssaoTexture);
1390 glDrawArrays(GL_TRIANGLES, 0, 3);
1393 glEnable(GL_DEPTH_TEST);
1394 glDepthMask(GL_TRUE);
1396 glBindFramebuffer(GL_FRAMEBUFFER, 0);
static Application * GetInstance()
The one Application for this process, or null before construction.
static const Math::Matrix4 & GetMainProjectionMatrix()
static const Math::Matrix4 & GetMainViewMatrix()
void BindTexturesAndCB()
Binds textures and uploads the material CB for the deferred geometry pass, skipping the shader bind.
Backend-agnostic GPU buffer: vertex, index, constant, or resource view target.
OpenGL VBO/EBO/UBO wrapper; target is derived from BufferType at construction.
OpenGLBuffer(uint32_t size, BufferType type)
static constexpr uint32_t PREFILTER_MIPS
virtual ~OpenGLRenderer()
virtual void SetDepthWrite(bool enabled) override
virtual Texture * CreateTexture(const std::string &TexturePath) override
Loads a texture from disk.
virtual void SetRenderFace(RenderFace face) override
virtual void DrawInstance(uint32_t instanceCount, uint32_t vertexPerInstance) override
Non-indexed instanced draw.
virtual void BindIndexBuffer(RefPtr< BufferBase > buffer, uint32_t slot=0) override
virtual void SetCullEnabled(bool enabled) override
virtual Shader * CreateShader(const std::string &shaderSource) override
Compiles a shader program from source or a source-file path.
virtual Texture * CreateTextureFromData(uint32_t width, uint32_t height, void *data) override
Creates a texture from an in-memory pixel buffer.
virtual void SetViewport(float x, float y, float width, float height, float minDepth=0.0f, float maxDepth=1.0f) override
Sets the active viewport rect and depth range in pixel/NDC units.
OpenGLRenderer(Window *window)
Registers this backend's buffer/shader/texture factories with ResourceManager.
virtual BufferBase * CreateBuffer(BufferType Type, uint32_t size, void *data) override
Allocates a backend buffer, optionally seeded with initial data.
virtual void BeginDebugLinePass() override
void BeginRender() override
Acquires the next frame and prepares it for command recording.
void ApplyMSAAChange() override
virtual void DrawIndexedInstance(uint32_t instanceCount, uint32_t indexPerInstance) override
Indexed instanced draw.
void EndRender() override
Submits recorded commands and presents the frame.
virtual void BindTexture(RefPtr< Sleak::Texture > texture, uint32_t slot=0) override
virtual void Resize(uint32_t width, uint32_t height) override
Recreates swapchain-dependent resources for a new surface size.
virtual void BindConstantBuffer(RefPtr< BufferBase > buffer, uint32_t slot=0) override
virtual void ClearDepthStencil(bool clearDepth, bool clearStencil, float depth, uint8_t stencil) override
virtual bool CreateImGUI() override
Initializes ImGui integration for this backend.
void ApplyVSyncChange() override
virtual void DrawIndexed(uint32_t indexCount) override
Indexed draw from the currently bound vertex/index buffers.
virtual void ClearRenderTarget(float r, float g, float b, float a) override
virtual void SetDepthCompare(DepthCompare compare) override
bool Initialize() override
Creates the device, swapchain, and backend resources.
Texture * CreateCubemapTextureFromPanorama(const std::string &panoramaPath)
Loads a cubemap by converting a single equirectangular panorama.
virtual void SetRenderMode(RenderMode mode) override
virtual void BindVertexBuffer(RefPtr< BufferBase > buffer, uint32_t slot=0) override
virtual void BindBoneBuffer(RefPtr< BufferBase > buffer) override
virtual void EndDebugLinePass() override
virtual void Draw(uint32_t vertexCount) override
Non-indexed draw from the currently bound vertex buffer.
Texture * CreateCubemapTexture(const std::array< std::string, 6 > &facePaths)
Loads a cubemap from six face image paths.
static RenderCommandQueue * GetInstance()
Lazily creates and returns the process-wide singleton instance.
virtual void BeginForwardTransparentPass()
virtual void EndForwardTransparentPass()
virtual bool IsDeferredEnabled() const
virtual void BindGBufferShader()
virtual void ExecuteDeferredLightingPass()
virtual void ConfigureRenderMode()=0
Applies the current RenderMode (fill/wireframe/points) to backend state.
virtual void ConfigureRenderFace()=0
Applies the current RenderFace (cull mode) to backend state.
bool m_vsyncChangeRequested
void UpdateFrameMetrics()
Rolls up frame count into rate/time/triangle stats once per MetricUpdateInterval.
uint32_t m_msaaSampleCount
uint32_t m_pendingMsaaSampleCount
void SetPerformanceCounter(bool value)
bool m_msaaChangeRequested
uint32_t m_maxMsaaSampleCount
uint32_t m_shadowMapResolution
bool m_shadowResourcesCreated
static void RegisterCreateCubemapTextureFromPanorama(T *instance, Texture *(T::*method)(const std::string &))
static void RegisterCreateCubemapTexture(T *instance, Texture *(T::*method)(const std::array< std::string, 6 > &))
static void RegisterCreateBuffer(T *instance, BufferBase *(T::*method)(BufferType, uint32_t, void *))
static void RegisterCreateShader(T *instance, Shader *(T::*method)(const std::string &))
static void RegisterCreateTextureFromMemory(std::function< Texture *(const void *, uint32_t, uint32_t, TextureFormat, uint32_t)> func)
static void RegisterCreateTexture(T *instance, Texture *(T::*method)(const std::string &))
Backend-agnostic compiled shader program.
virtual bool IsValid() const
True if the pointer is non-null.
SDL_Window * GetSDLWindow()
Returns the underlying SDL window handle.
Matrix< float, 4, 4 > Matrix4
Backend-facing rendering layer shared by the four graphics backends.
DepthCompare
Depth test comparison function.
RenderMode
Rasterizer fill style for a draw.
BufferType
GPU buffer usage kind, drives backend binding flags and layout.
RenderFace
Which triangle winding gets culled.
Root namespace for everything the engine exposes.
static constexpr uint32_t MAX_KERNEL_SIZE
static constexpr uint32_t NOISE_SIZE
std::vector< VertexAttribute > attributes