add simple render, add simple pbr shader(from hazel)

This commit is contained in:
2025-11-26 17:48:04 +08:00
parent bade15a87f
commit 5bbda471bf
68 changed files with 10512 additions and 83 deletions

View File

@ -4,11 +4,14 @@ file(GLOB_RECURSE SRC_SOURCE src/**.cpp)
# ------------- configure -------------
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(ASSIMP_BUILD_ZLIB ON CACHE BOOL "Build built-in zlib" FORCE)
add_subdirectory(vendor/spdlog EXCLUDE_FROM_ALL)
add_subdirectory(vendor/glfw EXCLUDE_FROM_ALL)
add_subdirectory(vendor/glad EXCLUDE_FROM_ALL)
add_subdirectory(vendor/glm EXCLUDE_FROM_ALL)
add_subdirectory(vendor/assimp EXCLUDE_FROM_ALL)
add_subdirectory(vendor/stb EXCLUDE_FROM_ALL)
# ------------- imgui -------------
@ -27,6 +30,8 @@ set(LINK_LIBRARIES_PRIVATE
spdlog
glfw
glad
assimp
stb
)
set(LINK_LIBRARIES_PUBLIC
@ -78,8 +83,8 @@ target_precompile_headers(${STATIC_LIBRARY} PRIVATE
)
set_target_properties(${STATIC_LIBRARY} PROPERTIES
OUTPUT_NAME ${PROJECT_NAME}
ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}
OUTPUT_NAME ${PROJECT_NAME}d
ARCHIVE_OUTPUT_NAME ${PROJECT_NAME}d
)
# shared library
@ -106,8 +111,8 @@ target_precompile_headers(${SHARED_LIBRARY} PRIVATE
)
set_target_properties(${SHARED_LIBRARY} PROPERTIES
OUTPUT_NAME ${PROJECT_NAME}d
LIBRARY_OUTPUT_NAME ${PROJECT_NAME}d
OUTPUT_NAME ${PROJECT_NAME}
LIBRARY_OUTPUT_NAME ${PROJECT_NAME}
)

View File

@ -8,7 +8,13 @@
#include "glad/glad.h"
#include "Prism/Renderer/Renderer.h"
#include "Log.h"
#include "GLFW/glfw3.h"
#include "Prism/Renderer/FrameBuffer.h"
#include "Prism/Renderer/RendererAPI.h"
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
#include <Windows.h>
namespace Prism
{
@ -74,11 +80,45 @@ namespace Prism
void Application::RenderImGui()
{
m_ImGuiLayer->Begin();
ImGui::Begin("Renderer");
auto& caps = RendererAPI::GetCapabilities();
ImGui::Text("Vendor: %s", caps.Vendor.c_str());
ImGui::Text("Renderer: %s", caps.Renderer.c_str());
ImGui::Text("Version: %s", caps.Version.c_str());
ImGui::End();
for (Layer* layer : m_LayerStack)
layer->OnImGuiRender();
m_ImGuiLayer->End();
}
std::string Application::OpenFile(const std::string& filter) const
{
OPENFILENAMEA ofn; // common dialog box structure
CHAR szFile[260] = { 0 }; // if using TCHAR macros
// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = glfwGetWin32Window((GLFWwindow*)m_Window->GetNativeWindow());
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = "All\0*.*\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileNameA(&ofn) == TRUE)
{
return ofn.lpstrFile;
}
return std::string();
}
void Application::PushLayer(Layer* layer)
{
m_LayerStack.PushLayer(layer);
@ -93,6 +133,11 @@ namespace Prism
bool Application::OnWindowResize(const WindowResizeEvent& e)
{
int width = e.GetWidth(), height = e.GetHeight();
PM_RENDER_2(width, height, { glViewport(0, 0, width, height); });
auto& fbs = FrameBufferPool::GetGlobal()->GetAll();
for (auto& fb : fbs)
fb->Resize(width, height);
return false;
}

View File

@ -28,6 +28,8 @@ namespace Prism
void RenderImGui();
std::string OpenFile(const std::string& filter) const;
inline Window& GetWindow() { return *m_Window; }
inline static Application& Get() { return *s_Instance; }

View File

@ -23,8 +23,10 @@ namespace Prism {
}
}
#if defined(_WIN32)
#ifdef PRISM_SHARED
#if defined(_WIN32)
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
@ -59,4 +61,6 @@ static void library_unload() {
Prism::ShutdownCore();
}
#endif
#endif

View File

@ -22,6 +22,11 @@
#else
#define PRISM_API
#define IMGUI_API
namespace Prism
{
void InitializeCore();
void ShutdownCore();
}
#endif
#define BIT(x) (1 << x)

View File

@ -11,9 +11,18 @@ extern Prism::Application* Prism::CreateApplication();
int main(int argc, char** argv)
{
#ifndef PRISM_SHARED
Prism::InitializeCore();
#endif
Prism::Application* app = Prism::CreateApplication();
app->Run();
delete app;
#ifndef PRISM_SHARED
Prism::ShutdownCore();
#endif
}
#endif //ENTRYPOINT_H

View File

@ -6,6 +6,7 @@
#define KEYEVENT_H
#include "Event.h"
#include "KeyEvent.h"
namespace Prism {

View File

@ -66,6 +66,10 @@ namespace Prism
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
ImFont* pFont = io.Fonts->AddFontFromFileTTF(R"(C:\Windows\Fonts\segoeui.ttf)", 18.0f);
io.FontDefault = io.Fonts->Fonts.back();
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic();
@ -77,6 +81,7 @@ namespace Prism
style.WindowRounding = 0.0f;
style.Colors[ImGuiCol_WindowBg].w = 1.0f;
}
style.Colors[ImGuiCol_WindowBg] = ImVec4(0.15f, 0.15f, 0.15f, style.Colors[ImGuiCol_WindowBg].w);
Application& app = Application::Get();
const auto window = static_cast<GLFWwindow*>(app.GetWindow().GetNativeWindow());

View File

@ -10,11 +10,11 @@ namespace Prism
class Input
{
public:
static bool IsKeyPressed(int keycode) { return s_Instance->IsKeyPressed(keycode); }
static bool IsKeyPressed(const int keycode) { return s_Instance->IsKeyPressedImpl(keycode); }
inline static bool IsMouseButtonPressed(int button) { return s_Instance->IsMouseButtonPressed(button); }
inline static float GetMouseX() { return s_Instance->GetMouseX(); }
inline static float GetMouseY() { return s_Instance->GetMouseY(); }
inline static bool IsMouseButtonPressed(const int button) { return s_Instance->IsMouseButtonPressedImpl(button); }
inline static float GetMouseX() { return s_Instance->GetMouseXImpl(); }
inline static float GetMouseY() { return s_Instance->GetMouseYImpl(); }
protected:
virtual bool IsKeyPressedImpl(int keycode) = 0;
virtual bool IsMouseButtonPressedImpl(int button) = 0;

View File

@ -0,0 +1,134 @@
//
// Created by sfd on 25-11-23.
//
#ifndef KEYCODES_H
#define KEYCODES_H
#pragma once
// From glfw3.h
#define HZ_KEY_SPACE 32
#define HZ_KEY_APOSTROPHE 39 /* ' */
#define HZ_KEY_COMMA 44 /* , */
#define HZ_KEY_MINUS 45 /* - */
#define HZ_KEY_PERIOD 46 /* . */
#define HZ_KEY_SLASH 47 /* / */
#define HZ_KEY_0 48
#define HZ_KEY_1 49
#define HZ_KEY_2 50
#define HZ_KEY_3 51
#define HZ_KEY_4 52
#define HZ_KEY_5 53
#define HZ_KEY_6 54
#define HZ_KEY_7 55
#define HZ_KEY_8 56
#define HZ_KEY_9 57
#define HZ_KEY_SEMICOLON 59 /* ; */
#define HZ_KEY_EQUAL 61 /* = */
#define HZ_KEY_A 65
#define HZ_KEY_B 66
#define HZ_KEY_C 67
#define HZ_KEY_D 68
#define HZ_KEY_E 69
#define HZ_KEY_F 70
#define HZ_KEY_G 71
#define HZ_KEY_H 72
#define HZ_KEY_I 73
#define HZ_KEY_J 74
#define HZ_KEY_K 75
#define HZ_KEY_L 76
#define HZ_KEY_M 77
#define HZ_KEY_N 78
#define HZ_KEY_O 79
#define HZ_KEY_P 80
#define HZ_KEY_Q 81
#define HZ_KEY_R 82
#define HZ_KEY_S 83
#define HZ_KEY_T 84
#define HZ_KEY_U 85
#define HZ_KEY_V 86
#define HZ_KEY_W 87
#define HZ_KEY_X 88
#define HZ_KEY_Y 89
#define HZ_KEY_Z 90
#define HZ_KEY_LEFT_BRACKET 91 /* [ */
#define HZ_KEY_BACKSLASH 92 /* \ */
#define HZ_KEY_RIGHT_BRACKET 93 /* ] */
#define HZ_KEY_GRAVE_ACCENT 96 /* ` */
#define HZ_KEY_WORLD_1 161 /* non-US #1 */
#define HZ_KEY_WORLD_2 162 /* non-US #2 */
/* Function keys */
#define HZ_KEY_ESCAPE 256
#define HZ_KEY_ENTER 257
#define HZ_KEY_TAB 258
#define HZ_KEY_BACKSPACE 259
#define HZ_KEY_INSERT 260
#define HZ_KEY_DELETE 261
#define HZ_KEY_RIGHT 262
#define HZ_KEY_LEFT 263
#define HZ_KEY_DOWN 264
#define HZ_KEY_UP 265
#define HZ_KEY_PAGE_UP 266
#define HZ_KEY_PAGE_DOWN 267
#define HZ_KEY_HOME 268
#define HZ_KEY_END 269
#define HZ_KEY_CAPS_LOCK 280
#define HZ_KEY_SCROLL_LOCK 281
#define HZ_KEY_NUM_LOCK 282
#define HZ_KEY_PRINT_SCREEN 283
#define HZ_KEY_PAUSE 284
#define HZ_KEY_F1 290
#define HZ_KEY_F2 291
#define HZ_KEY_F3 292
#define HZ_KEY_F4 293
#define HZ_KEY_F5 294
#define HZ_KEY_F6 295
#define HZ_KEY_F7 296
#define HZ_KEY_F8 297
#define HZ_KEY_F9 298
#define HZ_KEY_F10 299
#define HZ_KEY_F11 300
#define HZ_KEY_F12 301
#define HZ_KEY_F13 302
#define HZ_KEY_F14 303
#define HZ_KEY_F15 304
#define HZ_KEY_F16 305
#define HZ_KEY_F17 306
#define HZ_KEY_F18 307
#define HZ_KEY_F19 308
#define HZ_KEY_F20 309
#define HZ_KEY_F21 310
#define HZ_KEY_F22 311
#define HZ_KEY_F23 312
#define HZ_KEY_F24 313
#define HZ_KEY_F25 314
#define HZ_KEY_KP_0 320
#define HZ_KEY_KP_1 321
#define HZ_KEY_KP_2 322
#define HZ_KEY_KP_3 323
#define HZ_KEY_KP_4 324
#define HZ_KEY_KP_5 325
#define HZ_KEY_KP_6 326
#define HZ_KEY_KP_7 327
#define HZ_KEY_KP_8 328
#define HZ_KEY_KP_9 329
#define HZ_KEY_KP_DECIMAL 330
#define HZ_KEY_KP_DIVIDE 331
#define HZ_KEY_KP_MULTIPLY 332
#define HZ_KEY_KP_SUBTRACT 333
#define HZ_KEY_KP_ADD 334
#define HZ_KEY_KP_ENTER 335
#define HZ_KEY_KP_EQUAL 336
#define HZ_KEY_LEFT_SHIFT 340
#define HZ_KEY_LEFT_CONTROL 341
#define HZ_KEY_LEFT_ALT 342
#define HZ_KEY_LEFT_SUPER 343
#define HZ_KEY_RIGHT_SHIFT 344
#define HZ_KEY_RIGHT_CONTROL 345
#define HZ_KEY_RIGHT_ALT 346
#define HZ_KEY_RIGHT_SUPER 347
#define HZ_KEY_MENU 348
#endif //KEYCODES_H

View File

@ -29,12 +29,10 @@ namespace Prism
void OpenGLVertexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
{
m_Size = size;
PM_RENDER_S3(buffer, size, offset, {
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0);
});
}
@ -42,6 +40,11 @@ namespace Prism
{
PM_RENDER_S({
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 5, (const void*)(3 * sizeof(float)));
});
}
@ -66,6 +69,7 @@ namespace Prism
void OpenGLIndexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
{
m_Size = size;
PM_RENDER_S3(buffer, size, offset, {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->m_RendererID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);

View File

@ -43,6 +43,8 @@ namespace Prism
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0);
virtual void Bind() const;
virtual uint32_t GetCount() const { return m_Size / sizeof(uint32_t); }
virtual unsigned int GetSize() const { return m_Size; }
virtual RendererID GetRendererID() const { return m_RendererID; }
private:

View File

@ -0,0 +1,98 @@
//
// Created by sfd on 25-11-23.
//
#include "OpenGLFrameBuffer.h"
#include "glad/glad.h"
#include "Prism/Core/Log.h"
#include "Prism/Renderer/Renderer.h"
namespace Prism
{
OpenGLFrameBuffer::OpenGLFrameBuffer(const uint32_t width, const uint32_t height, const FramebufferFormat format)
: m_Width(width), m_Height(height), m_Format(format)
{
Resize(width, height);
}
OpenGLFrameBuffer::~OpenGLFrameBuffer()
{
PM_RENDER_S({
glDeleteFramebuffers(1, &self->m_RendererID);
});
}
void OpenGLFrameBuffer::Bind() const
{
PM_RENDER_S({
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
glViewport(0, 0, self->m_Width, self->m_Height);
});
}
void OpenGLFrameBuffer::Unbind() const
{
PM_RENDER_S({
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
}
void OpenGLFrameBuffer::Resize(uint32_t width, uint32_t height)
{
if (m_Width == width && m_Height == height)
return;
m_Width = width;
m_Height = height;
PM_RENDER_S({
if (self->m_RendererID)
{
glDeleteFramebuffers(1, &self->m_RendererID);
glDeleteTextures(1, &self->m_ColorAttachment);
glDeleteTextures(1, &self->m_DepthAttachment);
}
glGenFramebuffers(1, &self->m_RendererID);
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
glGenTextures(1, &self->m_ColorAttachment);
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
// TODO: Create Hazel texture object based on format here
if (self->m_Format == FramebufferFormat::RGBA16F)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, self->m_Width, self->m_Height, 0, GL_RGBA, GL_FLOAT, nullptr);
}
else if (self->m_Format == FramebufferFormat::RGBA8)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->m_Width, self->m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->m_ColorAttachment, 0);
glGenTextures(1, &self->m_DepthAttachment);
glBindTexture(GL_TEXTURE_2D, self->m_DepthAttachment);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, self->m_Width, self->m_Height, 0,
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, self->m_DepthAttachment, 0);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
PM_CORE_ERROR("Framebuffer is incomplete!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
});
}
void OpenGLFrameBuffer::BindTexture(uint32_t slot) const
{
PM_RENDER_S1(slot, {
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
});
}
}

