aboutsummaryrefslogtreecommitdiff
path: root/src/Platform/OpenGL
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-22 12:24:05 +0200
committerhachem <im@hachem.wtf>2025-08-22 12:24:05 +0200
commit0d819f2b9a71e862bce8799c6b0c1304e62219b3 (patch)
treea3011c8f5b04c98de5a8a24bc2b4ded312de958e /src/Platform/OpenGL
parentc20a400e620154f0c334fe0a37d547625b6ee65b (diff)
[add]: add HDRI
Diffstat (limited to 'src/Platform/OpenGL')
-rw-r--r--src/Platform/OpenGL/OpenGLFramebuffer.cpp1
-rw-r--r--src/Platform/OpenGL/OpenGLShader.h1
-rw-r--r--src/Platform/OpenGL/OpenGLTexture.cpp181
-rw-r--r--src/Platform/OpenGL/OpenGLTexture.h31
4 files changed, 212 insertions, 2 deletions
diff --git a/src/Platform/OpenGL/OpenGLFramebuffer.cpp b/src/Platform/OpenGL/OpenGLFramebuffer.cpp
index 523d748..3bb62f6 100644
--- a/src/Platform/OpenGL/OpenGLFramebuffer.cpp
+++ b/src/Platform/OpenGL/OpenGLFramebuffer.cpp
@@ -123,7 +123,6 @@ namespace Donut
bool multisample = m_Specification.Samples > 1;
- // Attachments
if (m_ColorAttachmentSpecifications.size())
{
m_ColorAttachments.resize(m_ColorAttachmentSpecifications.size());
diff --git a/src/Platform/OpenGL/OpenGLShader.h b/src/Platform/OpenGL/OpenGLShader.h
index e9a7dc2..99a150b 100644
--- a/src/Platform/OpenGL/OpenGLShader.h
+++ b/src/Platform/OpenGL/OpenGLShader.h
@@ -32,6 +32,7 @@ namespace Donut
virtual void MemoryBarrier(uint32_t barriers) override;
virtual const std::string& GetName() const override { return m_Name; }
+ virtual uint32_t GetRendererID() const override { return m_RendererID; }
void UploadUniformInt( const std::string& name, int value);
void UploadUniformIntArray(const std::string& name, int* values, uint32_t count);
diff --git a/src/Platform/OpenGL/OpenGLTexture.cpp b/src/Platform/OpenGL/OpenGLTexture.cpp
index e12dea4..d9033dc 100644
--- a/src/Platform/OpenGL/OpenGLTexture.cpp
+++ b/src/Platform/OpenGL/OpenGLTexture.cpp
@@ -1,5 +1,13 @@
#include "OpenGLTexture.h"
+#include "Rendering/Shader.h"
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+#include <glm/glm.hpp>
+#include <glm/gtc/matrix_transform.hpp>
+#include <glm/gtc/type_ptr.hpp>
+
namespace Donut
{
OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height)
@@ -18,7 +26,6 @@ namespace Donut
glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
- // TODO(Hachem): Texture Loading
OpenGLTexture2D::OpenGLTexture2D(const std::string& path)
: m_Path(path)
{
@@ -69,4 +76,176 @@ namespace Donut
GLenum access = readOnly ? GL_READ_ONLY : GL_WRITE_ONLY;
glBindImageTexture(slot, m_RendererID, 0, GL_FALSE, 0, access, m_InternalFormat);
}
+
+ OpenGLCubemapTexture::OpenGLCubemapTexture(uint32_t width, uint32_t height)
+ : m_Width(width), m_Height(height)
+ {
+ m_InternalFormat = GL_RGB16F;
+ m_DataFormat = GL_RGB;
+
+ glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_RendererID);
+ glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height);
+
+ glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ }
+
+ OpenGLCubemapTexture::OpenGLCubemapTexture(const std::string& path)
+ : m_Path(path)
+ {
+ m_Width = 1024;
+ m_Height = 1024;
+ m_InternalFormat = GL_RGB16F;
+ m_DataFormat = GL_RGB;
+
+ glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &m_RendererID);
+ glTextureStorage2D(m_RendererID, 1, m_InternalFormat, m_Width, m_Height);
+
+ glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+
+ LoadHDRI(path);
+ }
+
+ OpenGLCubemapTexture::~OpenGLCubemapTexture()
+ {
+ glDeleteTextures(1, &m_RendererID);
+ }
+
+ void OpenGLCubemapTexture::LoadHDRI(const std::string& path)
+ {
+ stbi_set_flip_vertically_on_load(true);
+ int width, height, channels;
+ float* hdrData = stbi_loadf(path.c_str(), &width, &height, &channels, 3);
+
+ if (!hdrData)
+ {
+ DONUT_ERROR("Failed to load HDRI: {}", path);
+ float defaultSky[6 * 4] =
+ {
+ 0.5f, 0.7f, 1.0f, 1.0f, // Right
+ 0.5f, 0.7f, 1.0f, 1.0f, // Left
+ 0.5f, 0.7f, 1.0f, 1.0f, // Top
+ 0.5f, 0.7f, 1.0f, 1.0f, // Bottom
+ 0.5f, 0.7f, 1.0f, 1.0f, // Front
+ 0.5f, 0.7f, 1.0f, 1.0f // Back
+ };
+
+ for (int i = 0; i < 6; ++i)
+ glTextureSubImage3D(m_RendererID, 0, 0, 0, i, 1, 1, 1, GL_RGBA, GL_FLOAT, &defaultSky[i * 4]);
+ return;
+ }
+
+ ConvertEquirectangularToCubemap(hdrData, width, height);
+ stbi_image_free(hdrData);
+
+ DONUT_INFO("Successfully loaded HDRI: {} ({}x{})", path, width, height);
+ }
+
+ void OpenGLCubemapTexture::ConvertEquirectangularToCubemap(float* hdrData, int width, int height)
+ {
+ uint32_t captureFBO, captureRBO;
+ glGenFramebuffers(1, &captureFBO);
+ glGenRenderbuffers(1, &captureRBO);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_Width, m_Height);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, captureRBO);
+
+ uint32_t hdrTexture;
+ glGenTextures(1, &hdrTexture);
+ glBindTexture(GL_TEXTURE_2D, hdrTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, width, height, 0, GL_RGB, GL_FLOAT, hdrData);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ auto equirectShader = Shader::Create("Assets/Shaders/EquirectToCubemap.glsl");
+ if (!equirectShader)
+ {
+ DONUT_ERROR("Failed to create equirectangular to cubemap shader");
+ return;
+ }
+
+ uint32_t shaderProgram = equirectShader->GetRendererID();
+
+ float vertices[] =
+ {
+ -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
+ 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f,
+ -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f,
+ -1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, -1.0f, 1.0f, -1.0f,
+ -1.0f, -1.0f, -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f
+ };
+
+ uint32_t cubeVAO, cubeVBO;
+ glGenVertexArrays(1, &cubeVAO);
+ glGenBuffers(1, &cubeVBO);
+ glBindVertexArray(cubeVAO);
+ glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
+ glEnableVertexAttribArray(0);
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+
+ glm::mat4 captureProjection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);
+ glm::mat4 captureViews[] =
+ {
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)),
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)),
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)),
+ glm::lookAt(glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3( 0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f))
+ };
+
+ glUseProgram(shaderProgram);
+ glUniform1i(glGetUniformLocation(shaderProgram, "equirectangularMap"), 0);
+ glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, &captureProjection[0][0]);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, hdrTexture);
+
+ glViewport(0, 0, m_Width, m_Height);
+ glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
+ for (unsigned int i = 0; i < 6; ++i)
+ {
+ glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, &captureViews[i][0][0]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, m_RendererID, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ glBindVertexArray(cubeVAO);
+ glDrawArrays(GL_TRIANGLES, 0, 36);
+ }
+ glBindVertexArray(0);
+
+ glDeleteVertexArrays(1, &cubeVAO);
+ glDeleteBuffers(1, &cubeVBO);
+ glDeleteProgram(shaderProgram);
+ glDeleteTextures(1, &hdrTexture);
+ glDeleteFramebuffers(1, &captureFBO);
+ glDeleteRenderbuffers(1, &captureRBO);
+ }
+
+ void OpenGLCubemapTexture::SetData(void* data, uint32_t size)
+ {
+ DONUT_WARN("SetData not implemented for cubemaps");
+ }
+
+ void OpenGLCubemapTexture::Bind(uint32_t slot) const
+ {
+ glBindTextureUnit(slot, m_RendererID);
+ }
+
+ void OpenGLCubemapTexture::BindAsImage(uint32_t slot, bool readOnly) const
+ {
+ GLenum access = readOnly ? GL_READ_ONLY : GL_WRITE_ONLY;
+ glBindImageTexture(slot, m_RendererID, 0, GL_TRUE, 0, access, m_InternalFormat);
+ }
}; \ No newline at end of file
diff --git a/src/Platform/OpenGL/OpenGLTexture.h b/src/Platform/OpenGL/OpenGLTexture.h
index 1c3cb05..220df09 100644
--- a/src/Platform/OpenGL/OpenGLTexture.h
+++ b/src/Platform/OpenGL/OpenGLTexture.h
@@ -34,4 +34,35 @@ namespace Donut
uint32_t m_RendererID;
GLenum m_InternalFormat, m_DataFormat;
};
+
+ class OpenGLCubemapTexture
+ : public CubemapTexture
+ {
+ public:
+ OpenGLCubemapTexture(uint32_t width, uint32_t height);
+ OpenGLCubemapTexture(const std::string& path);
+ virtual ~OpenGLCubemapTexture();
+
+ virtual uint32_t GetWidth() const override { return m_Width; }
+ virtual uint32_t GetHeight() const override { return m_Height; }
+ virtual uint32_t GetRendererID() const override { return m_RendererID; }
+
+ virtual void SetData(void* data, uint32_t size) override;
+ virtual void Bind(uint32_t slot = 0) const override;
+ virtual void BindAsImage(uint32_t slot = 0, bool readOnly = false) const override;
+
+ virtual bool operator==(const Texture& other) const override
+ {
+ return m_RendererID == other.GetRendererID();
+ }
+
+ private:
+ void LoadHDRI(const std::string& path);
+ void ConvertEquirectangularToCubemap(float* hdrData, int width, int height);
+
+ std::string m_Path;
+ uint32_t m_Width, m_Height;
+ uint32_t m_RendererID;
+ GLenum m_InternalFormat, m_DataFormat;
+ };
}