aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2025-08-12 19:17:50 +0200
committerhachem <im@hachem.wtf>2025-08-12 19:17:50 +0200
commit1ad6bc34323f5b30d463ebe47a58d47ff9d4f328 (patch)
tree535774e6db8e03fdb204c27734ca9fa43ab30a61 /src
parent8cf6858a6cd958f31521c4ce680cf2011bfb7cc3 (diff)
[add]: Texture and Pixel buffers
Diffstat (limited to 'src')
-rw-r--r--src/Core/Application.cpp96
-rw-r--r--src/Core/Application.h5
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.cpp17
-rw-r--r--src/Platform/OpenGL/OpenGLRendererAPI.h1
-rw-r--r--src/Platform/OpenGL/OpenGLTexture.cpp66
-rw-r--r--src/Platform/OpenGL/OpenGLTexture.h33
-rw-r--r--src/Rendering/Renderer.h6
-rw-r--r--src/Rendering/Texture.cpp32
-rw-r--r--src/Rendering/Texture.h30
9 files changed, 273 insertions, 13 deletions
diff --git a/src/Core/Application.cpp b/src/Core/Application.cpp
index 1af049a..0fd0023 100644
--- a/src/Core/Application.cpp
+++ b/src/Core/Application.cpp
@@ -5,6 +5,7 @@
#include "Rendering/VertexBuffer.h"
#include "Rendering/IndexBuffer.h"
#include "Rendering/Shader.h"
+#include "Rendering/Texture.h"
#include <iostream>
#include <glm/glm.hpp>
@@ -71,6 +72,8 @@ namespace Donut
else
m_Minimized = false;
+ Renderer::OnWindowResize(e.GetWidth(), e.GetHeight());
+
if (m_Camera)
m_Camera->SetProjection(45.0f, (float)e.GetWidth() / (float)e.GetHeight(), 0.1f, 100.0f);
@@ -150,6 +153,8 @@ namespace Donut
void Application::OnInit()
{
Renderer::Init();
+ Renderer::OnWindowResize(1280, 720);
+ RenderCommand::SetFaceCulling(false);
m_Camera = std::make_unique<Camera>(45.0f, 1280.0f / 720.0f, 0.1f, 100.0f);
m_Camera->SetPosition({ 0.0f, 0.0f, 3.0f });
@@ -158,14 +163,15 @@ namespace Donut
float vertices[] =
{
- -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f,
- 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f,
- 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f,
- -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f,
- -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f,
- 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f,
- 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 1.0f,
- -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f
+ // Position (3) | Color (4) | TexCoords (2)
+ -0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,
+ 0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f,
+ -0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f,
+ 0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f,
+ 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,
+ -0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f
};
uint32_t indices[] =
@@ -175,7 +181,7 @@ namespace Donut
5, 4, 7, 7, 6, 5,
4, 0, 3, 3, 7, 4,
3, 2, 6, 6, 7, 3,
- 4, 5, 1, 1, 0, 4
+ 4, 5, 1, 1, 0, 4
};
m_VertexArray = std::shared_ptr<VertexArray>(VertexArray::Create());
@@ -184,6 +190,7 @@ namespace Donut
VertexBufferLayout layout;
layout.Push<float>(3);
layout.Push<float>(4);
+ layout.Push<float>(2);
m_VertexBuffer->SetLayout(layout);
m_VertexArray->AddVertexBuffer(m_VertexBuffer);
@@ -191,7 +198,32 @@ namespace Donut
m_IndexBuffer = std::shared_ptr<IndexBuffer>(IndexBuffer::Create(indices, 36));
m_VertexArray->SetIndexBuffer(m_IndexBuffer);
- m_Shader = std::shared_ptr<Shader>(Shader::Create("assets/Basic.glsl"));
+ m_Shader = std::shared_ptr<Shader>(Shader::Create("assets/Textured.glsl"));
+
+ m_Texture = Texture2D::Create(256, 256);
+
+ uint32_t* pixelData = new uint32_t[256 * 256];
+ for (int y = 0; y < 256; y++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ float u = (float)x / 256.0f;
+ float v = (float)y / 256.0f;
+
+ float wave = sin(u * 10.0f) * cos(v * 10.0f);
+ wave = (wave + 1.0f) * 0.5f;
+
+ uint8_t r = (uint8_t)(wave * 255);
+ uint8_t g = (uint8_t)((1.0f - wave) * 255);
+ uint8_t b = (uint8_t)((u + v) * 0.5f * 255);
+ uint8_t a = 255;
+
+ pixelData[y * 256 + x] = (a << 24) | (b << 16) | (g << 8) | r;
+ }
+ }
+
+ m_Texture->SetData(pixelData, 256 * 256 * 4);
+ delete[] pixelData;
}
void Application::OnShutdown()
@@ -215,11 +247,13 @@ namespace Donut
m_Camera->MoveLeft(m_DeltaTime);
if (m_Keys[GLFW_KEY_D])
m_Camera->MoveRight(m_DeltaTime);
- if (m_Keys[GLFW_KEY_SPACE])
+ if (m_Keys[GLFW_KEY_SPACE])
m_Camera->MoveUp(m_DeltaTime);
if (m_Keys[GLFW_KEY_LEFT_SHIFT])
- m_Camera->MoveDown(m_DeltaTime);
+ m_Camera->MoveDown(m_DeltaTime);
}
+
+ UpdateTexture();
}
void Application::OnRender()
@@ -227,6 +261,12 @@ namespace Donut
Renderer::SetClearColor({ 0.0f, 0.0f, 0.0f, 1.0f });
Renderer::Clear();
+ if (m_Texture)
+ {
+ m_Texture->Bind(0);
+ m_Shader->SetInt("u_Texture", 0);
+ }
+
glm::mat4 viewProjection = m_Camera ? m_Camera->GetViewProjectionMatrix() : glm::mat4(1.0f);
glm::vec3 centerPos(0.0f, 0.0f, 0.0f);
@@ -252,4 +292,36 @@ namespace Donut
transform = glm::translate(glm::mat4(1.0f), backPos);
Renderer::Submit(m_Shader, m_VertexArray, transform, viewProjection);
}
+
+ void Application::UpdateTexture()
+ {
+ if (!m_Texture)
+ return;
+
+ m_TextureTime += m_DeltaTime;
+
+ uint32_t* pixelData = new uint32_t[256 * 256];
+ for (int y = 0; y < 256; y++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ float time = m_TextureTime * 2.0f;
+ float u = (float)x / 256.0f;
+ float v = (float)y / 256.0f;
+
+ float wave = sin(u * 10.0f + time) * cos(v * 10.0f + time * 0.5f);
+ wave = (wave + 1.0f) * 0.5f;
+
+ uint8_t r = (uint8_t)(wave * 255);
+ uint8_t g = (uint8_t)((1.0f - wave) * 255);
+ uint8_t b = (uint8_t)((u + v) * 0.5f * 255);
+ uint8_t a = 255;
+
+ pixelData[y * 256 + x] = (a << 24) | (b << 16) | (g << 8) | r;
+ }
+ }
+
+ m_Texture->SetData(pixelData, 256 * 256 * 4);
+ delete[] pixelData;
+ }
}
diff --git a/src/Core/Application.h b/src/Core/Application.h
index 9e5d31d..7406136 100644
--- a/src/Core/Application.h
+++ b/src/Core/Application.h
@@ -12,6 +12,7 @@ namespace Donut
class VertexBuffer;
class IndexBuffer;
class Shader;
+ class Texture2D;
};
namespace Donut
@@ -34,6 +35,7 @@ namespace Donut
void OnUpdate();
void OnRender();
void OnEvent(Event& event);
+ void UpdateTexture();
private:
std::unique_ptr<Window> m_Window;
bool m_Running;
@@ -43,10 +45,10 @@ namespace Donut
std::shared_ptr<VertexBuffer> m_VertexBuffer;
std::shared_ptr<IndexBuffer> m_IndexBuffer;
std::shared_ptr<Shader> m_Shader;
+ std::shared_ptr<Texture2D> m_Texture;
std::unique_ptr<Camera> m_Camera;
- // Input state
bool m_Keys[1024] = { false };
bool m_FirstMouse = true;
float m_LastX = 0.0f;
@@ -54,6 +56,7 @@ namespace Donut
float m_DeltaTime = 0.0f;
float m_LastFrame = 0.0f;
bool m_MouseDragging = false;
+ float m_TextureTime = 0.0f;
static Application* s_Instance;
};
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.cpp b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
index 3660555..5ee7d8d 100644
--- a/src/Platform/OpenGL/OpenGLRendererAPI.cpp
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.cpp
@@ -8,6 +8,11 @@ namespace Donut
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LESS);
+
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glFrontFace(GL_CCW);
}
void OpenGLRendererAPI::SetViewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height)
@@ -30,6 +35,18 @@ namespace Donut
glEnable(GL_DEPTH_TEST);
}
+ void OpenGLRendererAPI::SetFaceCulling(bool enabled)
+ {
+ if (enabled)
+ {
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ glFrontFace(GL_CCW);
+ }
+ else
+ glDisable(GL_CULL_FACE);
+ }
+
void OpenGLRendererAPI::DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount)
{
uint32_t count = indexCount ? indexCount : vertexArray->GetIndexBuffer()->GetCount();
diff --git a/src/Platform/OpenGL/OpenGLRendererAPI.h b/src/Platform/OpenGL/OpenGLRendererAPI.h
index f37cc79..35bd9c3 100644
--- a/src/Platform/OpenGL/OpenGLRendererAPI.h
+++ b/src/Platform/OpenGL/OpenGLRendererAPI.h
@@ -14,6 +14,7 @@ namespace Donut
virtual void SetClearColor(const glm::vec4& color) override;
virtual void Clear() override;
virtual void EnableDepthTest() override;
+ virtual void SetFaceCulling(bool enabled) override;
virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount = 0) override;
};
diff --git a/src/Platform/OpenGL/OpenGLTexture.cpp b/src/Platform/OpenGL/OpenGLTexture.cpp
new file mode 100644
index 0000000..02252d1
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLTexture.cpp
@@ -0,0 +1,66 @@
+#include "OpenGLTexture.h"
+#include <iostream>
+
+namespace Donut
+{
+ OpenGLTexture2D::OpenGLTexture2D(uint32_t width, uint32_t height)
+ : m_Width(width), m_Height(height)
+ {
+ m_InternalFormat = GL_RGBA8;
+ m_DataFormat = GL_RGBA;
+
+ glCreateTextures(GL_TEXTURE_2D, 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_REPEAT);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ }
+
+ // TODO: Texture Loading
+ OpenGLTexture2D::OpenGLTexture2D(const std::string& path)
+ : m_Path(path)
+ {
+ m_Width = 1;
+ m_Height = 1;
+ m_InternalFormat = GL_RGBA8;
+ m_DataFormat = GL_RGBA;
+
+ glCreateTextures(GL_TEXTURE_2D, 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_REPEAT);
+ glTextureParameteri(m_RendererID, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
+ uint32_t whitePixel = 0xFFFFFFFF;
+ glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, &whitePixel);
+
+ std::cout << "Created default texture (stb_image not available for loading: " << path << ")" << std::endl;
+ }
+
+ OpenGLTexture2D::~OpenGLTexture2D()
+ {
+ glDeleteTextures(1, &m_RendererID);
+ }
+
+ void OpenGLTexture2D::SetData(void* data, uint32_t size)
+ {
+ uint32_t bpp = m_DataFormat == GL_RGBA ? 4 : 3;
+ if (size != m_Width * m_Height * bpp)
+ {
+ std::cout << "Data must be entire texture!" << std::endl;
+ return;
+ }
+ glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, m_DataFormat, GL_UNSIGNED_BYTE, data);
+ }
+
+ void OpenGLTexture2D::Bind(uint32_t slot) const
+ {
+ glBindTextureUnit(slot, m_RendererID);
+ }
+}; \ No newline at end of file
diff --git a/src/Platform/OpenGL/OpenGLTexture.h b/src/Platform/OpenGL/OpenGLTexture.h
new file mode 100644
index 0000000..4a95ab4
--- /dev/null
+++ b/src/Platform/OpenGL/OpenGLTexture.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "Rendering/Texture.h"
+#include <glad/glad.h>
+
+namespace Donut
+{
+ class OpenGLTexture2D : public Texture2D
+ {
+ public:
+ OpenGLTexture2D(uint32_t width, uint32_t height);
+ OpenGLTexture2D(const std::string& path);
+ virtual ~OpenGLTexture2D();
+
+ 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 bool operator==(const Texture& other) const override
+ {
+ return m_RendererID == other.GetRendererID();
+ }
+
+ private:
+ std::string m_Path;
+ uint32_t m_Width, m_Height;
+ uint32_t m_RendererID;
+ GLenum m_InternalFormat, m_DataFormat;
+ };
+}
diff --git a/src/Rendering/Renderer.h b/src/Rendering/Renderer.h
index d08d015..82c156e 100644
--- a/src/Rendering/Renderer.h
+++ b/src/Rendering/Renderer.h
@@ -34,6 +34,7 @@ namespace Donut
virtual void SetClearColor(const glm::vec4& color) = 0;
virtual void Clear() = 0;
virtual void EnableDepthTest() = 0;
+ virtual void SetFaceCulling(bool enabled) = 0;
virtual void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount = 0) = 0;
@@ -72,6 +73,11 @@ namespace Donut
s_RendererAPI->EnableDepthTest();
}
+ inline static void SetFaceCulling(bool enabled)
+ {
+ s_RendererAPI->SetFaceCulling(enabled);
+ }
+
inline static void DrawIndexed(const std::shared_ptr<VertexArray>& vertexArray, uint32_t indexCount = 0)
{
s_RendererAPI->DrawIndexed(vertexArray, indexCount);
diff --git a/src/Rendering/Texture.cpp b/src/Rendering/Texture.cpp
new file mode 100644
index 0000000..a52a469
--- /dev/null
+++ b/src/Rendering/Texture.cpp
@@ -0,0 +1,32 @@
+#include "Texture.h"
+#include "Renderer.h"
+#include "../Platform/OpenGL/OpenGLTexture.h"
+
+namespace Donut
+{
+ std::shared_ptr<Texture2D> Texture2D::Create(uint32_t width, uint32_t height)
+ {
+ switch (Renderer::GetAPI())
+ {
+ case RendererAPI::API::OpenGL:
+ return std::make_shared<OpenGLTexture2D>(width, height);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+
+ std::shared_ptr<Texture2D> Texture2D::Create(const std::string& path)
+ {
+ switch (Renderer::GetAPI())
+ {
+ case RendererAPI::API::OpenGL:
+ return std::make_shared<OpenGLTexture2D>(path);
+ case RendererAPI::API::None:
+ return nullptr;
+ default:
+ return nullptr;
+ }
+ }
+}; \ No newline at end of file
diff --git a/src/Rendering/Texture.h b/src/Rendering/Texture.h
new file mode 100644
index 0000000..eebce85
--- /dev/null
+++ b/src/Rendering/Texture.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <memory>
+#include <string>
+#include <glm/glm.hpp>
+
+namespace Donut
+{
+ class Texture
+ {
+ public:
+ virtual ~Texture() = default;
+
+ virtual uint32_t GetWidth() const = 0;
+ virtual uint32_t GetHeight() const = 0;
+ virtual uint32_t GetRendererID() const = 0;
+
+ virtual void SetData(void* data, uint32_t size) = 0;
+ virtual void Bind(uint32_t slot = 0) const = 0;
+
+ virtual bool operator==(const Texture& other) const = 0;
+ };
+
+ class Texture2D : public Texture
+ {
+ public:
+ static std::shared_ptr<Texture2D> Create(uint32_t width, uint32_t height);
+ static std::shared_ptr<Texture2D> Create(const std::string& path);
+ };
+}; \ No newline at end of file