View File

@ -0,0 +1,42 @@
//
// Created by sfd on 25-11-23.
//
#ifndef OPENGLFRAMEBUFFER_H
#define OPENGLFRAMEBUFFER_H
#include "Prism/Renderer/FrameBuffer.h"
namespace Prism
{
class OpenGLFrameBuffer : public FrameBuffer
{
public:
OpenGLFrameBuffer(uint32_t width, uint32_t height, FramebufferFormat format);
virtual ~OpenGLFrameBuffer();
void Bind() const override;
void Unbind() const override;
void Resize(uint32_t width, uint32_t height) override;
void BindTexture(uint32_t slot) const override;
RendererID GetRendererID() const override { return m_RendererID; }
RendererID GetColorAttachmentRendererID() const override { return m_ColorAttachment; }
RendererID GetDepthAttachmentRendererID() const override { return m_DepthAttachment; }
virtual uint32_t GetWidth() const { return m_Width; }
virtual uint32_t GetHeight() const { return m_Height; }
virtual FramebufferFormat GetFormat() const { return m_Format; }
private:
RendererID m_RendererID = 0;
uint32_t m_Width, m_Height;
FramebufferFormat m_Format;
RendererID m_ColorAttachment, m_DepthAttachment;
};
}
#endif //OPENGLFRAMEBUFFER_H

View File

@ -6,14 +6,42 @@
#include "Prism/Renderer/RendererAPI.h"
#include "glad/glad.h"
#include "Prism/Core/Log.h"
namespace Prism
{
static void OpenGLLogMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
PM_CORE_ERROR("{0}", message);
}
void RendererAPI::Init()
{
glDebugMessageCallback(OpenGLLogMessage, nullptr);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
unsigned int vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
glFrontFace(GL_CCW);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
auto& caps = GetCapabilities();
caps.Vendor = (const char*)glGetString(GL_VENDOR);
caps.Renderer = (const char*)glGetString(GL_RENDERER);
caps.Version = (const char*)glGetString(GL_VERSION);
glGetIntegerv(GL_MAX_SAMPLES, &caps.MaxSamples);
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &caps.MaxAnisotropy);
}
void RendererAPI::Shutdown()
@ -31,8 +59,13 @@ namespace Prism
glClearColor(r, g, b, a);
}
void RendererAPI::DrawIndexed(const int count)
void RendererAPI::DrawIndexed(const unsigned int count, bool depthTest)
{
if (depthTest)
glEnable(GL_DEPTH_TEST);
else
glDisable(GL_DEPTH_TEST);
glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr);
}
}

View File

@ -10,9 +10,23 @@
namespace Prism
{
OpenGLShader::OpenGLShader(const std::string& filepath)
: m_AssetPath(filepath)
{
ReadShaderFromFile(filepath);
CompileAndUploadShader();
size_t found = filepath.find_last_of("/\\");
m_Name = found != std::string::npos ? filepath.substr(found + 1) : filepath;
Reload();
}
void OpenGLShader::Reload()
{
ReadShaderFromFile(m_AssetPath);
PM_RENDER_S({
if (self->m_RendererID)
glDeleteShader(self->m_RendererID);
self->CompileAndUploadShader();
});
}
void OpenGLShader::Bind()
@ -37,6 +51,14 @@ namespace Prism
self->UploadUniformFloat(name, value);
});
}
case UniformType::Float3:
{
const std::string& name = decl.Name;
glm::vec3& values = *(glm::vec3*)(uniformBuffer.GetBuffer() + decl.Offset);
PM_RENDER_S2(name, values, {
self->UploadUniformFloat3(name, values);
});
}
case UniformType::Float4:
{
const std::string& name = decl.Name;
@ -45,10 +67,38 @@ namespace Prism
self->UploadUniformFloat4(name, values);
});
}
case UniformType::Mat4:
{
const std::string& name = decl.Name;
glm::mat4& values = *(glm::mat4*)(uniformBuffer.GetBuffer() + decl.Offset);
PM_RENDER_S2(name, values, {
self->UploadUniformMat4(name, values);
});
}
}
}
}
void OpenGLShader::SetFloat(const std::string& name, float value)
{
PM_RENDER_S2(name, value, {
self->UploadUniformFloat(name, value);
});
}
void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
{
PM_RENDER_S2(name, value, {
self->UploadUniformMat4(name, value);
});
}
const std::string& OpenGLShader::GetName() const
{
return m_Name;
}
void OpenGLShader::ReadShaderFromFile(const std::string& filepath)
{
std::ifstream file(filepath, std::ios::in | std::ios::binary);
@ -71,6 +121,7 @@ namespace Prism
{
std::istringstream ss(m_ShaderSource);
std::string token;
/*
while (ss >> token)
{
if (token == "#type")
@ -82,6 +133,7 @@ namespace Prism
PM_CORE_TRACE("{}", token.c_str());
}
*/
std::unordered_map<GLenum, std::string> shaderSources;
@ -119,7 +171,7 @@ namespace Prism
const std::string& source = kv.second;
GLuint shaderRendererID = glCreateShader(type);
const GLchar* sourcePtr = source.c_str();
glShaderSource(shaderRendererID, 1, &sourcePtr, NULL);
glShaderSource(shaderRendererID, 1, &sourcePtr, nullptr);
glCompileShader(shaderRendererID);
@ -167,6 +219,20 @@ namespace Prism
glDetachShader(program, id);
m_RendererID = program;
// Bind default texture unit
UploadUniformInt("u_Texture", 0);
// PBR shader textures
UploadUniformInt("u_AlbedoTexture", 1);
UploadUniformInt("u_NormalTexture", 2);
UploadUniformInt("u_MetalnessTexture", 3);
UploadUniformInt("u_RoughnessTexture", 4);
UploadUniformInt("u_EnvRadianceTex", 10);
UploadUniformInt("u_EnvIrradianceTex", 11);
UploadUniformInt("u_BRDFLUTTexture", 15);
}
GLenum OpenGLShader::ShaderTypeFromString(const std::string& type)
@ -179,15 +245,63 @@ namespace Prism
return GL_NONE;
}
void OpenGLShader::UploadUniformFloat(const std::string& name, float value)
void OpenGLShader::UploadUniformInt(const std::string& name, const int value) const
{
glUseProgram(m_RendererID);
glUniform1f(glGetUniformLocation(m_RendererID, name.c_str()), value);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniform1i(location, value);
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values)
void OpenGLShader::UploadUniformFloat(const std::string& name, const float value) const
{
glUseProgram(m_RendererID);
glUniform4f(glGetUniformLocation(m_RendererID, name.c_str()), values.x, values.y, values.z, values.w);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniform1f(location, value);
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
void OpenGLShader::UploadUniformFloat2(const std::string& name, const glm::vec2& values) const
{
glUseProgram(m_RendererID);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniform2fv(location,1, glm::value_ptr(values));
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
void OpenGLShader::UploadUniformFloat3(const std::string& name, const glm::vec3& values) const
{
glUseProgram(m_RendererID);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniform3fv(location,1, glm::value_ptr(values));
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
void OpenGLShader::UploadUniformFloat4(const std::string& name, const glm::vec4& values) const
{
glUseProgram(m_RendererID);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniform4fv(location,1, glm::value_ptr(values));
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
void OpenGLShader::UploadUniformMat4(const std::string& name, const glm::mat4& values) const
{
glUseProgram(m_RendererID);
auto location = glGetUniformLocation(m_RendererID, name.c_str());
if (location != -1)
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(values));
else
PM_CORE_WARN("Uniform '{0}' not found!", name);
}
}

View File

@ -16,22 +16,32 @@ namespace Prism
public:
OpenGLShader(const std::string& filepath);
virtual void Reload();
virtual void Bind() override;
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) override;
virtual void SetFloat(const std::string& name, float value) override;
virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
const std::string& GetName() const override;
private:
void ReadShaderFromFile(const std::string& filepath);
void CompileAndUploadShader();
static GLenum ShaderTypeFromString(const std::string& type);
void UploadUniformFloat(const std::string& name, float value);
void UploadUniformFloat2(const std::string& name, float* values);
void UploadUniformFloat3(const std::string& name, float* values);
void UploadUniformFloat4(const std::string& name, const glm::vec4& values);
void UploadUniformInt(const std::string& name, int value) const;
void UploadUniformFloat(const std::string& name, float value) const;
void UploadUniformFloat2(const std::string& name, const glm::vec2& values) const;
void UploadUniformFloat3(const std::string& name, const glm::vec3& values) const;
void UploadUniformFloat4(const std::string& name, const glm::vec4& values) const;
void UploadUniformMat4(const std::string& name, const glm::mat4& values) const;
private:
RendererID m_RendererID;
std::string m_Name, m_AssetPath;
std::string m_ShaderSource;
};
}

View File

@ -4,8 +4,10 @@
#include "OpenGLTexture.h"
#include "glad/glad.h"
#include "Prism/Renderer/Renderer.h"
#include "glad/glad.h"
#include "stb_image.h"
#include "Prism/Core/Log.h"
namespace Prism
{
@ -13,12 +15,23 @@ namespace Prism
{
switch (format)
{
case Prism::TextureFormat::RGB: return GL_RGB;
case Prism::TextureFormat::RGBA: return GL_RGBA;
case TextureFormat::RGB: return GL_RGB;
case TextureFormat::RGBA: return GL_RGBA;
}
return 0;
}
static int CalculateMipMapCount(const int width, const int height)
{
int levels = 1;
while ((width | height) >> levels) {
levels++;
}
return levels;
}
// ******************************************
// Texture2D
// ******************************************
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height)
: m_Format(format), m_Width(width), m_Height(height)
@ -27,13 +40,186 @@ namespace Prism
PM_RENDER_1(self, {
glGenTextures(1, &self->m_RendererID);
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, nullptr);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
});
}
OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb)
: m_FilePath(path)
{
int width, height, channels;
PM_CORE_INFO("Loading texture {0}, srgb={1}", path, srgb);
m_ImageData = stbi_load(path.c_str(), &width, &height, &channels, srgb ? STBI_rgb : STBI_rgb_alpha);
m_Width = width;
m_Height = height;
m_Format = TextureFormat::RGBA;
PM_RENDER_S1(srgb, {
// TODO: Consolidate properly
if (srgb)
{
glCreateTextures(GL_TEXTURE_2D, 1, &self->m_RendererID);
int levels = CalculateMipMapCount(self->m_Width, self->m_Height);
PM_CORE_INFO("Creating srgb texture width {0} mips", levels);
glTextureStorage2D(self->m_RendererID, levels, GL_SRGB8, self->m_Width, self->m_Height);
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureSubImage2D(self->m_RendererID, 0, 0, 0, self->m_Width, self->m_Height, GL_RGB, GL_UNSIGNED_BYTE, self->m_ImageData);
glGenerateTextureMipmap(self->m_RendererID);
}
else
{
glGenTextures(1, &self->m_RendererID);
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, srgb ? GL_SRGB8 : PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, self->m_ImageData);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
stbi_image_free(self->m_ImageData);
});
}
OpenGLTexture2D::~OpenGLTexture2D()
{
auto self = this;
PM_RENDER_1(self, {
glDeleteTextures(1, &self->m_RendererID);
});
}
void OpenGLTexture2D::Bind(unsigned int slot) const
{
PM_RENDER_S1(slot, {
glBindTextureUnit(slot, self->m_RendererID);
});
}
// ******************************************
// TextureCube
// ******************************************
OpenGLTextureCube::OpenGLTextureCube(const std::string& path)
: m_FilePath(path)
{
int width, height, channels;
stbi_set_flip_vertically_on_load(false);
m_ImageData = stbi_load(path.c_str(), &width, &height, &channels, STBI_rgb);
m_Width = width;
m_Height = height;
m_Format = TextureFormat::RGB;
unsigned int faceWidth = m_Width / 4;
unsigned int faceHeight = m_Height / 3;
PM_CORE_ASSERT(faceWidth == faceHeight, "Non-square faces!");
std::array<unsigned char*, 6> faces;
for (size_t i = 0; i < faces.size(); i++)
faces[i] = new unsigned char[faceWidth * faceHeight * 3]; // 3 BPP
int faceIndex = 0;
for (size_t i = 0; i < 4; i++)
{
for (size_t y = 0; y < faceHeight; y++)
{
size_t yOffset = y + faceHeight;
for (size_t x = 0; x < faceWidth; x++)
{
size_t xOffset = x + i * faceWidth;
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
}
}
faceIndex++;
}
for (size_t i = 0; i < 3; i++)
{
// Skip the middle one
if (i == 1)
continue;
for (size_t y = 0; y < faceHeight; y++)
{
size_t yOffset = y + i * faceHeight;
for (size_t x = 0; x < faceWidth; x++)
{
size_t xOffset = x + faceWidth;
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
}
}
faceIndex++;
}
PM_RENDER_S3(faces, faceWidth, faceHeight, {
glGenTextures(1, &self->m_RendererID);
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
auto format = PrismToOpenGLTextureFormat(self->m_Format);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[2]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[4]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[5]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[1]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[3]);
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
glBindTexture(GL_TEXTURE_2D, 0);
for (size_t i = 0; i < faces.size(); i++)
delete[] faces[i];
stbi_image_free(self->m_ImageData);
});
}
OpenGLTextureCube::~OpenGLTextureCube()
{
auto self = this;
PM_RENDER_1(self, {
glDeleteTextures(1, &self->m_RendererID);
});
}
void OpenGLTextureCube::Bind(unsigned int slot) const
{
PM_RENDER_S1(slot, {
glActiveTexture(GL_TEXTURE0 + slot);
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
});
}
}

View File

@ -14,15 +14,52 @@ namespace Prism
{
public:
OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height);
~OpenGLTexture2D();
OpenGLTexture2D(const std::string& path, bool srgb);
virtual ~OpenGLTexture2D();
virtual void Bind(unsigned int slot = 0) const override;
virtual TextureFormat GetFormat() const { return m_Format; }
virtual unsigned int GetWidth() const { return m_Width; }
virtual unsigned int GetHeight() const { return m_Height; }
virtual const std::string& GetPath() const override { return m_FilePath; }
virtual RendererID GetRendererID() const override { return m_RendererID; }
private:
RendererID m_RendererID;
TextureFormat m_Format;
unsigned int m_Width, m_Height;
unsigned char* m_ImageData;
std::string m_FilePath;
};
class OpenGLTextureCube : public TextureCube
{
public:
OpenGLTextureCube(const std::string& path);
virtual ~OpenGLTextureCube();
virtual void Bind(unsigned int slot = 0) const override;
virtual TextureFormat GetFormat() const override { return m_Format; }
virtual unsigned int GetWidth() const override { return m_Width; }
virtual unsigned int GetHeight() const override { return m_Height; }
virtual const std::string& GetPath() const override { return m_FilePath; }
virtual RendererID GetRendererID() const override { return m_RendererID; }
private:
RendererID m_RendererID;
TextureFormat m_Format;
unsigned int m_Width, m_Height;
unsigned char* m_ImageData;
std::string m_FilePath;
};
}

View File

@ -11,6 +11,7 @@
namespace Prism
{
Input* Input::s_Instance = new WindowsInput;
bool WindowsInput::IsKeyPressedImpl(const int keycode)
{

View File

@ -71,8 +71,8 @@ namespace Prism
int success = glfwInit();
PM_CORE_ASSERT(success, "Could not initialize GLFW!");
glfwSetErrorCallback(GLFWErrorCallback);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
s_GLFWInitialized = true;

View File

@ -32,6 +32,7 @@ namespace Prism
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0) = 0;
virtual void Bind() const = 0;
virtual uint32_t GetCount() const = 0;
virtual unsigned int GetSize() const = 0;
virtual RendererID GetRendererID() const = 0;

View File

@ -0,0 +1,111 @@
//
// Created by sfd on 25-11-23.
//
#include "Camera.h"
#include "GLFW/glfw3.h"
#include "glm/detail/type_quat.hpp"
#include "glm/gtc/quaternion.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include "glm/gtx/quaternion.hpp"
#include "Prism/Core/Input.h"
#define M_PI 3.14159f
namespace Prism
{
Camera::Camera(const glm::mat4& projectionMatrix)
: m_ProjectionMatrix(projectionMatrix)
{
// Sensible defaults
m_PanSpeed = 0.0015f;
m_RotationSpeed = 0.002f;
m_ZoomSpeed = 0.2f;
m_Position = { 0, 0, 10 };
m_Rotation = glm::vec3(90.0f, 0.0f, 0.0f);
m_FocalPoint = glm::vec3(0.0f);
m_Distance = glm::distance(m_Position, m_FocalPoint);
m_Yaw = 3.0f * (float)M_PI / 4.0f;
m_Pitch = M_PI / 4.0f;
}
void Camera::Focus()
{
}
void Camera::Update()
{
if (Input::IsKeyPressed(GLFW_KEY_LEFT_ALT))
{
const glm::vec2& mouse{ Input::GetMouseX(), Input::GetMouseY() };
glm::vec2 delta = mouse - m_InitialMousePosition;
m_InitialMousePosition = mouse;
if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_MIDDLE))
MousePan(delta);
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_LEFT))
MouseRotate(delta);
else if (Input::IsMouseButtonPressed(GLFW_MOUSE_BUTTON_RIGHT))
MouseZoom(delta.y);
}
m_Position = CalculatePosition();
glm::quat orientation = GetOrientation();
m_Rotation = glm::eulerAngles(orientation) * (180.0f / (float)M_PI);
m_ViewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 1)) * glm::toMat4(glm::conjugate(orientation)) * glm::translate(glm::mat4(1.0f), -m_Position);
}
glm::vec3 Camera::GetUpDirection()
{
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 1.0f, 0.0f));
}
glm::vec3 Camera::GetRightDirection()
{
return glm::rotate(GetOrientation(), glm::vec3(1.0f, 0.0f, 0.0f));
}
glm::vec3 Camera::GetForwardDirection()
{
return glm::rotate(GetOrientation(), glm::vec3(0.0f, 0.0f, -1.0f));
}
void Camera::MousePan(const glm::vec2& delta)
{
m_FocalPoint += -GetRightDirection() * delta.x * m_PanSpeed * m_Distance;
m_FocalPoint += GetUpDirection() * delta.y * m_PanSpeed * m_Distance;
}
void Camera::MouseRotate(const glm::vec2& delta)
{
float yawSign = GetUpDirection().y < 0 ? -1.0f : 1.0f;
m_Yaw += yawSign * delta.x * m_RotationSpeed;
m_Pitch += delta.y * m_RotationSpeed;
}
void Camera::MouseZoom(float delta)
{
m_Distance -= delta * m_ZoomSpeed;
if (m_Distance < 1.0f)
{
m_FocalPoint += GetForwardDirection();
m_Distance = 1.0f;
}
}
glm::vec3 Camera::CalculatePosition()
{
return m_FocalPoint - GetForwardDirection() * m_Distance;
}
glm::quat Camera::GetOrientation()
{
return glm::quat(glm::vec3(-m_Pitch, -m_Yaw, 0.0f));
}
}

View File

@ -0,0 +1,55 @@
//
// Created by sfd on 25-11-23.
//
#ifndef CAMERA_H
#define CAMERA_H
#include <glm/glm.hpp>
namespace Prism
{
class Camera
{
public:
Camera(const glm::mat4& projectionMatrix);
void Focus();
void Update();
inline float GetDistance() const { return m_Distance; }
inline void SetDistance(float distance) { m_Distance = distance; }
inline void SetProjectionMatrix(const glm::mat4& projectionMatrix) { m_ProjectionMatrix = projectionMatrix; }
const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; }
const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; }
glm::vec3 GetUpDirection();
glm::vec3 GetRightDirection();
glm::vec3 GetForwardDirection();
const glm::vec3& GetPosition() const { return m_Position; }
private:
void MousePan(const glm::vec2& delta);
void MouseRotate(const glm::vec2& delta);
void MouseZoom(float delta);
glm::vec3 CalculatePosition();
glm::quat GetOrientation();
private:
glm::mat4 m_ProjectionMatrix, m_ViewMatrix;
glm::vec3 m_Position, m_Rotation, m_FocalPoint;
bool m_Panning, m_Rotating;
glm::vec2 m_InitialMousePosition;
glm::vec3 m_InitialFocalPoint, m_InitialRotation;
float m_Distance;
float m_PanSpeed, m_RotationSpeed, m_ZoomSpeed;
float m_Pitch, m_Yaw;
};
}
#endif //CAMERA_H

View File

@ -0,0 +1,46 @@
//
// Created by sfd on 25-11-23.
//
#include "FrameBuffer.h"
#include "Prism/Platform/OpenGL/OpenGLFrameBuffer.h"
namespace Prism
{
FrameBuffer* Prism::FrameBuffer::Create(uint32_t width, uint32_t height, FramebufferFormat format)
{
FrameBuffer* result = nullptr;
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: result = new OpenGLFrameBuffer(width, height, format);
}
FrameBufferPool::GetGlobal()->Add(result);
return result;
}
FrameBufferPool* FrameBufferPool::s_Instance = new FrameBufferPool;
FrameBufferPool::FrameBufferPool(uint32_t maxFBs)
{
}
FrameBufferPool::~FrameBufferPool()
{
}
std::weak_ptr<FrameBuffer> FrameBufferPool::AllocateBuffer()
{
// m_Pool.push_back();
return std::weak_ptr<FrameBuffer>();
}
void FrameBufferPool::Add(FrameBuffer* framebuffer)
{
m_Pool.push_back(framebuffer);
}
}

View File

@ -0,0 +1,57 @@
//
// Created by sfd on 25-11-23.
//
#ifndef FRAMEBUFFER_H
#define FRAMEBUFFER_H
#include "RendererAPI.h"
namespace Prism
{
enum class FramebufferFormat
{
None = 0,
RGBA8 = 1,
RGBA16F = 2
};
class FrameBuffer
{
public:
static FrameBuffer* Create(uint32_t width, uint32_t height, FramebufferFormat format);
virtual ~FrameBuffer() {}
virtual void Bind() const = 0;
virtual void Unbind() const = 0;
virtual void Resize(uint32_t width, uint32_t height) = 0;
virtual void BindTexture(uint32_t slot = 0) const = 0;
virtual RendererID GetRendererID() const = 0;
virtual RendererID GetColorAttachmentRendererID() const = 0;
virtual RendererID GetDepthAttachmentRendererID() const = 0;
};
class FrameBufferPool final
{
public:
FrameBufferPool(uint32_t maxFBs = 32);
~FrameBufferPool();
std::weak_ptr<FrameBuffer> AllocateBuffer();
void Add(FrameBuffer* framebuffer);
const std::vector<FrameBuffer*>& GetAll() const { return m_Pool; }
inline static FrameBufferPool* GetGlobal() { return s_Instance; }
private:
std::vector<FrameBuffer*> m_Pool;
static FrameBufferPool* s_Instance;
};
}
#endif //FRAMEBUFFER_H

View File

@ -0,0 +1,129 @@
//
// Created by sfd on 25-11-23.
//
#include "Mesh.h"
#include "Renderer.h"
#include "assimp/DefaultLogger.hpp"
#include "assimp/Importer.hpp"
#include "assimp/LogStream.hpp"
#include "assimp/postprocess.h"
#include "assimp/scene.h"
#include "glad/glad.h"
#include "Prism/Core/Log.h"
namespace Prism
{
namespace {
const unsigned int ImportFlags =
aiProcess_CalcTangentSpace |
aiProcess_Triangulate |
aiProcess_SortByPType |
aiProcess_PreTransformVertices |
aiProcess_GenNormals |
aiProcess_GenUVCoords |
aiProcess_OptimizeMeshes |
aiProcess_Debone |
aiProcess_ValidateDataStructure;
}
struct LogStream : public Assimp::LogStream
{
static void Initialize()
{
if (Assimp::DefaultLogger::isNullLogger())
{
Assimp::DefaultLogger::create("", Assimp::Logger::VERBOSE);
Assimp::DefaultLogger::get()->attachStream(new LogStream, Assimp::Logger::Err | Assimp::Logger::Warn);
}
}
void write(const char* message) override
{
PM_CORE_ERROR("Assimp error: {0}", message);
}
};
Mesh::Mesh(const std::string& filename)
: m_FilePath(filename)
{
LogStream::Initialize();
PM_CORE_INFO("Loading mesh: {0}", filename.c_str());
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filename, ImportFlags);
if (!scene || !scene->HasMeshes())
PM_CORE_ERROR("Failed to load mesh file: {0}", filename);
aiMesh* mesh = scene->mMeshes[0];
PM_CORE_ASSERT(mesh->HasPositions(), "Meshes require positions.");
PM_CORE_ASSERT(mesh->HasNormals(), "Meshes require normals.");
m_Vertices.reserve(mesh->mNumVertices);
// Extract vertices from model
for (size_t i = 0; i < m_Vertices.capacity(); i++)
{
Vertex vertex;
vertex.Position = { mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z };
vertex.Normal = { mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z };
if (mesh->HasTangentsAndBitangents())
{
vertex.Tangent = { mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z };
vertex.Binormal = { mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z };
}
if (mesh->HasTextureCoords(0))
vertex.Texcoord = { mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y };
m_Vertices.push_back(vertex);
}
m_VertexBuffer.reset(VertexBuffer::Create());
m_VertexBuffer->SetData(m_Vertices.data(), m_Vertices.size() * sizeof(Vertex));
// Extract indices from model
m_Indices.reserve(mesh->mNumFaces);
for (size_t i = 0; i < m_Indices.capacity(); i++)
{
PM_CORE_ASSERT(mesh->mFaces[i].mNumIndices == 3, "Must have 3 indices.");
m_Indices.push_back({ mesh->mFaces[i].mIndices[0], mesh->mFaces[i].mIndices[1], mesh->mFaces[i].mIndices[2] });
}
m_IndexBuffer.reset(IndexBuffer::Create());
m_IndexBuffer->SetData(m_Indices.data(), m_Indices.size() * sizeof(Index));
}
Mesh::~Mesh()
{
}
void Mesh::Render()
{
// TODO: Sort this out
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
PM_RENDER_S({
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Position));
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Normal));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Tangent));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Binormal));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Texcoord));
});
Renderer::DrawIndexed(m_IndexBuffer->GetCount());
}
}

View File

@ -0,0 +1,52 @@
//
// Created by sfd on 25-11-23.
//
#ifndef MESH_H
#define MESH_H
#include <glm/glm.hpp>
#include "Buffer.h"
namespace Prism
{
class Mesh
{
public:
struct Vertex
{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec3 Tangent;
glm::vec3 Binormal;
glm::vec2 Texcoord;
};
static_assert(sizeof(Vertex) == 14 * sizeof(float));
static const int NumAttributes = 5;
struct Index
{
uint32_t V1, V2, V3;
};
static_assert(sizeof(Index) == 3 * sizeof(uint32_t));
Mesh(const std::string& filename);
~Mesh();
void Render();
inline const std::string& GetFilePath() const { return m_FilePath; }
private:
std::vector<Vertex> m_Vertices;
std::vector<Index> m_Indices;
std::unique_ptr<VertexBuffer> m_VertexBuffer;
std::unique_ptr<IndexBuffer> m_IndexBuffer;
std::string m_FilePath;
};
}
#endif //MESH_H

View File

@ -27,10 +27,10 @@ namespace Prism
{
}
void Renderer::DrawIndexed(const int count)
void Renderer::DrawIndexed(unsigned int count, bool depthTest)
{
PM_RENDER_1(count, {
RendererAPI::DrawIndexed(count);
PM_RENDER_2(count, depthTest, {
RendererAPI::DrawIndexed(count, depthTest);
});
}

View File

@ -18,7 +18,7 @@ namespace Prism
static void Clear();
static void Clear(float r, float g, float b, float a = 1.0f);
static void SetClearColor(float r, float g, float b, float a);
static void DrawIndexed(const int count);
static void DrawIndexed(unsigned int count, bool depthTest = true);
// test
static void ClearMagenta();

View File

@ -16,7 +16,17 @@ namespace Prism
OpenGL
};
class PRISM_API RendererAPI
struct RenderAPICapabilities
{
std::string Vendor;
std::string Renderer;
std::string Version;
int MaxSamples;
float MaxAnisotropy;
};
class RendererAPI
{
public:
static void Init();
@ -25,9 +35,15 @@ namespace Prism
static void Clear(float r, float g, float b, float a);
static void SetClearColor(float r, float g, float b, float a);
static void DrawIndexed(int count);
static void DrawIndexed(unsigned int count, bool depthTest = true);
static RendererAPIType Current() { return s_CurrentRendererAPI; }
static RenderAPICapabilities& GetCapabilities()
{
static RenderAPICapabilities capabilities;
return capabilities;
}
private:
static RendererAPIType s_CurrentRendererAPI;
};

View File

@ -9,13 +9,20 @@
namespace Prism
{
std::vector<Shader*> Shader::s_AllShaders;
Shader* Shader::Create(const std::string& filepath)
{
Shader* result = nullptr;
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return new OpenGLShader(filepath);
case RendererAPIType::OpenGL: result = new OpenGLShader(filepath);
}
return nullptr;
s_AllShaders.push_back(result);
return result;
}
}

View File

@ -53,6 +53,7 @@ namespace Prism
byte Buffer[N];
UniformDecl Uniforms[U];
std::ptrdiff_t Cursor = 0;
int Index = 0;
virtual const byte* GetBuffer() const override { return Buffer; }
virtual const UniformDecl* GetUniforms() const override { return Uniforms; }
@ -63,27 +64,48 @@ namespace Prism
void Push(const std::string& name, const float& data)
{
Uniforms[0] = { UniformType::Float, Cursor, name };
Uniforms[Index++] = { UniformType::Float, Cursor, name };
memcpy(Buffer + Cursor, &data, sizeof(float));
Cursor += sizeof(float);
}
void Push(const std::string& name, const glm::vec3& data)
{
Uniforms[Index++] = { UniformType::Float3, Cursor, name };
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::vec3));
Cursor += sizeof(glm::vec3);
}
void Push(const std::string& name, const glm::vec4& data)
{
Uniforms[0] = { UniformType::Float4, Cursor, name };
Uniforms[Index++] = { UniformType::Float4, Cursor, name };
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::vec4));
Cursor += sizeof(glm::vec4);
}
void Push(const std::string& name, const glm::mat4& data)
{
Uniforms[Index++] = { UniformType::Mat4, Cursor, name };
memcpy(Buffer + Cursor, glm::value_ptr(data), sizeof(glm::mat4));
Cursor += sizeof(glm::mat4);
}
};
class PRISM_API Shader
{
public:
virtual void Reload() = 0;
virtual void Bind() = 0;
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
virtual void SetFloat(const std::string& name, float value) = 0;
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
virtual const std::string& GetName() const = 0;
static Shader* Create(const std::string& filepath);
static std::vector<Shader*> s_AllShaders;
};
}

View File

@ -19,4 +19,23 @@ namespace Prism
return nullptr;
}
Texture2D* Texture2D::Create(const std::string& path, bool srgb)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return new OpenGLTexture2D(path, srgb);
}
return nullptr;
}
TextureCube* TextureCube::Create(const std::string& path)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return new OpenGLTextureCube(path);
}
return nullptr;
}
}

View File

@ -4,6 +4,7 @@
#ifndef TEXTURE_H
#define TEXTURE_H
#include "RendererAPI.h"
namespace Prism
@ -20,17 +21,38 @@ namespace Prism
{
public:
virtual ~Texture() {}
virtual RendererID GetRendererID() const = 0;
};
class PRISM_API Texture2D : public Texture
{
public:
static Texture2D* Create(TextureFormat format, unsigned int width, unsigned int height);
static Texture2D* Create(const std::string& path, bool srgb = false);
virtual void Bind(unsigned int slot = 0) const = 0;
virtual TextureFormat GetFormat() const = 0;
virtual unsigned int GetWidth() const = 0;
virtual unsigned int GetHeight() const = 0;
virtual const std::string& GetPath() const = 0;
};
class PRISM_API TextureCube : public Texture
{
public:
static TextureCube* Create(const std::string& path);
virtual void Bind(unsigned int slot = 0) const = 0;
virtual TextureFormat GetFormat() const = 0;
virtual unsigned int GetWidth() const = 0;
virtual unsigned int GetHeight() const = 0;
virtual const std::string& GetPath() const = 0;
};
}

1
Prism/vendor/assimp vendored Submodule

Submodule Prism/vendor/assimp added at ab28db52f0

5
Prism/vendor/stb/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,5 @@
file(GLOB STB_SOURCE src/**.c)
add_library(stb STATIC ${STB_SOURCE})
target_include_directories(stb PUBLIC src)

5
Prism/vendor/stb/src/stb_image.c vendored Normal file
View File

@ -0,0 +1,5 @@
//
// Created by sfd on 25-10-24.
//
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

7988
Prism/vendor/stb/src/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff