add support for skeletal animation
This commit is contained in:
@ -12,10 +12,6 @@
|
|||||||
#include "Prism/Renderer/FrameBuffer.h"
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
#include "Prism/Renderer/RendererAPI.h"
|
#include "Prism/Renderer/RendererAPI.h"
|
||||||
|
|
||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
|
||||||
#include <GLFW/glfw3native.h>
|
|
||||||
#include <Windows.h>
|
|
||||||
|
|
||||||
#include "tinyfiledialogs.h"
|
#include "tinyfiledialogs.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -106,6 +102,7 @@ namespace Prism
|
|||||||
|
|
||||||
std::string Application::OpenFile(const std::string& filter) const
|
std::string Application::OpenFile(const std::string& filter) const
|
||||||
{
|
{
|
||||||
|
// TODO: will move it to other folder
|
||||||
// 处理过滤器
|
// 处理过滤器
|
||||||
std::vector<const char*> filterPatterns;
|
std::vector<const char*> filterPatterns;
|
||||||
std::vector<std::string> patternStorage;
|
std::vector<std::string> patternStorage;
|
||||||
@ -162,29 +159,6 @@ namespace Prism
|
|||||||
|
|
||||||
return result ? std::string(result) : std::string();
|
return result ? std::string(result) : std::string();
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
void Application::PushLayer(Layer* layer)
|
||||||
|
|||||||
@ -42,8 +42,13 @@ namespace Prism
|
|||||||
#define PM_DEBUGBREAK() asm("int3")
|
#define PM_DEBUGBREAK() asm("int3")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define PM_ASSERT(x, ...) { if(!(x)) { PM_ERROR("Assertion Failed: {0}", __VA_ARGS__); PM_DEBUGBREAK(); } }
|
#define PM_ASSERT_NO_MESSAGE(condition) { if(!(condition)) { PM_CORE_ERROR("Assertion Failed!"); PM_DEBUGBREAK(); } }
|
||||||
#define PM_CORE_ASSERT(x, ...) { if(!(x)) { PM_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); PM_DEBUGBREAK(); } }
|
#define PM_ASSERT_MESSAGE(condition, ...) { if(!(condition)) { PM_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); PM_DEBUGBREAK(); } }
|
||||||
|
|
||||||
|
#define PM_ASSERT_RESOLVE(arg1, arg2, macro, ...) macro
|
||||||
|
|
||||||
|
#define PM_ASSERT(...) PM_ASSERT_RESOLVE(__VA_ARGS__, PM_ASSERT_MESSAGE, PM_ASSERT_NO_MESSAGE)(__VA_ARGS__)
|
||||||
|
#define PM_CORE_ASSERT(...) PM_ASSERT_RESOLVE(__VA_ARGS__, PM_ASSERT_MESSAGE, PM_ASSERT_NO_MESSAGE)(__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define PM_ASSERT(x, ...)
|
#define PM_ASSERT(x, ...)
|
||||||
#define PM_CORE_ASSERT(x, ...)
|
#define PM_CORE_ASSERT(x, ...)
|
||||||
|
|||||||
@ -20,12 +20,25 @@ namespace Prism
|
|||||||
|
|
||||||
void OpenGLShader::Reload()
|
void OpenGLShader::Reload()
|
||||||
{
|
{
|
||||||
ReadShaderFromFile(m_AssetPath);
|
const std::string source = ReadShaderFromFile(m_AssetPath);
|
||||||
|
m_ShaderSource = PreProcess(source);
|
||||||
|
Parse();
|
||||||
|
|
||||||
PM_RENDER_S({
|
PM_RENDER_S({
|
||||||
if (self->m_RendererID)
|
if (self->m_RendererID)
|
||||||
glDeleteShader(self->m_RendererID);
|
glDeleteShader(self->m_RendererID);
|
||||||
|
|
||||||
self->CompileAndUploadShader();
|
self->CompileAndUploadShader();
|
||||||
|
self->ResolveUniforms();
|
||||||
|
self->ValidateUniforms();
|
||||||
|
|
||||||
|
if (self->m_Loaded)
|
||||||
|
{
|
||||||
|
for (auto& callback : self->m_ShaderReloadedCallbacks)
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
self->m_Loaded = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,6 +93,11 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::AddShaderReloadedCallback(const ShaderReloadedCallback& callback)
|
||||||
|
{
|
||||||
|
m_ShaderReloadedCallbacks.push_back(callback);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGLShader::SetFloat(const std::string& name, float value)
|
void OpenGLShader::SetFloat(const std::string& name, float value)
|
||||||
{
|
{
|
||||||
PM_RENDER_S2(name, value, {
|
PM_RENDER_S2(name, value, {
|
||||||
@ -94,78 +112,485 @@ namespace Prism
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::SetVSMaterialUniformBuffer(Buffer buffer)
|
||||||
|
{
|
||||||
|
PM_RENDER_S1(buffer, {
|
||||||
|
glUseProgram(self->m_RendererID);
|
||||||
|
self->ResolveAndSetUniforms(self->m_VSMaterialUniformBuffer, buffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::SetPSMaterialUniformBuffer(Buffer buffer)
|
||||||
|
{
|
||||||
|
PM_RENDER_S1(buffer, {
|
||||||
|
glUseProgram(self->m_RendererID);
|
||||||
|
self->ResolveAndSetUniforms(self->m_PSMaterialUniformBuffer, buffer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::SetMat4FromRenderThread(const std::string& name, const glm::mat4& value)
|
||||||
|
{
|
||||||
|
UploadUniformMat4(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& OpenGLShader::GetName() const
|
const std::string& OpenGLShader::GetName() const
|
||||||
{
|
{
|
||||||
return m_Name;
|
return m_Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShader::ReadShaderFromFile(const std::string& filepath)
|
std::string OpenGLShader::ReadShaderFromFile(const std::string& filepath) const
|
||||||
{
|
{
|
||||||
|
std::string result;
|
||||||
std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
std::ifstream file(filepath, std::ios::in | std::ios::binary);
|
||||||
|
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
file.seekg(0, std::ios::end);
|
file.seekg(0, std::ios::end);
|
||||||
m_ShaderSource.resize(file.tellg());
|
result.resize(file.tellg());
|
||||||
file.seekg(0, std::ios::beg);
|
file.seekg(0, std::ios::beg);
|
||||||
file.read(&m_ShaderSource[0], m_ShaderSource.size());
|
file.read(&result[0], result.size());
|
||||||
file.close();
|
file.close();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PM_CORE_WARN("Could not read shader file {0}", filepath);
|
PM_CORE_WARN("Could not read shader file {0}", filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLShader::CompileAndUploadShader()
|
std::unordered_map<GLenum, std::string> OpenGLShader::PreProcess(const std::string& source)
|
||||||
{
|
{
|
||||||
std::istringstream ss(m_ShaderSource);
|
std::unordered_map<GLenum, std::string> shaderSources;
|
||||||
std::string token;
|
|
||||||
/*
|
|
||||||
while (ss >> token)
|
|
||||||
{
|
|
||||||
if (token == "#type")
|
|
||||||
{
|
|
||||||
std::string type;
|
|
||||||
ss >> type;
|
|
||||||
PM_CORE_TRACE("Type={0}", type);
|
|
||||||
}
|
|
||||||
|
|
||||||
PM_CORE_TRACE("{}", token.c_str());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::unordered_map<GLenum, std::string> shaderSources;
|
|
||||||
|
|
||||||
|
|
||||||
const char* typeToken = "#type";
|
const char* typeToken = "#type";
|
||||||
size_t typeTokenLength = strlen(typeToken);
|
size_t typeTokenLength = strlen(typeToken);
|
||||||
size_t pos = m_ShaderSource.find(typeToken, 0);
|
size_t pos = source.find(typeToken, 0);
|
||||||
while (pos != std::string::npos)
|
while (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
size_t eol = source.find("\r\n", pos);
|
||||||
|
if (eol == std::string::npos) {
|
||||||
|
eol = source.find('\n', pos);
|
||||||
|
if (eol == std::string::npos) {
|
||||||
|
eol = source.find('\r', pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(eol != std::string::npos, "Syntax error");
|
||||||
|
size_t begin = pos + typeTokenLength + 1;
|
||||||
|
std::string type = source.substr(begin, eol - begin);
|
||||||
|
PM_CORE_ASSERT(type == "vertex" || type == "fragment" || type == "pixel", "Invalid shader type");
|
||||||
|
|
||||||
|
size_t nextLinePos = source.find_first_not_of("\r\n", eol);
|
||||||
|
pos = source.find(typeToken, nextLinePos);
|
||||||
|
shaderSources[ShaderTypeFromString(type)] = source.substr(nextLinePos, pos - (nextLinePos == std::string::npos ? m_ShaderSource.size() - 1 : nextLinePos));
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaderSources;
|
||||||
|
}
|
||||||
|
const char* FindToken(const char* str, const std::string& token)
|
||||||
|
{
|
||||||
|
const char* t = str;
|
||||||
|
while (t = strstr(t, token.c_str()))
|
||||||
|
{
|
||||||
|
bool left = str == t || isspace(t[-1]);
|
||||||
|
bool right = !t[token.size()] || isspace(t[token.size()]);
|
||||||
|
if (left && right)
|
||||||
|
return t;
|
||||||
|
|
||||||
|
t += token.size();
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* FindToken(const std::string& string, const std::string& token)
|
||||||
|
{
|
||||||
|
return FindToken(string.c_str(), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const std::string& delimiters)
|
||||||
|
{
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = string.find_first_of(delimiters);
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
while (end <= std::string::npos)
|
||||||
|
{
|
||||||
|
std::string token = string.substr(start, end - start);
|
||||||
|
if (!token.empty())
|
||||||
|
result.push_back(token);
|
||||||
|
|
||||||
|
if (end == std::string::npos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
start = end + 1;
|
||||||
|
end = string.find_first_of(delimiters, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const char delimiter)
|
||||||
|
{
|
||||||
|
return SplitString(string, std::string(1, delimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> Tokenize(const std::string& string)
|
||||||
|
{
|
||||||
|
return SplitString(string, " \t\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> GetLines(const std::string& string)
|
||||||
|
{
|
||||||
|
return SplitString(string, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetBlock(const char* str, const char** outPosition)
|
||||||
|
{
|
||||||
|
const char* end = strstr(str, "}");
|
||||||
|
if (!end)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
if (outPosition)
|
||||||
|
*outPosition = end;
|
||||||
|
const uint32_t length = end - str + 1;
|
||||||
|
return std::string(str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetStatement(const char* str, const char** outPosition)
|
||||||
|
{
|
||||||
|
const char* end = strstr(str, ";");
|
||||||
|
if (!end)
|
||||||
|
return str;
|
||||||
|
|
||||||
|
if (outPosition)
|
||||||
|
*outPosition = end;
|
||||||
|
const uint32_t length = end - str + 1;
|
||||||
|
return std::string(str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartsWith(const std::string& string, const std::string& start)
|
||||||
|
{
|
||||||
|
return string.find(start) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::Parse()
|
||||||
|
{
|
||||||
|
const char* token;
|
||||||
|
const char* vstr;
|
||||||
|
const char* fstr;
|
||||||
|
|
||||||
|
m_Resources.clear();
|
||||||
|
m_Structs.clear();
|
||||||
|
m_VSMaterialUniformBuffer.reset();
|
||||||
|
m_PSMaterialUniformBuffer.reset();
|
||||||
|
|
||||||
|
auto& vertexSource = m_ShaderSource[GL_VERTEX_SHADER];
|
||||||
|
auto& fragmentSource = m_ShaderSource[GL_FRAGMENT_SHADER];
|
||||||
|
|
||||||
|
// Vertex Shader
|
||||||
|
vstr = vertexSource.c_str();
|
||||||
|
while ((token = FindToken(vstr, "struct")))
|
||||||
|
ParseUniformStruct(GetBlock(token, &vstr), ShaderDomain::Vertex);
|
||||||
|
|
||||||
|
vstr = vertexSource.c_str();
|
||||||
|
while ((token = FindToken(vstr, "uniform")))
|
||||||
|
ParseUniform(GetStatement(token, &vstr), ShaderDomain::Vertex);
|
||||||
|
|
||||||
|
// Fragment Shader
|
||||||
|
fstr = fragmentSource.c_str();
|
||||||
|
while ((token = FindToken(fstr, "struct")))
|
||||||
|
ParseUniformStruct(GetBlock(token, &fstr), ShaderDomain::Pixel);
|
||||||
|
|
||||||
|
fstr = fragmentSource.c_str();
|
||||||
|
while ((token = FindToken(fstr, "uniform")))
|
||||||
|
ParseUniform(GetStatement(token, &fstr), ShaderDomain::Pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool IsTypeStringResource(const std::string& type)
|
||||||
|
{
|
||||||
|
if (type == "sampler2D") return true;
|
||||||
|
if (type == "samplerCube") return true;
|
||||||
|
if (type == "sampler2DShadow") return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ShaderStruct* OpenGLShader::FindStruct(const std::string& name)
|
||||||
|
{
|
||||||
|
for (ShaderStruct* s : m_Structs)
|
||||||
|
{
|
||||||
|
if (s->GetName() == name)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t OpenGLShader::GetUniformLocation(const std::string& name) const
|
||||||
|
{
|
||||||
|
int32_t result = glGetUniformLocation(m_RendererID, name.c_str());
|
||||||
|
if (result == -1)
|
||||||
|
PM_CORE_WARN("Could not find uniform '{0}' in shader", name);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void OpenGLShader::ParseUniform(const std::string& statement, ShaderDomain domain)
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens = Tokenize(statement);
|
||||||
|
uint32_t index = 0;
|
||||||
|
|
||||||
|
index++; // "uniform"
|
||||||
|
std::string typeString = tokens[index++];
|
||||||
|
std::string name = tokens[index++];
|
||||||
|
// Strip ; from name if present
|
||||||
|
if (const char* s = strstr(name.c_str(), ";"))
|
||||||
|
name = std::string(name.c_str(), s - name.c_str());
|
||||||
|
|
||||||
|
std::string n(name);
|
||||||
|
int32_t count = 1;
|
||||||
|
const char* namestr = n.c_str();
|
||||||
|
if (const char* s = strstr(namestr, "["))
|
||||||
{
|
{
|
||||||
size_t eol = m_ShaderSource.find("\r\n", pos);
|
name = std::string(namestr, s - namestr);
|
||||||
if (eol == std::string::npos) {
|
|
||||||
eol = m_ShaderSource.find('\n', pos);
|
const char* end = strstr(namestr, "]");
|
||||||
if (eol == std::string::npos) {
|
std::string c(s + 1, end - s);
|
||||||
eol = m_ShaderSource.find('\r', pos);
|
count = atoi(c.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsTypeStringResource(typeString))
|
||||||
|
{
|
||||||
|
ShaderResourceDeclaration* declaration = new OpenGLShaderResourceDeclaration(OpenGLShaderResourceDeclaration::StringToType(typeString), name, count);
|
||||||
|
m_Resources.push_back(declaration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration::Type t = OpenGLShaderUniformDeclaration::StringToType(typeString);
|
||||||
|
OpenGLShaderUniformDeclaration* declaration = nullptr;
|
||||||
|
|
||||||
|
if (t == OpenGLShaderUniformDeclaration::Type::NONE)
|
||||||
|
{
|
||||||
|
// Find struct
|
||||||
|
ShaderStruct* s = FindStruct(typeString);
|
||||||
|
PM_CORE_ASSERT(s, "");
|
||||||
|
declaration = new OpenGLShaderUniformDeclaration(domain, s, name, count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
declaration = new OpenGLShaderUniformDeclaration(domain, t, name, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
PM_CORE_ASSERT(eol != std::string::npos, "Syntax error");
|
if (StartsWith(name, "r_"))
|
||||||
size_t begin = pos + typeTokenLength + 1;
|
{
|
||||||
std::string type = m_ShaderSource.substr(begin, eol - begin);
|
if (domain == ShaderDomain::Vertex)
|
||||||
PM_CORE_ASSERT(type == "vertex" || type == "fragment" || type == "pixel", "Invalid shader type");
|
((OpenGLShaderUniformBufferDeclaration*)m_VSRendererUniformBuffers.front())->PushUniform(declaration);
|
||||||
|
else if (domain == ShaderDomain::Pixel)
|
||||||
|
((OpenGLShaderUniformBufferDeclaration*)m_PSRendererUniformBuffers.front())->PushUniform(declaration);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (domain == ShaderDomain::Vertex)
|
||||||
|
{
|
||||||
|
if (!m_VSMaterialUniformBuffer)
|
||||||
|
m_VSMaterialUniformBuffer.reset(new OpenGLShaderUniformBufferDeclaration("", domain));
|
||||||
|
|
||||||
size_t nextLinePos = m_ShaderSource.find_first_not_of("\r\n", eol);
|
m_VSMaterialUniformBuffer->PushUniform(declaration);
|
||||||
pos = m_ShaderSource.find(typeToken, nextLinePos);
|
}
|
||||||
shaderSources[ShaderTypeFromString(type)] = m_ShaderSource.substr(nextLinePos, pos - (nextLinePos == std::string::npos ? m_ShaderSource.size() - 1 : nextLinePos));
|
else if (domain == ShaderDomain::Pixel)
|
||||||
|
{
|
||||||
|
if (!m_PSMaterialUniformBuffer)
|
||||||
|
m_PSMaterialUniformBuffer.reset(new OpenGLShaderUniformBufferDeclaration("", domain));
|
||||||
|
|
||||||
|
m_PSMaterialUniformBuffer->PushUniform(declaration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ParseUniformStruct(const std::string& block, ShaderDomain domain)
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens = Tokenize(block);
|
||||||
|
|
||||||
|
uint32_t index = 0;
|
||||||
|
index++; // struct
|
||||||
|
std::string name = tokens[index++];
|
||||||
|
ShaderStruct* uniformStruct = new ShaderStruct(name);
|
||||||
|
index++; // {
|
||||||
|
while (index < tokens.size())
|
||||||
|
{
|
||||||
|
if (tokens[index] == "}")
|
||||||
|
break;
|
||||||
|
|
||||||
|
std::string type = tokens[index++];
|
||||||
|
std::string name = tokens[index++];
|
||||||
|
|
||||||
|
// Strip ; from name if present
|
||||||
|
if (const char* s = strstr(name.c_str(), ";"))
|
||||||
|
name = std::string(name.c_str(), s - name.c_str());
|
||||||
|
|
||||||
|
uint32_t count = 1;
|
||||||
|
const char* namestr = name.c_str();
|
||||||
|
if (const char* s = strstr(namestr, "["))
|
||||||
|
{
|
||||||
|
name = std::string(namestr, s - namestr);
|
||||||
|
|
||||||
|
const char* end = strstr(namestr, "]");
|
||||||
|
std::string c(s + 1, end - s);
|
||||||
|
count = atoi(c.c_str());
|
||||||
|
}
|
||||||
|
ShaderUniformDeclaration* field = new OpenGLShaderUniformDeclaration(domain, OpenGLShaderUniformDeclaration::StringToType(type), name, count);
|
||||||
|
uniformStruct->AddField(field);
|
||||||
|
}
|
||||||
|
m_Structs.push_back(uniformStruct);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ResolveUniforms()
|
||||||
|
{
|
||||||
|
glUseProgram(m_RendererID);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_VSRendererUniformBuffers.size(); i++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformBufferDeclaration* decl = (OpenGLShaderUniformBufferDeclaration*)m_VSRendererUniformBuffers[i];
|
||||||
|
const ShaderUniformList& uniforms = decl->GetUniformDeclarations();
|
||||||
|
for (size_t j = 0; j < uniforms.size(); j++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* uniform = (OpenGLShaderUniformDeclaration*)uniforms[j];
|
||||||
|
if (uniform->GetType() == OpenGLShaderUniformDeclaration::Type::STRUCT)
|
||||||
|
{
|
||||||
|
const ShaderStruct& s = uniform->GetShaderUniformStruct();
|
||||||
|
const auto& fields = s.GetFields();
|
||||||
|
for (size_t k = 0; k < fields.size(); k++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* field = (OpenGLShaderUniformDeclaration*)fields[k];
|
||||||
|
field->m_Location = GetUniformLocation(uniform->m_Name + "." + field->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uniform->m_Location = GetUniformLocation(uniform->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_PSRendererUniformBuffers.size(); i++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformBufferDeclaration* decl = (OpenGLShaderUniformBufferDeclaration*)m_PSRendererUniformBuffers[i];
|
||||||
|
const ShaderUniformList& uniforms = decl->GetUniformDeclarations();
|
||||||
|
for (size_t j = 0; j < uniforms.size(); j++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* uniform = (OpenGLShaderUniformDeclaration*)uniforms[j];
|
||||||
|
if (uniform->GetType() == OpenGLShaderUniformDeclaration::Type::STRUCT)
|
||||||
|
{
|
||||||
|
const ShaderStruct& s = uniform->GetShaderUniformStruct();
|
||||||
|
const auto& fields = s.GetFields();
|
||||||
|
for (size_t k = 0; k < fields.size(); k++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* field = (OpenGLShaderUniformDeclaration*)fields[k];
|
||||||
|
field->m_Location = GetUniformLocation(uniform->m_Name + "." + field->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uniform->m_Location = GetUniformLocation(uniform->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto& decl = m_VSMaterialUniformBuffer;
|
||||||
|
if (decl)
|
||||||
|
{
|
||||||
|
const ShaderUniformList& uniforms = decl->GetUniformDeclarations();
|
||||||
|
for (size_t j = 0; j < uniforms.size(); j++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* uniform = (OpenGLShaderUniformDeclaration*)uniforms[j];
|
||||||
|
if (uniform->GetType() == OpenGLShaderUniformDeclaration::Type::STRUCT)
|
||||||
|
{
|
||||||
|
const ShaderStruct& s = uniform->GetShaderUniformStruct();
|
||||||
|
const auto& fields = s.GetFields();
|
||||||
|
for (size_t k = 0; k < fields.size(); k++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* field = (OpenGLShaderUniformDeclaration*)fields[k];
|
||||||
|
field->m_Location = GetUniformLocation(uniform->m_Name + "." + field->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uniform->m_Location = GetUniformLocation(uniform->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto& decl = m_PSMaterialUniformBuffer;
|
||||||
|
if (decl)
|
||||||
|
{
|
||||||
|
const ShaderUniformList& uniforms = decl->GetUniformDeclarations();
|
||||||
|
for (size_t j = 0; j < uniforms.size(); j++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* uniform = (OpenGLShaderUniformDeclaration*)uniforms[j];
|
||||||
|
if (uniform->GetType() == OpenGLShaderUniformDeclaration::Type::STRUCT)
|
||||||
|
{
|
||||||
|
const ShaderStruct& s = uniform->GetShaderUniformStruct();
|
||||||
|
const auto& fields = s.GetFields();
|
||||||
|
for (size_t k = 0; k < fields.size(); k++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* field = (OpenGLShaderUniformDeclaration*)fields[k];
|
||||||
|
field->m_Location = GetUniformLocation(uniform->m_Name + "." + field->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uniform->m_Location = GetUniformLocation(uniform->m_Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t sampler = 0;
|
||||||
|
for (size_t i = 0; i < m_Resources.size(); i++)
|
||||||
|
{
|
||||||
|
OpenGLShaderResourceDeclaration* resource = (OpenGLShaderResourceDeclaration*)m_Resources[i];
|
||||||
|
int32_t location = GetUniformLocation(resource->m_Name);
|
||||||
|
|
||||||
|
if (resource->GetCount() == 1)
|
||||||
|
{
|
||||||
|
resource->m_Register = sampler;
|
||||||
|
if (location != -1)
|
||||||
|
UploadUniformInt(location, sampler);
|
||||||
|
|
||||||
|
sampler++;
|
||||||
|
}
|
||||||
|
else if (resource->GetCount() > 1)
|
||||||
|
{
|
||||||
|
resource->m_Register = 0;
|
||||||
|
uint32_t count = resource->GetCount();
|
||||||
|
int* samplers = new int[count];
|
||||||
|
for (uint32_t s = 0; s < count; s++)
|
||||||
|
samplers[s] = s;
|
||||||
|
UploadUniformIntArray(resource->GetName(), samplers, count);
|
||||||
|
delete[] samplers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ValidateUniforms()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::CompileAndUploadShader()
|
||||||
|
{
|
||||||
|
|
||||||
std::vector<GLuint> shaderRendererIDs;
|
std::vector<GLuint> shaderRendererIDs;
|
||||||
|
|
||||||
GLuint program = glCreateProgram();
|
GLuint program = glCreateProgram();
|
||||||
|
|
||||||
for (const auto& kv : shaderSources)
|
for (const auto& kv : m_ShaderSource)
|
||||||
{
|
{
|
||||||
GLenum type = kv.first;
|
GLenum type = kv.first;
|
||||||
const std::string& source = kv.second;
|
const std::string& source = kv.second;
|
||||||
@ -219,20 +644,6 @@ namespace Prism
|
|||||||
glDetachShader(program, id);
|
glDetachShader(program, id);
|
||||||
|
|
||||||
m_RendererID = program;
|
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)
|
GLenum OpenGLShader::ShaderTypeFromString(const std::string& type)
|
||||||
@ -304,4 +715,185 @@ namespace Prism
|
|||||||
else
|
else
|
||||||
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
PM_CORE_WARN("Uniform '{0}' not found!", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ResolveAndSetUniforms(const Scope<OpenGLShaderUniformBufferDeclaration>& decl, Buffer buffer)
|
||||||
|
{
|
||||||
|
const ShaderUniformList& uniforms = decl->GetUniformDeclarations();
|
||||||
|
for (size_t i = 0; i < uniforms.size(); i++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* uniform = (OpenGLShaderUniformDeclaration*)uniforms[i];
|
||||||
|
if (uniform->IsArray())
|
||||||
|
ResolveAndSetUniformArray(uniform, buffer);
|
||||||
|
else
|
||||||
|
ResolveAndSetUniform(uniform, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ResolveAndSetUniform(OpenGLShaderUniformDeclaration* uniform, Buffer buffer)
|
||||||
|
{
|
||||||
|
if (uniform->GetLocation() == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(uniform->GetLocation() != -1, "Uniform has invalid location!");
|
||||||
|
|
||||||
|
uint32_t offset = uniform->GetOffset();
|
||||||
|
switch (uniform->GetType())
|
||||||
|
{
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::FLOAT32:
|
||||||
|
UploadUniformFloat(uniform->GetLocation(), *(float*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::INT32:
|
||||||
|
UploadUniformInt(uniform->GetLocation(), *(int32_t*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC2:
|
||||||
|
UploadUniformFloat2(uniform->GetLocation(), *(glm::vec2*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC3:
|
||||||
|
UploadUniformFloat3(uniform->GetLocation(), *(glm::vec3*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC4:
|
||||||
|
UploadUniformFloat4(uniform->GetLocation(), *(glm::vec4*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT3:
|
||||||
|
UploadUniformMat3(uniform->GetLocation(), *(glm::mat3*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT4:
|
||||||
|
UploadUniformMat4(uniform->GetLocation(), *(glm::mat4*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::STRUCT:
|
||||||
|
UploadUniformStruct(uniform, buffer.Data, offset);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PM_CORE_ASSERT(false, "Unknown uniform type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ResolveAndSetUniformArray(OpenGLShaderUniformDeclaration* uniform, Buffer buffer)
|
||||||
|
{
|
||||||
|
//HZ_CORE_ASSERT(uniform->GetLocation() != -1, "Uniform has invalid location!");
|
||||||
|
|
||||||
|
uint32_t offset = uniform->GetOffset();
|
||||||
|
switch (uniform->GetType())
|
||||||
|
{
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::FLOAT32:
|
||||||
|
UploadUniformFloat(uniform->GetLocation(), *(float*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::INT32:
|
||||||
|
UploadUniformInt(uniform->GetLocation(), *(int32_t*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC2:
|
||||||
|
UploadUniformFloat2(uniform->GetLocation(), *(glm::vec2*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC3:
|
||||||
|
UploadUniformFloat3(uniform->GetLocation(), *(glm::vec3*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC4:
|
||||||
|
UploadUniformFloat4(uniform->GetLocation(), *(glm::vec4*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT3:
|
||||||
|
UploadUniformMat3(uniform->GetLocation(), *(glm::mat3*)&buffer.Data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT4:
|
||||||
|
UploadUniformMat4Array(uniform->GetLocation(), *(glm::mat4*)&buffer.Data[offset], uniform->GetCount());
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::STRUCT:
|
||||||
|
UploadUniformStruct(uniform, buffer.Data, offset);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PM_CORE_ASSERT(false, "Unknown uniform type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::ResolveAndSetUniformField(const OpenGLShaderUniformDeclaration& field, byte* data, int32_t offset)
|
||||||
|
{
|
||||||
|
switch (field.GetType())
|
||||||
|
{
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::FLOAT32:
|
||||||
|
UploadUniformFloat(field.GetLocation(), *(float*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::INT32:
|
||||||
|
UploadUniformInt(field.GetLocation(), *(int32_t*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC2:
|
||||||
|
UploadUniformFloat2(field.GetLocation(), *(glm::vec2*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC3:
|
||||||
|
UploadUniformFloat3(field.GetLocation(), *(glm::vec3*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC4:
|
||||||
|
UploadUniformFloat4(field.GetLocation(), *(glm::vec4*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT3:
|
||||||
|
UploadUniformMat3(field.GetLocation(), *(glm::mat3*)&data[offset]);
|
||||||
|
break;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT4:
|
||||||
|
UploadUniformMat4(field.GetLocation(), *(glm::mat4*)&data[offset]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PM_CORE_ASSERT(false, "Unknown uniform type!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformInt(uint32_t location, int32_t value)
|
||||||
|
{
|
||||||
|
glUniform1i(location, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformIntArray(uint32_t location, int32_t* values, int32_t count)
|
||||||
|
{
|
||||||
|
glUniform1iv(location, count, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat(uint32_t location, float value)
|
||||||
|
{
|
||||||
|
glUniform1f(location, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat2(uint32_t location, const glm::vec2& value)
|
||||||
|
{
|
||||||
|
glUniform2f(location, value.x, value.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat3(uint32_t location, const glm::vec3& value)
|
||||||
|
{
|
||||||
|
glUniform3f(location, value.x, value.y, value.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformFloat4(uint32_t location, const glm::vec4& value)
|
||||||
|
{
|
||||||
|
glUniform4f(location, value.x, value.y, value.z, value.w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformMat3(uint32_t location, const glm::mat3& values)
|
||||||
|
{
|
||||||
|
glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformMat4(uint32_t location, const glm::mat4& values)
|
||||||
|
{
|
||||||
|
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformMat4Array(uint32_t location, const glm::mat4& values, uint32_t count)
|
||||||
|
{
|
||||||
|
glUniformMatrix4fv(location, count, GL_FALSE, glm::value_ptr(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformStruct(OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset)
|
||||||
|
{
|
||||||
|
const ShaderStruct& s = uniform->GetShaderUniformStruct();
|
||||||
|
const auto& fields = s.GetFields();
|
||||||
|
for (size_t k = 0; k < fields.size(); k++)
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* field = (OpenGLShaderUniformDeclaration*)fields[k];
|
||||||
|
ResolveAndSetUniformField(*field, buffer, offset);
|
||||||
|
offset += field->m_Size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShader::UploadUniformIntArray(const std::string& name, int32_t* values, int32_t count)
|
||||||
|
{
|
||||||
|
int32_t location = GetUniformLocation(name);
|
||||||
|
glUniform1iv(location, count, values);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#ifndef OPENGLSHADER_H
|
#ifndef OPENGLSHADER_H
|
||||||
#define OPENGLSHADER_H
|
#define OPENGLSHADER_H
|
||||||
|
#include "OpenGLShaderUniform.h"
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "Prism/Renderer/RendererAPI.h"
|
#include "Prism/Renderer/RendererAPI.h"
|
||||||
#include "Prism/Renderer/Shader.h"
|
#include "Prism/Renderer/Shader.h"
|
||||||
@ -20,14 +21,33 @@ namespace Prism
|
|||||||
virtual void Bind() override;
|
virtual void Bind() override;
|
||||||
|
|
||||||
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) override;
|
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) override;
|
||||||
|
virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) override;
|
||||||
|
|
||||||
virtual void SetFloat(const std::string& name, float value) override;
|
virtual void SetFloat(const std::string& name, float value) override;
|
||||||
virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
|
virtual void SetMat4(const std::string& name, const glm::mat4& value) override;
|
||||||
|
|
||||||
|
virtual void SetVSMaterialUniformBuffer(Buffer buffer) override;
|
||||||
|
virtual void SetPSMaterialUniformBuffer(Buffer buffer) override;
|
||||||
|
|
||||||
|
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value) override;
|
||||||
|
|
||||||
const std::string& GetName() const override;
|
const std::string& GetName() const override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReadShaderFromFile(const std::string& filepath);
|
std::string ReadShaderFromFile(const std::string& filepath) const;
|
||||||
|
std::unordered_map<GLenum, std::string> PreProcess(const std::string& source);
|
||||||
|
void Parse();
|
||||||
|
void ParseUniform(const std::string& statement, ShaderDomain domain);
|
||||||
|
void ParseUniformStruct(const std::string& block, ShaderDomain domain);
|
||||||
|
ShaderStruct* FindStruct(const std::string& name);
|
||||||
|
|
||||||
|
int32_t GetUniformLocation(const std::string& name) const;
|
||||||
|
|
||||||
|
void ResolveUniforms();
|
||||||
|
void ValidateUniforms();
|
||||||
|
|
||||||
|
|
||||||
void CompileAndUploadShader();
|
void CompileAndUploadShader();
|
||||||
|
|
||||||
static GLenum ShaderTypeFromString(const std::string& type);
|
static GLenum ShaderTypeFromString(const std::string& type);
|
||||||
@ -38,11 +58,47 @@ namespace Prism
|
|||||||
void UploadUniformFloat3(const std::string& name, const glm::vec3& 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 UploadUniformFloat4(const std::string& name, const glm::vec4& values) const;
|
||||||
void UploadUniformMat4(const std::string& name, const glm::mat4& values) const;
|
void UploadUniformMat4(const std::string& name, const glm::mat4& values) const;
|
||||||
|
|
||||||
|
void ResolveAndSetUniforms(const Scope<OpenGLShaderUniformBufferDeclaration>& decl, Buffer buffer);
|
||||||
|
void ResolveAndSetUniform(OpenGLShaderUniformDeclaration* uniform, Buffer buffer);
|
||||||
|
void ResolveAndSetUniformArray(OpenGLShaderUniformDeclaration* uniform, Buffer buffer);
|
||||||
|
void ResolveAndSetUniformField(const OpenGLShaderUniformDeclaration& field, byte* data, int32_t offset);
|
||||||
|
|
||||||
|
void UploadUniformInt(uint32_t location, int32_t value);
|
||||||
|
void UploadUniformIntArray(uint32_t location, int32_t* values, int32_t count);
|
||||||
|
void UploadUniformFloat(uint32_t location, float value);
|
||||||
|
void UploadUniformFloat2(uint32_t location, const glm::vec2& value);
|
||||||
|
void UploadUniformFloat3(uint32_t location, const glm::vec3& value);
|
||||||
|
void UploadUniformFloat4(uint32_t location, const glm::vec4& value);
|
||||||
|
void UploadUniformMat3(uint32_t location, const glm::mat3& values);
|
||||||
|
void UploadUniformMat4(uint32_t location, const glm::mat4& values);
|
||||||
|
void UploadUniformMat4Array(uint32_t location, const glm::mat4& values, uint32_t count);
|
||||||
|
|
||||||
|
void UploadUniformStruct(OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset);
|
||||||
|
void UploadUniformIntArray(const std::string& name, int32_t* values, int32_t count);
|
||||||
|
|
||||||
|
inline const ShaderUniformBufferList& GetVSRendererUniforms() const override { return m_VSRendererUniformBuffers; }
|
||||||
|
inline const ShaderUniformBufferList& GetPSRendererUniforms() const override { return m_PSRendererUniformBuffers; }
|
||||||
|
inline const ShaderUniformBufferDeclaration& GetVSMaterialUniformBuffer() const override { return *m_VSMaterialUniformBuffer; }
|
||||||
|
inline const ShaderUniformBufferDeclaration& GetPSMaterialUniformBuffer() const override { return *m_PSMaterialUniformBuffer; }
|
||||||
|
inline const ShaderResourceList& GetResources() const override { return m_Resources; }
|
||||||
private:
|
private:
|
||||||
RendererID m_RendererID;
|
RendererID m_RendererID;
|
||||||
|
|
||||||
|
bool m_Loaded = false;
|
||||||
|
|
||||||
std::string m_Name, m_AssetPath;
|
std::string m_Name, m_AssetPath;
|
||||||
std::string m_ShaderSource;
|
std::unordered_map<GLenum, std::string> m_ShaderSource;
|
||||||
|
|
||||||
|
std::vector<ShaderReloadedCallback> m_ShaderReloadedCallbacks;
|
||||||
|
|
||||||
|
ShaderUniformBufferList m_VSRendererUniformBuffers;
|
||||||
|
ShaderUniformBufferList m_PSRendererUniformBuffers;
|
||||||
|
Scope<OpenGLShaderUniformBufferDeclaration> m_VSMaterialUniformBuffer;
|
||||||
|
Scope<OpenGLShaderUniformBufferDeclaration> m_PSMaterialUniformBuffer;
|
||||||
|
ShaderResourceList m_Resources;
|
||||||
|
ShaderStructList m_Structs;
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
130
Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp
Normal file
130
Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "OpenGLShaderUniform.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration::OpenGLShaderUniformDeclaration(ShaderDomain domain, Type type, const std::string& name, uint32_t count)
|
||||||
|
: m_Type(type), m_Struct(nullptr), m_Domain(domain)
|
||||||
|
{
|
||||||
|
m_Name = name;
|
||||||
|
m_Count = count;
|
||||||
|
m_Size = SizeOfUniformType(type) * count;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderUniformDeclaration::OpenGLShaderUniformDeclaration(ShaderDomain domain, ShaderStruct* uniformStruct, const std::string& name, uint32_t count)
|
||||||
|
: m_Struct(uniformStruct), m_Type(OpenGLShaderUniformDeclaration::Type::STRUCT), m_Domain(domain)
|
||||||
|
{
|
||||||
|
m_Name = name;
|
||||||
|
m_Count = count;
|
||||||
|
m_Size = m_Struct->GetSize() * count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderUniformDeclaration::SetOffset(uint32_t offset)
|
||||||
|
{
|
||||||
|
if (m_Type == OpenGLShaderUniformDeclaration::Type::STRUCT)
|
||||||
|
m_Struct->SetOffset(offset);
|
||||||
|
|
||||||
|
m_Offset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t OpenGLShaderUniformDeclaration::SizeOfUniformType(Type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::INT32: return 4;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::FLOAT32: return 4;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC2: return 4 * 2;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC3: return 4 * 3;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC4: return 4 * 4;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT3: return 4 * 3 * 3;
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT4: return 4 * 4 * 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderUniformDeclaration::Type OpenGLShaderUniformDeclaration::StringToType(const std::string& type)
|
||||||
|
{
|
||||||
|
if (type == "int32") return Type::INT32;
|
||||||
|
if (type == "float") return Type::FLOAT32;
|
||||||
|
if (type == "vec2") return Type::VEC2;
|
||||||
|
if (type == "vec3") return Type::VEC3;
|
||||||
|
if (type == "vec4") return Type::VEC4;
|
||||||
|
if (type == "mat3") return Type::MAT3;
|
||||||
|
if (type == "mat4") return Type::MAT4;
|
||||||
|
|
||||||
|
return Type::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OpenGLShaderUniformDeclaration::TypeToString(Type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::INT32: return "int32";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::FLOAT32: return "float";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC2: return "vec2";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC3: return "vec3";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::VEC4: return "vec4";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT3: return "mat3";
|
||||||
|
case OpenGLShaderUniformDeclaration::Type::MAT4: return "mat4";
|
||||||
|
}
|
||||||
|
return "Invalid Type";
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderUniformBufferDeclaration::OpenGLShaderUniformBufferDeclaration(const std::string& name, ShaderDomain domain)
|
||||||
|
: m_Name(name), m_Domain(domain), m_Size(0), m_Register(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLShaderUniformBufferDeclaration::PushUniform(OpenGLShaderUniformDeclaration* uniform)
|
||||||
|
{
|
||||||
|
uint32_t offset = 0;
|
||||||
|
if (m_Uniforms.size())
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration* previous = (OpenGLShaderUniformDeclaration*)m_Uniforms.back();
|
||||||
|
offset = previous->m_Offset + previous->m_Size;
|
||||||
|
}
|
||||||
|
uniform->SetOffset(offset);
|
||||||
|
m_Size += uniform->GetSize();
|
||||||
|
m_Uniforms.push_back(uniform);
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderUniformDeclaration* OpenGLShaderUniformBufferDeclaration::FindUniform(const std::string& name)
|
||||||
|
{
|
||||||
|
for (ShaderUniformDeclaration* uniform : m_Uniforms)
|
||||||
|
{
|
||||||
|
if (uniform->GetName() == name)
|
||||||
|
return uniform;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderResourceDeclaration::OpenGLShaderResourceDeclaration(Type type, const std::string& name, uint32_t count)
|
||||||
|
: m_Type(type), m_Name(name), m_Count(count)
|
||||||
|
{
|
||||||
|
m_Name = name;
|
||||||
|
m_Count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
OpenGLShaderResourceDeclaration::Type OpenGLShaderResourceDeclaration::StringToType(const std::string& type)
|
||||||
|
{
|
||||||
|
if (type == "sampler2D") return Type::TEXTURE2D;
|
||||||
|
if (type == "samplerCube") return Type::TEXTURECUBE;
|
||||||
|
|
||||||
|
return Type::NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string OpenGLShaderResourceDeclaration::TypeToString(Type type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Type::TEXTURE2D: return "sampler2D";
|
||||||
|
case Type::TEXTURECUBE: return "samplerCube";
|
||||||
|
}
|
||||||
|
return "Invalid Type";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
118
Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h
Normal file
118
Prism/src/Prism/Platform/OpenGL/OpenGLShaderUniform.h
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef OPENGLSHADERUNIFORM_H
|
||||||
|
#define OPENGLSHADERUNIFORM_H
|
||||||
|
#include "Prism/Renderer/ShaderUniform.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class OpenGLShaderResourceDeclaration : public ShaderResourceDeclaration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
NONE, TEXTURE2D, TEXTURECUBE
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
friend class OpenGLShader;
|
||||||
|
private:
|
||||||
|
std::string m_Name;
|
||||||
|
uint32_t m_Register = 0;
|
||||||
|
uint32_t m_Count;
|
||||||
|
Type m_Type;
|
||||||
|
public:
|
||||||
|
OpenGLShaderResourceDeclaration(Type type, const std::string& name, uint32_t count);
|
||||||
|
|
||||||
|
inline const std::string& GetName() const override { return m_Name; }
|
||||||
|
inline uint32_t GetRegister() const override { return m_Register; }
|
||||||
|
inline uint32_t GetCount() const override { return m_Count; }
|
||||||
|
|
||||||
|
inline Type GetType() const { return m_Type; }
|
||||||
|
public:
|
||||||
|
static Type StringToType(const std::string& type);
|
||||||
|
static std::string TypeToString(Type type);
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenGLShaderUniformDeclaration : public ShaderUniformDeclaration
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class OpenGLShader;
|
||||||
|
friend class OpenGLShaderUniformBufferDeclaration;
|
||||||
|
public:
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
NONE, FLOAT32, VEC2, VEC3, VEC4, MAT3, MAT4, INT32, STRUCT
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
std::string m_Name;
|
||||||
|
uint32_t m_Size;
|
||||||
|
uint32_t m_Count;
|
||||||
|
uint32_t m_Offset;
|
||||||
|
ShaderDomain m_Domain;
|
||||||
|
|
||||||
|
Type m_Type;
|
||||||
|
ShaderStruct* m_Struct;
|
||||||
|
mutable int32_t m_Location;
|
||||||
|
public:
|
||||||
|
OpenGLShaderUniformDeclaration(ShaderDomain domain, Type type, const std::string& name, uint32_t count = 1);
|
||||||
|
OpenGLShaderUniformDeclaration(ShaderDomain domain, ShaderStruct* uniformStruct, const std::string& name, uint32_t count = 1);
|
||||||
|
|
||||||
|
inline const std::string& GetName() const override { return m_Name; }
|
||||||
|
inline uint32_t GetSize() const override { return m_Size; }
|
||||||
|
inline uint32_t GetCount() const override { return m_Count; }
|
||||||
|
inline uint32_t GetOffset() const override { return m_Offset; }
|
||||||
|
inline uint32_t GetAbsoluteOffset() const { return m_Struct ? m_Struct->GetOffset() + m_Offset : m_Offset; }
|
||||||
|
inline ShaderDomain GetDomain() const { return m_Domain; }
|
||||||
|
|
||||||
|
int32_t GetLocation() const { return m_Location; }
|
||||||
|
inline Type GetType() const { return m_Type; }
|
||||||
|
inline bool IsArray() const { return m_Count > 1; }
|
||||||
|
inline const ShaderStruct& GetShaderUniformStruct() const { PM_CORE_ASSERT(m_Struct, ""); return *m_Struct; }
|
||||||
|
protected:
|
||||||
|
void SetOffset(uint32_t offset) override;
|
||||||
|
public:
|
||||||
|
static uint32_t SizeOfUniformType(Type type);
|
||||||
|
static Type StringToType(const std::string& type);
|
||||||
|
static std::string TypeToString(Type type);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GLShaderUniformField
|
||||||
|
{
|
||||||
|
OpenGLShaderUniformDeclaration::Type type;
|
||||||
|
std::string name;
|
||||||
|
uint32_t count;
|
||||||
|
mutable uint32_t size;
|
||||||
|
mutable int32_t location;
|
||||||
|
};
|
||||||
|
|
||||||
|
class OpenGLShaderUniformBufferDeclaration : public ShaderUniformBufferDeclaration
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class Shader;
|
||||||
|
private:
|
||||||
|
std::string m_Name;
|
||||||
|
ShaderUniformList m_Uniforms;
|
||||||
|
uint32_t m_Register;
|
||||||
|
uint32_t m_Size;
|
||||||
|
ShaderDomain m_Domain;
|
||||||
|
public:
|
||||||
|
OpenGLShaderUniformBufferDeclaration(const std::string& name, ShaderDomain domain);
|
||||||
|
|
||||||
|
void PushUniform(OpenGLShaderUniformDeclaration* uniform);
|
||||||
|
|
||||||
|
inline const std::string& GetName() const override { return m_Name; }
|
||||||
|
inline uint32_t GetRegister() const override { return m_Register; }
|
||||||
|
inline uint32_t GetSize() const override { return m_Size; }
|
||||||
|
virtual ShaderDomain GetDomain() const { return m_Domain; }
|
||||||
|
inline const ShaderUniformList& GetUniformDeclarations() const override { return m_Uniforms; }
|
||||||
|
|
||||||
|
ShaderUniformDeclaration* FindUniform(const std::string& name);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //OPENGLSHADERUNIFORM_H
|
||||||
@ -33,18 +33,19 @@ namespace Prism
|
|||||||
// Texture2D
|
// Texture2D
|
||||||
// ******************************************
|
// ******************************************
|
||||||
|
|
||||||
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height)
|
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap)
|
||||||
: m_Format(format), m_Width(width), m_Height(height)
|
: m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap)
|
||||||
{
|
{
|
||||||
auto self = this;
|
auto self = this;
|
||||||
PM_RENDER_1(self, {
|
PM_RENDER_1(self, {
|
||||||
glGenTextures(1, &self->m_RendererID);
|
glGenTextures(1, &self->m_RendererID);
|
||||||
glBindTexture(GL_TEXTURE_2D, 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_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
GLenum wrap = self->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap);
|
||||||
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
|
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);
|
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, nullptr);
|
||||||
@ -55,12 +56,13 @@ namespace Prism
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb)
|
OpenGLTexture2D::OpenGLTexture2D(const std::string& path, bool srgb)
|
||||||
: m_FilePath(path)
|
: m_FilePath(path)
|
||||||
{
|
{
|
||||||
int width, height, channels;
|
int width, height, channels;
|
||||||
PM_CORE_INFO("Loading texture {0}, srgb={1}", path, srgb);
|
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_ImageData.Data = stbi_load(path.c_str(), &width, &height, &channels, srgb ? STBI_rgb : STBI_rgb_alpha);
|
||||||
|
|
||||||
m_Width = width;
|
m_Width = width;
|
||||||
m_Height = height;
|
m_Height = height;
|
||||||
@ -77,7 +79,7 @@ namespace Prism
|
|||||||
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
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);
|
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);
|
glTextureSubImage2D(self->m_RendererID, 0, 0, 0, self->m_Width, self->m_Height, GL_RGB, GL_UNSIGNED_BYTE, self->m_ImageData.Data);
|
||||||
glGenerateTextureMipmap(self->m_RendererID);
|
glGenerateTextureMipmap(self->m_RendererID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -90,30 +92,58 @@ namespace Prism
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
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_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);
|
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.Data);
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
stbi_image_free(self->m_ImageData);
|
stbi_image_free(self->m_ImageData.Data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGLTexture2D::~OpenGLTexture2D()
|
OpenGLTexture2D::~OpenGLTexture2D()
|
||||||
{
|
{
|
||||||
auto self = this;
|
PM_RENDER_S({
|
||||||
PM_RENDER_1(self, {
|
|
||||||
glDeleteTextures(1, &self->m_RendererID);
|
glDeleteTextures(1, &self->m_RendererID);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTexture2D::Bind(unsigned int slot) const
|
void OpenGLTexture2D::Bind(uint32_t slot) const
|
||||||
{
|
{
|
||||||
PM_RENDER_S1(slot, {
|
PM_RENDER_S1(slot, {
|
||||||
glBindTextureUnit(slot, self->m_RendererID);
|
glBindTextureUnit(slot, self->m_RendererID);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGLTexture2D::Lock()
|
||||||
|
{
|
||||||
|
m_Locked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTexture2D::Unlock()
|
||||||
|
{
|
||||||
|
m_Locked = false;
|
||||||
|
PM_RENDER_S({
|
||||||
|
glTextureSubImage2D(self->m_RendererID, 0, 0, 0, self->m_Width, self->m_Height, PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, self->m_ImageData.Data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGLTexture2D::Resize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(m_Locked, "Texture must be locked!");
|
||||||
|
|
||||||
|
m_ImageData.Allocate(width * height * Texture::GetBPP(m_Format));
|
||||||
|
#if PM_DEBUG
|
||||||
|
m_ImageData.ZeroInitialize();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer OpenGLTexture2D::GetWriteableBuffer()
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(m_Locked, "Texture must be locked!");
|
||||||
|
return m_ImageData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ******************************************
|
// ******************************************
|
||||||
// TextureCube
|
// TextureCube
|
||||||
@ -214,11 +244,10 @@ namespace Prism
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGLTextureCube::Bind(unsigned int slot) const
|
void OpenGLTextureCube::Bind(uint32_t slot) const
|
||||||
{
|
{
|
||||||
PM_RENDER_S1(slot, {
|
PM_RENDER_S1(slot, {
|
||||||
glActiveTexture(GL_TEXTURE0 + slot);
|
glBindTextureUnit(slot, self->m_RendererID);
|
||||||
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,15 +13,22 @@ namespace Prism
|
|||||||
class OpenGLTexture2D : public Texture2D
|
class OpenGLTexture2D : public Texture2D
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height);
|
OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap);
|
||||||
OpenGLTexture2D(const std::string& path, bool srgb);
|
OpenGLTexture2D(const std::string& path, bool srgb);
|
||||||
virtual ~OpenGLTexture2D();
|
virtual ~OpenGLTexture2D();
|
||||||
|
|
||||||
virtual void Bind(unsigned int slot = 0) const override;
|
virtual void Bind(uint32_t slot = 0) const override;
|
||||||
|
|
||||||
|
virtual TextureFormat GetFormat() const override { return m_Format; }
|
||||||
|
virtual uint32_t GetWidth() const override { return m_Width; }
|
||||||
|
virtual uint32_t GetHeight() const override { return m_Height; }
|
||||||
|
|
||||||
|
virtual void Lock() override;
|
||||||
|
virtual void Unlock() override;
|
||||||
|
|
||||||
|
virtual void Resize(uint32_t width, uint32_t height) override;
|
||||||
|
virtual Buffer GetWriteableBuffer() 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 const std::string& GetPath() const override { return m_FilePath; }
|
||||||
|
|
||||||
@ -30,8 +37,11 @@ namespace Prism
|
|||||||
RendererID m_RendererID;
|
RendererID m_RendererID;
|
||||||
TextureFormat m_Format;
|
TextureFormat m_Format;
|
||||||
unsigned int m_Width, m_Height;
|
unsigned int m_Width, m_Height;
|
||||||
|
TextureWrap m_Wrap = TextureWrap::Clamp;
|
||||||
|
|
||||||
unsigned char* m_ImageData;
|
bool m_Locked = false;
|
||||||
|
|
||||||
|
Buffer m_ImageData;
|
||||||
|
|
||||||
std::string m_FilePath;
|
std::string m_FilePath;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
#include "glm/gtx/quaternion.hpp"
|
#include "glm/gtx/quaternion.hpp"
|
||||||
#include "Prism/Core/Input.h"
|
#include "Prism/Core/Input.h"
|
||||||
|
|
||||||
#define M_PI 3.14159f
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
|||||||
178
Prism/src/Prism/Renderer/Material.cpp
Normal file
178
Prism/src/Prism/Renderer/Material.cpp
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "Material.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
Material::Material(const Ref<Shader>& shader)
|
||||||
|
: m_Shader(shader)
|
||||||
|
{
|
||||||
|
m_Shader->AddShaderReloadedCallback(std::bind(&Material::OnShaderReloaded, this));
|
||||||
|
AllocateStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
Material::~Material()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Material::AllocateStorage()
|
||||||
|
{
|
||||||
|
const auto& vsBuffer = m_Shader->GetVSMaterialUniformBuffer();
|
||||||
|
m_VSUniformStorageBuffer.Allocate(vsBuffer.GetSize());
|
||||||
|
m_VSUniformStorageBuffer.ZeroInitialize();
|
||||||
|
|
||||||
|
const auto& psBuffer = m_Shader->GetPSMaterialUniformBuffer();
|
||||||
|
m_PSUniformStorageBuffer.Allocate(psBuffer.GetSize());
|
||||||
|
m_PSUniformStorageBuffer.ZeroInitialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::OnShaderReloaded()
|
||||||
|
{
|
||||||
|
AllocateStorage();
|
||||||
|
|
||||||
|
for (auto mi : m_MaterialInstances)
|
||||||
|
mi->OnShaderReloaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderUniformDeclaration* Material::FindUniformDeclaration(const std::string& name)
|
||||||
|
{
|
||||||
|
if (m_VSUniformStorageBuffer)
|
||||||
|
{
|
||||||
|
auto& declarations = m_Shader->GetVSMaterialUniformBuffer().GetUniformDeclarations();
|
||||||
|
for (ShaderUniformDeclaration* uniform : declarations)
|
||||||
|
{
|
||||||
|
if (uniform->GetName() == name)
|
||||||
|
return uniform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_PSUniformStorageBuffer)
|
||||||
|
{
|
||||||
|
auto& declarations = m_Shader->GetPSMaterialUniformBuffer().GetUniformDeclarations();
|
||||||
|
for (ShaderUniformDeclaration* uniform : declarations)
|
||||||
|
{
|
||||||
|
if (uniform->GetName() == name)
|
||||||
|
return uniform;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShaderResourceDeclaration* Material::FindResourceDeclaration(const std::string& name)
|
||||||
|
{
|
||||||
|
auto& resources = m_Shader->GetResources();
|
||||||
|
for (ShaderResourceDeclaration* resource : resources)
|
||||||
|
{
|
||||||
|
if (resource->GetName() == name)
|
||||||
|
return resource;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer& Material::GetUniformBufferTarget(ShaderUniformDeclaration* uniformDeclaration)
|
||||||
|
{
|
||||||
|
switch (uniformDeclaration->GetDomain())
|
||||||
|
{
|
||||||
|
case ShaderDomain::Vertex: return m_VSUniformStorageBuffer;
|
||||||
|
case ShaderDomain::Pixel: return m_PSUniformStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(false, "Invalid uniform declaration domain! Material does not support this shader type.");
|
||||||
|
return m_VSUniformStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::Bind() const
|
||||||
|
{
|
||||||
|
m_Shader->Bind();
|
||||||
|
|
||||||
|
if (m_VSUniformStorageBuffer)
|
||||||
|
m_Shader->SetVSMaterialUniformBuffer(m_VSUniformStorageBuffer);
|
||||||
|
|
||||||
|
if (m_PSUniformStorageBuffer)
|
||||||
|
m_Shader->SetPSMaterialUniformBuffer(m_PSUniformStorageBuffer);
|
||||||
|
|
||||||
|
BindTextures();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Material::BindTextures() const
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < m_Textures.size(); i++)
|
||||||
|
{
|
||||||
|
auto& texture = m_Textures[i];
|
||||||
|
if (texture)
|
||||||
|
texture->Bind(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialInstance::MaterialInstance(const Ref<Material>& material)
|
||||||
|
: m_Material(material)
|
||||||
|
{
|
||||||
|
m_Material->m_MaterialInstances.insert(this);
|
||||||
|
AllocateStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialInstance::~MaterialInstance()
|
||||||
|
{
|
||||||
|
m_Material->m_MaterialInstances.erase(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialInstance::OnShaderReloaded()
|
||||||
|
{
|
||||||
|
AllocateStorage();
|
||||||
|
m_OverriddenValues.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialInstance::AllocateStorage()
|
||||||
|
{
|
||||||
|
const auto& vsBuffer = m_Material->m_Shader->GetVSMaterialUniformBuffer();
|
||||||
|
m_VSUniformStorageBuffer.Allocate(vsBuffer.GetSize());
|
||||||
|
memcpy(m_VSUniformStorageBuffer.Data, m_Material->m_VSUniformStorageBuffer.Data, vsBuffer.GetSize());
|
||||||
|
|
||||||
|
const auto& psBuffer = m_Material->m_Shader->GetPSMaterialUniformBuffer();
|
||||||
|
m_PSUniformStorageBuffer.Allocate(psBuffer.GetSize());
|
||||||
|
memcpy(m_PSUniformStorageBuffer.Data, m_Material->m_PSUniformStorageBuffer.Data, psBuffer.GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialInstance::OnMaterialValueUpdated(ShaderUniformDeclaration* decl)
|
||||||
|
{
|
||||||
|
if (m_OverriddenValues.find(decl->GetName()) == m_OverriddenValues.end())
|
||||||
|
{
|
||||||
|
auto& buffer = GetUniformBufferTarget(decl);
|
||||||
|
auto& materialBuffer = m_Material->GetUniformBufferTarget(decl);
|
||||||
|
buffer.Write(materialBuffer.Data + decl->GetOffset(), decl->GetSize(), decl->GetOffset());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer& MaterialInstance::GetUniformBufferTarget(ShaderUniformDeclaration* uniformDeclaration)
|
||||||
|
{
|
||||||
|
switch (uniformDeclaration->GetDomain())
|
||||||
|
{
|
||||||
|
case ShaderDomain::Vertex: return m_VSUniformStorageBuffer;
|
||||||
|
case ShaderDomain::Pixel: return m_PSUniformStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(false, "Invalid uniform declaration domain! Material does not support this shader type.");
|
||||||
|
return m_VSUniformStorageBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaterialInstance::Bind() const
|
||||||
|
{
|
||||||
|
if (m_VSUniformStorageBuffer)
|
||||||
|
m_Material->m_Shader->SetVSMaterialUniformBuffer(m_VSUniformStorageBuffer);
|
||||||
|
|
||||||
|
if (m_PSUniformStorageBuffer)
|
||||||
|
m_Material->m_Shader->SetPSMaterialUniformBuffer(m_PSUniformStorageBuffer);
|
||||||
|
|
||||||
|
m_Material->BindTextures();
|
||||||
|
for (uint32_t i = 0; i < m_Textures.size(); i++)
|
||||||
|
{
|
||||||
|
auto& texture = m_Textures[i];
|
||||||
|
if (texture)
|
||||||
|
texture->Bind(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
141
Prism/src/Prism/Renderer/Material.h
Normal file
141
Prism/src/Prism/Renderer/Material.h
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef MATERIAL_H
|
||||||
|
#define MATERIAL_H
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
#include "Shader.h"
|
||||||
|
#include "Texture.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifndef _MSC_VER
|
||||||
|
class MaterialInstance;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class PRISM_API Material
|
||||||
|
{
|
||||||
|
friend class MaterialInstance;
|
||||||
|
public:
|
||||||
|
Material(const Ref<Shader>& shader);
|
||||||
|
virtual ~Material();
|
||||||
|
|
||||||
|
void Bind() const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Set(const std::string& name, const T& value);
|
||||||
|
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<Texture>& texture)
|
||||||
|
{
|
||||||
|
auto decl = FindResourceDeclaration(name);
|
||||||
|
uint32_t slot = decl->GetRegister();
|
||||||
|
if (m_Textures.size() <= slot)
|
||||||
|
m_Textures.resize((size_t)slot + 1);
|
||||||
|
m_Textures[slot] = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<Texture2D>& texture)
|
||||||
|
{
|
||||||
|
Set(name, (const Ref<Texture>&)texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<TextureCube>& texture)
|
||||||
|
{
|
||||||
|
Set(name, (const Ref<Texture>&)texture);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void AllocateStorage();
|
||||||
|
void OnShaderReloaded();
|
||||||
|
void BindTextures() const;
|
||||||
|
|
||||||
|
ShaderUniformDeclaration* FindUniformDeclaration(const std::string& name);
|
||||||
|
ShaderResourceDeclaration* FindResourceDeclaration(const std::string& name);
|
||||||
|
Buffer& GetUniformBufferTarget(ShaderUniformDeclaration* uniformDeclaration);
|
||||||
|
private:
|
||||||
|
Ref<Shader> m_Shader;
|
||||||
|
std::unordered_set<MaterialInstance*> m_MaterialInstances;
|
||||||
|
|
||||||
|
Buffer m_VSUniformStorageBuffer;
|
||||||
|
Buffer m_PSUniformStorageBuffer;
|
||||||
|
std::vector<Ref<Texture>> m_Textures;
|
||||||
|
|
||||||
|
int32_t m_RenderFlags = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PRISM_API MaterialInstance
|
||||||
|
{
|
||||||
|
friend class Material;
|
||||||
|
public:
|
||||||
|
MaterialInstance(const Ref<Material>& material);
|
||||||
|
virtual ~MaterialInstance();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Set(const std::string& name, const T& value)
|
||||||
|
{
|
||||||
|
auto decl = m_Material->FindUniformDeclaration(name);
|
||||||
|
// HZ_CORE_ASSERT(decl, "Could not find uniform with name '{0}'", name);
|
||||||
|
PM_CORE_ASSERT(decl, "Could not find uniform with name 'x'");
|
||||||
|
auto& buffer = GetUniformBufferTarget(decl);
|
||||||
|
buffer.Write((byte*)& value, decl->GetSize(), decl->GetOffset());
|
||||||
|
|
||||||
|
m_OverriddenValues.insert(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<Texture>& texture)
|
||||||
|
{
|
||||||
|
auto decl = m_Material->FindResourceDeclaration(name);
|
||||||
|
uint32_t slot = decl->GetRegister();
|
||||||
|
if (m_Textures.size() <= slot)
|
||||||
|
m_Textures.resize((size_t)slot + 1);
|
||||||
|
m_Textures[slot] = texture;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<Texture2D>& texture)
|
||||||
|
{
|
||||||
|
Set(name, (const Ref<Texture>&)texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Set(const std::string& name, const Ref<TextureCube>& texture)
|
||||||
|
{
|
||||||
|
Set(name, (const Ref<Texture>&)texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Bind() const;
|
||||||
|
private:
|
||||||
|
void AllocateStorage();
|
||||||
|
void OnShaderReloaded();
|
||||||
|
Buffer& GetUniformBufferTarget(ShaderUniformDeclaration* uniformDeclaration);
|
||||||
|
void OnMaterialValueUpdated(ShaderUniformDeclaration* decl);
|
||||||
|
private:
|
||||||
|
Ref<Material> m_Material;
|
||||||
|
|
||||||
|
Buffer m_VSUniformStorageBuffer;
|
||||||
|
Buffer m_PSUniformStorageBuffer;
|
||||||
|
std::vector<Ref<Texture>> m_Textures;
|
||||||
|
|
||||||
|
// TODO: This is temporary; come up with a proper system to track overrides
|
||||||
|
std::unordered_set<std::string> m_OverriddenValues;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Material::Set(const std::string& name, const T& value)
|
||||||
|
{
|
||||||
|
auto decl = FindUniformDeclaration(name);
|
||||||
|
// HZ_CORE_ASSERT(decl, "Could not find uniform with name '{0}'", name);
|
||||||
|
PM_CORE_ASSERT(decl, "Could not find uniform with name 'x'");
|
||||||
|
auto& buffer = GetUniformBufferTarget(decl);
|
||||||
|
buffer.Write((byte*)&value, decl->GetSize(), decl->GetOffset());
|
||||||
|
|
||||||
|
for (auto mi : m_MaterialInstances)
|
||||||
|
mi->OnMaterialValueUpdated(decl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //MATERIAL_H
|
||||||
@ -11,23 +11,21 @@
|
|||||||
#include "assimp/postprocess.h"
|
#include "assimp/postprocess.h"
|
||||||
#include "assimp/scene.h"
|
#include "assimp/scene.h"
|
||||||
#include "glad/glad.h"
|
#include "glad/glad.h"
|
||||||
#include "Prism/Core/Log.h"
|
|
||||||
|
#define GLM_ENABLE_EXPERIMENTAL
|
||||||
|
#include "glm/gtx/quaternion.hpp"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
const unsigned int s_ImportFlags =
|
||||||
|
aiProcess_CalcTangentSpace | // Create binormals/tangents just in case
|
||||||
|
aiProcess_Triangulate | // Make sure we're triangles
|
||||||
|
aiProcess_SortByPType | // Split meshes by primitive type
|
||||||
|
aiProcess_GenNormals | // Make sure we have legit normals
|
||||||
|
aiProcess_GenUVCoords | // Convert UVs if required
|
||||||
|
aiProcess_OptimizeMeshes | // Batch draws where possible
|
||||||
|
aiProcess_ValidateDataStructure; // Validation
|
||||||
|
|
||||||
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
|
struct LogStream : public Assimp::LogStream
|
||||||
{
|
{
|
||||||
@ -40,12 +38,56 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(const char* message) override
|
virtual void write(const char* message) override
|
||||||
{
|
{
|
||||||
PM_CORE_ERROR("Assimp error: {0}", message);
|
PM_CORE_ERROR("Assimp error: {0}", message);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static glm::mat4 aiMatrix4x4ToGlm(const aiMatrix4x4 &from)
|
||||||
|
{
|
||||||
|
glm::mat4 to;
|
||||||
|
//the a,b,c,d in assimp is the row ; the 1,2,3,4 is the column
|
||||||
|
to[0][0] = from.a1; to[1][0] = from.a2; to[2][0] = from.a3; to[3][0] = from.a4;
|
||||||
|
to[0][1] = from.b1; to[1][1] = from.b2; to[2][1] = from.b3; to[3][1] = from.b4;
|
||||||
|
to[0][2] = from.c1; to[1][2] = from.c2; to[2][2] = from.c3; to[3][2] = from.c4;
|
||||||
|
to[0][3] = from.d1; to[1][3] = from.d2; to[2][3] = from.d3; to[3][3] = from.d4;
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Vertex::AddBoneData(uint32_t BoneID, float Weight)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (Weights[i] == 0.0)
|
||||||
|
{
|
||||||
|
IDs[i] = BoneID;
|
||||||
|
Weights[i] = Weight;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Keep top weights
|
||||||
|
PM_CORE_WARN("Vertex has more than four bones/weights affecting it, extra data will be discarded (BoneID={0}, Weight={1})", BoneID, Weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VertexBoneData::AddBoneData(uint32_t BoneID, float Weight)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
|
if (Weights[i] == 0.0)
|
||||||
|
{
|
||||||
|
IDs[i] = BoneID;
|
||||||
|
Weights[i] = Weight;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// should never get here - more bones than we have space for
|
||||||
|
PM_CORE_ASSERT(false, "Too many bones!");
|
||||||
|
}
|
||||||
|
|
||||||
Mesh::Mesh(const std::string& filename)
|
Mesh::Mesh(const std::string& filename)
|
||||||
: m_FilePath(filename)
|
: m_FilePath(filename)
|
||||||
{
|
{
|
||||||
@ -53,77 +95,365 @@ namespace Prism
|
|||||||
|
|
||||||
PM_CORE_INFO("Loading mesh: {0}", filename.c_str());
|
PM_CORE_INFO("Loading mesh: {0}", filename.c_str());
|
||||||
|
|
||||||
Assimp::Importer importer;
|
m_Importer = std::make_unique<Assimp::Importer>();
|
||||||
|
|
||||||
const aiScene* scene = importer.ReadFile(filename, ImportFlags);
|
const aiScene* scene = m_Importer->ReadFile(filename, s_ImportFlags);
|
||||||
if (!scene || !scene->HasMeshes())
|
if (!scene || !scene->HasMeshes())
|
||||||
PM_CORE_ERROR("Failed to load mesh file: {0}", filename);
|
PM_CORE_ERROR("Failed to load mesh file: {0}", filename);
|
||||||
|
|
||||||
aiMesh* mesh = scene->mMeshes[0];
|
|
||||||
|
|
||||||
PM_CORE_ASSERT(mesh->HasPositions(), "Meshes require positions.");
|
m_InverseTransform = glm::inverse(aiMatrix4x4ToGlm(scene->mRootNode->mTransformation));
|
||||||
PM_CORE_ASSERT(mesh->HasNormals(), "Meshes require normals.");
|
|
||||||
|
|
||||||
m_Vertices.reserve(mesh->mNumVertices);
|
uint32_t vertexCount = 0;
|
||||||
|
uint32_t indexCount = 0;
|
||||||
|
|
||||||
// Extract vertices from model
|
m_Submeshes.reserve(scene->mNumMeshes);
|
||||||
for (size_t i = 0; i < m_Vertices.capacity(); i++)
|
for (size_t m = 0; m < scene->mNumMeshes; m++)
|
||||||
{
|
{
|
||||||
Vertex vertex;
|
aiMesh* mesh = scene->mMeshes[m];
|
||||||
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())
|
Submesh submesh;
|
||||||
|
submesh.BaseVertex = vertexCount;
|
||||||
|
submesh.BaseIndex = indexCount;
|
||||||
|
submesh.MaterialIndex = mesh->mMaterialIndex;
|
||||||
|
submesh.IndexCount = mesh->mNumFaces * 3;
|
||||||
|
m_Submeshes.push_back(submesh);
|
||||||
|
|
||||||
|
vertexCount += mesh->mNumVertices;
|
||||||
|
indexCount += submesh.IndexCount;
|
||||||
|
|
||||||
|
PM_CORE_ASSERT(mesh->HasPositions(), "Meshes require positions.");
|
||||||
|
PM_CORE_ASSERT(mesh->HasNormals(), "Meshes require normals.");
|
||||||
|
|
||||||
|
// Vertices
|
||||||
|
for (size_t i = 0; i < mesh->mNumVertices; i++)
|
||||||
{
|
{
|
||||||
vertex.Tangent = { mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z };
|
Vertex vertex;
|
||||||
vertex.Binormal = { mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z };
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mesh->HasTextureCoords(0))
|
// Indices
|
||||||
vertex.Texcoord = { mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y };
|
for (size_t i = 0; i < mesh->mNumFaces; i++)
|
||||||
m_Vertices.push_back(vertex);
|
{
|
||||||
|
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] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bones
|
||||||
|
for (size_t m = 0; m < scene->mNumMeshes; m++)
|
||||||
|
{
|
||||||
|
aiMesh* mesh = scene->mMeshes[m];
|
||||||
|
Submesh& submesh = m_Submeshes[m];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mesh->mNumBones; i++)
|
||||||
|
{
|
||||||
|
aiBone* bone = mesh->mBones[i];
|
||||||
|
std::string boneName(bone->mName.data);
|
||||||
|
int boneIndex = 0;
|
||||||
|
|
||||||
|
if (m_BoneMapping.find(boneName) == m_BoneMapping.end())
|
||||||
|
{
|
||||||
|
// Allocate an index for a new bone
|
||||||
|
boneIndex = m_BoneCount;
|
||||||
|
m_BoneCount++;
|
||||||
|
BoneInfo bi;
|
||||||
|
m_BoneInfo.push_back(bi);
|
||||||
|
m_BoneInfo[boneIndex].BoneOffset = aiMatrix4x4ToGlm(bone->mOffsetMatrix);
|
||||||
|
m_BoneMapping[boneName] = boneIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PM_CORE_TRACE("Found existing bone in map");
|
||||||
|
boneIndex = m_BoneMapping[boneName];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t j = 0; j < bone->mNumWeights; j++)
|
||||||
|
{
|
||||||
|
int VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId;
|
||||||
|
float Weight = bone->mWeights[j].mWeight;
|
||||||
|
m_Vertices[VertexID].AddBoneData(boneIndex, Weight);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_VertexBuffer.reset(VertexBuffer::Create());
|
m_VertexBuffer.reset(VertexBuffer::Create());
|
||||||
m_VertexBuffer->SetData(m_Vertices.data(), (uint32_t)(m_Vertices.size() * sizeof(Vertex)));
|
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.reset(IndexBuffer::Create());
|
||||||
m_IndexBuffer->SetData(m_Indices.data(), (uint32_t)(m_Indices.size() * sizeof(Index)));
|
m_IndexBuffer->SetData(m_Indices.data(), m_Indices.size() * sizeof(Index));
|
||||||
|
|
||||||
|
m_Scene = scene;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mesh::~Mesh()
|
Mesh::~Mesh()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Mesh::Render()
|
void Mesh::Render(TimeStep deltaTime, Shader* shader)
|
||||||
{
|
{
|
||||||
// TODO: Sort this out
|
if (m_AnimationPlaying && m_Scene->mAnimations)
|
||||||
m_VertexBuffer->Bind();
|
{
|
||||||
m_IndexBuffer->Bind();
|
m_WorldTime += deltaTime;
|
||||||
PM_RENDER_S({
|
|
||||||
glEnableVertexAttribArray(0);
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Position));
|
|
||||||
|
|
||||||
glEnableVertexAttribArray(1);
|
float ticksPerSecond = (float)(m_Scene->mAnimations[0]->mTicksPerSecond != 0 ? m_Scene->mAnimations[0]->mTicksPerSecond : 25.0f) * m_TimeMultiplier;
|
||||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Normal));
|
m_AnimationTime += deltaTime * ticksPerSecond;
|
||||||
|
m_AnimationTime = fmod(m_AnimationTime, (float)m_Scene->mAnimations[0]->mDuration);
|
||||||
|
}
|
||||||
|
|
||||||
glEnableVertexAttribArray(2);
|
if (m_Scene->mAnimations)
|
||||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Tangent));
|
BoneTransform(m_AnimationTime);
|
||||||
|
|
||||||
glEnableVertexAttribArray(3);
|
// TODO: Sort this out
|
||||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Binormal));
|
m_VertexBuffer->Bind();
|
||||||
|
m_IndexBuffer->Bind();
|
||||||
|
|
||||||
glEnableVertexAttribArray(4);
|
// TODO: replace with render API calls
|
||||||
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Texcoord));
|
PM_RENDER_S1(shader, {
|
||||||
});
|
for (Submesh& submesh : self->m_Submeshes)
|
||||||
Renderer::DrawIndexed(m_IndexBuffer->GetCount());
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(5);
|
||||||
|
glVertexAttribIPointer(5, 4, GL_INT, sizeof(Vertex), (const void*)offsetof(Vertex, IDs));
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(6);
|
||||||
|
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const void*)offsetof(Vertex, Weights));
|
||||||
|
|
||||||
|
if (self->m_Scene->mAnimations)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < self->m_BoneTransforms.size(); i++)
|
||||||
|
{
|
||||||
|
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
|
||||||
|
shader->SetMat4FromRenderThread(uniformName, self->m_BoneTransforms[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::OnImGuiRender()
|
||||||
|
{
|
||||||
|
ImGui::Begin("Mesh Debug");
|
||||||
|
if (ImGui::CollapsingHeader(m_FilePath.c_str()))
|
||||||
|
{
|
||||||
|
if (ImGui::CollapsingHeader("Animation"))
|
||||||
|
{
|
||||||
|
if (ImGui::Button(m_AnimationPlaying ? "Pause" : "Play"))
|
||||||
|
m_AnimationPlaying = !m_AnimationPlaying;
|
||||||
|
|
||||||
|
ImGui::SliderFloat("##AnimationTime", &m_AnimationTime, 0.0f, (float)m_Scene->mAnimations[0]->mDuration);
|
||||||
|
ImGui::DragFloat("Time Scale", &m_TimeMultiplier, 0.05f, 0.0f, 10.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::DumpVertexBuffer()
|
||||||
|
{
|
||||||
|
// TODO: Convert to ImGui
|
||||||
|
PM_CORE_TRACE("------------------------------------------------------");
|
||||||
|
PM_CORE_TRACE("Vertex Buffer Dump");
|
||||||
|
PM_CORE_TRACE("Mesh: {0}", m_FilePath);
|
||||||
|
for (size_t i = 0; i < m_Vertices.size(); i++)
|
||||||
|
{
|
||||||
|
auto& vertex = m_Vertices[i];
|
||||||
|
PM_CORE_TRACE("Vertex: {0}", i);
|
||||||
|
PM_CORE_TRACE("Position: {0}, {1}, {2}", vertex.Position.x, vertex.Position.y, vertex.Position.z);
|
||||||
|
PM_CORE_TRACE("Normal: {0}, {1}, {2}", vertex.Normal.x, vertex.Normal.y, vertex.Normal.z);
|
||||||
|
PM_CORE_TRACE("Binormal: {0}, {1}, {2}", vertex.Binormal.x, vertex.Binormal.y, vertex.Binormal.z);
|
||||||
|
PM_CORE_TRACE("Tangent: {0}, {1}, {2}", vertex.Tangent.x, vertex.Tangent.y, vertex.Tangent.z);
|
||||||
|
PM_CORE_TRACE("TexCoord: {0}, {1}", vertex.Texcoord.x, vertex.Texcoord.y);
|
||||||
|
PM_CORE_TRACE("--");
|
||||||
|
}
|
||||||
|
PM_CORE_TRACE("------------------------------------------------------");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::BoneTransform(float time)
|
||||||
|
{
|
||||||
|
ReadNodeHierarchy(time, m_Scene->mRootNode, glm::mat4(1.0f));
|
||||||
|
m_BoneTransforms.resize(m_BoneCount);
|
||||||
|
for (size_t i = 0; i < m_BoneCount; i++)
|
||||||
|
m_BoneTransforms[i] = m_BoneInfo[i].FinalTransformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Mesh::ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform)
|
||||||
|
{
|
||||||
|
std::string name(pNode->mName.data);
|
||||||
|
const aiAnimation* animation = m_Scene->mAnimations[0];
|
||||||
|
glm::mat4 nodeTransform(aiMatrix4x4ToGlm(pNode->mTransformation));
|
||||||
|
const aiNodeAnim* nodeAnim = FindNodeAnim(animation, name);
|
||||||
|
|
||||||
|
if (nodeAnim)
|
||||||
|
{
|
||||||
|
glm::vec3 translation = InterpolateTranslation(AnimationTime, nodeAnim);
|
||||||
|
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(translation.x, translation.y, translation.z));
|
||||||
|
|
||||||
|
glm::quat rotation = InterpolateRotation(AnimationTime, nodeAnim);
|
||||||
|
glm::mat4 rotationMatrix = glm::toMat4(rotation);
|
||||||
|
|
||||||
|
glm::vec3 scale = InterpolateScale(AnimationTime, nodeAnim);
|
||||||
|
glm::mat4 scaleMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(scale.x, scale.y, scale.z));
|
||||||
|
|
||||||
|
nodeTransform = translationMatrix * rotationMatrix * scaleMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 transform = ParentTransform * nodeTransform;
|
||||||
|
|
||||||
|
if (m_BoneMapping.find(name) != m_BoneMapping.end())
|
||||||
|
{
|
||||||
|
uint32_t BoneIndex = m_BoneMapping[name];
|
||||||
|
m_BoneInfo[BoneIndex].FinalTransformation = m_InverseTransform * transform * m_BoneInfo[BoneIndex].BoneOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < pNode->mNumChildren; i++)
|
||||||
|
ReadNodeHierarchy(AnimationTime, pNode->mChildren[i], transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
const aiNodeAnim* Mesh::FindNodeAnim(const aiAnimation* animation, const std::string& nodeName)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < animation->mNumChannels; i++)
|
||||||
|
{
|
||||||
|
const aiNodeAnim* nodeAnim = animation->mChannels[i];
|
||||||
|
if (std::string(nodeAnim->mNodeName.data) == nodeName)
|
||||||
|
return nodeAnim;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Mesh::FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < pNodeAnim->mNumPositionKeys - 1; i++)
|
||||||
|
{
|
||||||
|
if (AnimationTime < (float)pNodeAnim->mPositionKeys[i + 1].mTime)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Mesh::FindRotation(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(pNodeAnim->mNumRotationKeys > 0);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < pNodeAnim->mNumRotationKeys - 1; i++)
|
||||||
|
{
|
||||||
|
if (AnimationTime < (float)pNodeAnim->mRotationKeys[i + 1].mTime)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Mesh::FindScaling(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(pNodeAnim->mNumScalingKeys > 0);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < pNodeAnim->mNumScalingKeys - 1; i++)
|
||||||
|
{
|
||||||
|
if (AnimationTime < (float)pNodeAnim->mScalingKeys[i + 1].mTime)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Mesh::InterpolateTranslation(float animationTime, const aiNodeAnim* nodeAnim)
|
||||||
|
{
|
||||||
|
if (nodeAnim->mNumPositionKeys == 1)
|
||||||
|
{
|
||||||
|
// No interpolation necessary for single value
|
||||||
|
auto v = nodeAnim->mPositionKeys[0].mValue;
|
||||||
|
return { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PositionIndex = FindPosition(animationTime, nodeAnim);
|
||||||
|
uint32_t NextPositionIndex = (PositionIndex + 1);
|
||||||
|
PM_CORE_ASSERT(NextPositionIndex < nodeAnim->mNumPositionKeys);
|
||||||
|
float DeltaTime = (float)(nodeAnim->mPositionKeys[NextPositionIndex].mTime - nodeAnim->mPositionKeys[PositionIndex].mTime);
|
||||||
|
float Factor = (animationTime - (float)nodeAnim->mPositionKeys[PositionIndex].mTime) / DeltaTime;
|
||||||
|
if (Factor < 0.0f)
|
||||||
|
Factor = 0.0f;
|
||||||
|
PM_CORE_ASSERT(Factor <= 1.0f, "Factor must be below 1.0f");
|
||||||
|
const aiVector3D& Start = nodeAnim->mPositionKeys[PositionIndex].mValue;
|
||||||
|
const aiVector3D& End = nodeAnim->mPositionKeys[NextPositionIndex].mValue;
|
||||||
|
aiVector3D Delta = End - Start;
|
||||||
|
auto aiVec = Start + Factor * Delta;
|
||||||
|
return { aiVec.x, aiVec.y, aiVec.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::quat Mesh::InterpolateRotation(float animationTime, const aiNodeAnim* nodeAnim)
|
||||||
|
{
|
||||||
|
if (nodeAnim->mNumRotationKeys == 1)
|
||||||
|
{
|
||||||
|
// No interpolation necessary for single value
|
||||||
|
auto v = nodeAnim->mRotationKeys[0].mValue;
|
||||||
|
return glm::quat(v.w, v.x, v.y, v.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t RotationIndex = FindRotation(animationTime, nodeAnim);
|
||||||
|
uint32_t NextRotationIndex = (RotationIndex + 1);
|
||||||
|
PM_CORE_ASSERT(NextRotationIndex < nodeAnim->mNumRotationKeys);
|
||||||
|
float DeltaTime = (float)(nodeAnim->mRotationKeys[NextRotationIndex].mTime - nodeAnim->mRotationKeys[RotationIndex].mTime);
|
||||||
|
float Factor = (animationTime - (float)nodeAnim->mRotationKeys[RotationIndex].mTime) / DeltaTime;
|
||||||
|
if (Factor < 0.0f)
|
||||||
|
Factor = 0.0f;
|
||||||
|
PM_CORE_ASSERT(Factor <= 1.0f, "Factor must be below 1.0f");
|
||||||
|
const aiQuaternion& StartRotationQ = nodeAnim->mRotationKeys[RotationIndex].mValue;
|
||||||
|
const aiQuaternion& EndRotationQ = nodeAnim->mRotationKeys[NextRotationIndex].mValue;
|
||||||
|
auto q = aiQuaternion();
|
||||||
|
aiQuaternion::Interpolate(q, StartRotationQ, EndRotationQ, Factor);
|
||||||
|
q = q.Normalize();
|
||||||
|
return glm::quat(q.w, q.x, q.y, q.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 Mesh::InterpolateScale(float animationTime, const aiNodeAnim* nodeAnim)
|
||||||
|
{
|
||||||
|
if (nodeAnim->mNumScalingKeys == 1)
|
||||||
|
{
|
||||||
|
// No interpolation necessary for single value
|
||||||
|
auto v = nodeAnim->mScalingKeys[0].mValue;
|
||||||
|
return { v.x, v.y, v.z };
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t index = FindScaling(animationTime, nodeAnim);
|
||||||
|
uint32_t nextIndex = (index + 1);
|
||||||
|
PM_CORE_ASSERT(nextIndex < nodeAnim->mNumScalingKeys);
|
||||||
|
float deltaTime = (float)(nodeAnim->mScalingKeys[nextIndex].mTime - nodeAnim->mScalingKeys[index].mTime);
|
||||||
|
float factor = (animationTime - (float)nodeAnim->mScalingKeys[index].mTime) / deltaTime;
|
||||||
|
if (factor < 0.0f)
|
||||||
|
factor = 0.0f;
|
||||||
|
PM_CORE_ASSERT(factor <= 1.0f, "Factor must be below 1.0f");
|
||||||
|
const auto& start = nodeAnim->mScalingKeys[index].mValue;
|
||||||
|
const auto& end = nodeAnim->mScalingKeys[nextIndex].mValue;
|
||||||
|
auto delta = end - start;
|
||||||
|
auto aiVec = start + factor * delta;
|
||||||
|
return { aiVec.x, aiVec.y, aiVec.z };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,42 +8,122 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
|
#include "Shader.h"
|
||||||
|
#include "Prism/Core/TimeStep.h"
|
||||||
|
|
||||||
|
struct aiNode;
|
||||||
|
struct aiAnimation;
|
||||||
|
struct aiNodeAnim;
|
||||||
|
struct aiScene;
|
||||||
|
|
||||||
|
namespace Assimp
|
||||||
|
{
|
||||||
|
class Importer;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
glm::vec3 Position;
|
||||||
|
glm::vec3 Normal;
|
||||||
|
glm::vec3 Tangent;
|
||||||
|
glm::vec3 Binormal;
|
||||||
|
glm::vec2 Texcoord;
|
||||||
|
|
||||||
|
uint32_t IDs[4] = { 0, 0,0, 0 };
|
||||||
|
float Weights[4]{ 0.0f, 0.0f, 0.0f, 0.0f };
|
||||||
|
|
||||||
|
void AddBoneData(uint32_t BoneID, float Weight);
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int NumAttributes = 5;
|
||||||
|
|
||||||
|
struct Index
|
||||||
|
{
|
||||||
|
uint32_t V1, V2, V3;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(Index) == 3 * sizeof(uint32_t));
|
||||||
|
|
||||||
|
struct BoneInfo
|
||||||
|
{
|
||||||
|
glm::mat4 BoneOffset;
|
||||||
|
glm::mat4 FinalTransformation;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexBoneData
|
||||||
|
{
|
||||||
|
uint32_t IDs[4];
|
||||||
|
float Weights[4];
|
||||||
|
|
||||||
|
VertexBoneData()
|
||||||
|
{
|
||||||
|
memset(IDs, 0, sizeof(IDs));
|
||||||
|
memset(Weights, 0, sizeof(Weights));
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddBoneData(uint32_t BoneID, float Weight);
|
||||||
|
};
|
||||||
|
|
||||||
|
class Submesh
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint32_t BaseVertex;
|
||||||
|
uint32_t BaseIndex;
|
||||||
|
uint32_t MaterialIndex;
|
||||||
|
uint32_t IndexCount;
|
||||||
|
};
|
||||||
|
|
||||||
class PRISM_API Mesh
|
class PRISM_API Mesh
|
||||||
{
|
{
|
||||||
public:
|
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(const std::string& filename);
|
||||||
~Mesh();
|
~Mesh();
|
||||||
|
|
||||||
void Render();
|
void Render(TimeStep deltaTime, Shader* shader);
|
||||||
|
void OnImGuiRender();
|
||||||
|
void DumpVertexBuffer();
|
||||||
|
|
||||||
inline const std::string& GetFilePath() const { return m_FilePath; }
|
inline const std::string& GetFilePath() const { return m_FilePath; }
|
||||||
private:
|
private:
|
||||||
std::vector<Vertex> m_Vertices;
|
void BoneTransform(float time);
|
||||||
std::vector<Index> m_Indices;
|
void ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform);
|
||||||
|
|
||||||
|
const aiNodeAnim* FindNodeAnim(const aiAnimation* animation, const std::string& nodeName);
|
||||||
|
uint32_t FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim);
|
||||||
|
uint32_t FindRotation(float AnimationTime, const aiNodeAnim* pNodeAnim);
|
||||||
|
uint32_t FindScaling(float AnimationTime, const aiNodeAnim* pNodeAnim);
|
||||||
|
glm::vec3 InterpolateTranslation(float animationTime, const aiNodeAnim* nodeAnim);
|
||||||
|
glm::quat InterpolateRotation(float animationTime, const aiNodeAnim* nodeAnim);
|
||||||
|
glm::vec3 InterpolateScale(float animationTime, const aiNodeAnim* nodeAnim);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<Submesh> m_Submeshes;
|
||||||
|
|
||||||
|
std::unique_ptr<Assimp::Importer> m_Importer;
|
||||||
|
|
||||||
|
glm::mat4 m_InverseTransform;
|
||||||
|
|
||||||
|
uint32_t m_BoneCount = 0;
|
||||||
|
std::vector<BoneInfo> m_BoneInfo;
|
||||||
|
|
||||||
std::unique_ptr<VertexBuffer> m_VertexBuffer;
|
std::unique_ptr<VertexBuffer> m_VertexBuffer;
|
||||||
std::unique_ptr<IndexBuffer> m_IndexBuffer;
|
std::unique_ptr<IndexBuffer> m_IndexBuffer;
|
||||||
|
|
||||||
|
std::vector<Vertex> m_Vertices;
|
||||||
|
std::vector<Index> m_Indices;
|
||||||
|
std::unordered_map<std::string, uint32_t> m_BoneMapping;
|
||||||
|
std::vector<glm::mat4> m_BoneTransforms;
|
||||||
|
const aiScene* m_Scene;
|
||||||
|
|
||||||
|
// Animation
|
||||||
|
float m_AnimationTime = 0.0f;
|
||||||
|
float m_WorldTime = 0.0f;
|
||||||
|
float m_TimeMultiplier = 1.0f;
|
||||||
|
bool m_AnimationPlaying = true;
|
||||||
|
|
||||||
std::string m_FilePath;
|
std::string m_FilePath;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
// std::vector<Shader*> Shader::s_AllShaders;
|
std::vector<Shader*> Shader::s_AllShaders;
|
||||||
|
|
||||||
Shader* Shader::Create(const std::string& filepath)
|
Shader* Shader::Create(const std::string& filepath)
|
||||||
{
|
{
|
||||||
@ -25,4 +25,9 @@ namespace Prism
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<Shader*>& Shader::GetAllShaders()
|
||||||
|
{
|
||||||
|
return s_AllShaders;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,6 +8,8 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
#include "glm/gtc/type_ptr.hpp"
|
#include "glm/gtc/type_ptr.hpp"
|
||||||
|
#include "Prism/Core/Buffer.h"
|
||||||
|
#include "ShaderUniform.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -95,17 +97,36 @@ namespace Prism
|
|||||||
class PRISM_API Shader
|
class PRISM_API Shader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
using ShaderReloadedCallback = std::function<void()>;
|
||||||
|
|
||||||
|
|
||||||
virtual void Reload() = 0;
|
virtual void Reload() = 0;
|
||||||
virtual void Bind() = 0;
|
virtual void Bind() = 0;
|
||||||
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
|
virtual void UploadUniformBuffer(const UniformBufferBase& uniformBuffer) = 0;
|
||||||
|
|
||||||
virtual void SetFloat(const std::string& name, float value) = 0;
|
virtual void SetFloat(const std::string& name, float value) = 0;
|
||||||
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
|
virtual void SetMat4(const std::string& name, const glm::mat4& value) = 0;
|
||||||
|
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value) = 0;
|
||||||
|
|
||||||
virtual const std::string& GetName() const = 0;
|
virtual const std::string& GetName() const = 0;
|
||||||
|
|
||||||
static Shader* Create(const std::string& filepath);
|
virtual void SetVSMaterialUniformBuffer(Buffer buffer) = 0;
|
||||||
|
virtual void SetPSMaterialUniformBuffer(Buffer buffer) = 0;
|
||||||
|
|
||||||
static inline std::vector<Shader*> s_AllShaders;
|
virtual const ShaderUniformBufferList& GetVSRendererUniforms() const = 0;
|
||||||
|
virtual const ShaderUniformBufferList& GetPSRendererUniforms() const = 0;
|
||||||
|
virtual const ShaderUniformBufferDeclaration& GetVSMaterialUniformBuffer() const = 0;
|
||||||
|
virtual const ShaderUniformBufferDeclaration& GetPSMaterialUniformBuffer() const = 0;
|
||||||
|
|
||||||
|
virtual const ShaderResourceList& GetResources() const = 0;
|
||||||
|
|
||||||
|
virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) = 0;
|
||||||
|
|
||||||
|
static Shader* Create(const std::string& filepath);
|
||||||
|
static std::vector<Shader*>& GetAllShaders();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::vector<Shader*> s_AllShaders;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
95
Prism/src/Prism/Renderer/ShaderUniform.h
Normal file
95
Prism/src/Prism/Renderer/ShaderUniform.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// Created by sfd on 25-11-27.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef SHADERUNIFORM_H
|
||||||
|
#define SHADERUNIFORM_H
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
enum class ShaderDomain
|
||||||
|
{
|
||||||
|
None = 0, Vertex = 0, Pixel = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
class PRISM_API ShaderUniformDeclaration
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class Shader;
|
||||||
|
friend class OpenGLShader;
|
||||||
|
friend class ShaderStruct;
|
||||||
|
public:
|
||||||
|
virtual const std::string& GetName() const = 0;
|
||||||
|
virtual uint32_t GetSize() const = 0;
|
||||||
|
virtual uint32_t GetCount() const = 0;
|
||||||
|
virtual uint32_t GetOffset() const = 0;
|
||||||
|
virtual ShaderDomain GetDomain() const = 0;
|
||||||
|
protected:
|
||||||
|
virtual void SetOffset(uint32_t offset) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ShaderUniformDeclaration*> ShaderUniformList;
|
||||||
|
|
||||||
|
class PRISM_API ShaderUniformBufferDeclaration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual const std::string& GetName() const = 0;
|
||||||
|
virtual uint32_t GetRegister() const = 0;
|
||||||
|
virtual uint32_t GetSize() const = 0;
|
||||||
|
virtual const ShaderUniformList& GetUniformDeclarations() const = 0;
|
||||||
|
|
||||||
|
virtual ShaderUniformDeclaration* FindUniform(const std::string& name) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ShaderUniformBufferDeclaration*> ShaderUniformBufferList;
|
||||||
|
|
||||||
|
class ShaderStruct
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
friend class Shader;
|
||||||
|
private:
|
||||||
|
std::string m_Name;
|
||||||
|
std::vector<ShaderUniformDeclaration*> m_Fields;
|
||||||
|
uint32_t m_Size;
|
||||||
|
uint32_t m_Offset;
|
||||||
|
public:
|
||||||
|
ShaderStruct(const std::string& name)
|
||||||
|
: m_Name(name), m_Size(0), m_Offset(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddField(ShaderUniformDeclaration* field)
|
||||||
|
{
|
||||||
|
m_Size += field->GetSize();
|
||||||
|
uint32_t offset = 0;
|
||||||
|
if (m_Fields.size())
|
||||||
|
{
|
||||||
|
ShaderUniformDeclaration* previous = m_Fields.back();
|
||||||
|
offset = previous->GetOffset() + previous->GetSize();
|
||||||
|
}
|
||||||
|
field->SetOffset(offset);
|
||||||
|
m_Fields.push_back(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetOffset(uint32_t offset) { m_Offset = offset; }
|
||||||
|
|
||||||
|
inline const std::string& GetName() const { return m_Name; }
|
||||||
|
inline uint32_t GetSize() const { return m_Size; }
|
||||||
|
inline uint32_t GetOffset() const { return m_Offset; }
|
||||||
|
inline const std::vector<ShaderUniformDeclaration*>& GetFields() const { return m_Fields; }
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ShaderStruct*> ShaderStructList;
|
||||||
|
|
||||||
|
class ShaderResourceDeclaration
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual const std::string& GetName() const = 0;
|
||||||
|
virtual uint32_t GetRegister() const = 0;
|
||||||
|
virtual uint32_t GetCount() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<ShaderResourceDeclaration*> ShaderResourceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //SHADERUNIFORM_H
|
||||||
@ -9,16 +9,27 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
Texture2D* Texture2D::Create(TextureFormat format, unsigned int width, unsigned int height)
|
uint32_t Texture::GetBPP(const TextureFormat format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case TextureFormat::RGB: return 3;
|
||||||
|
case TextureFormat::RGBA: return 4;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture2D* Texture2D::Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap)
|
||||||
{
|
{
|
||||||
switch (RendererAPI::Current())
|
switch (RendererAPI::Current())
|
||||||
{
|
{
|
||||||
case RendererAPIType::None: return nullptr;
|
case RendererAPIType::None: return nullptr;
|
||||||
case RendererAPIType::OpenGL: return new OpenGLTexture2D(format, width, height);
|
case RendererAPIType::OpenGL: return new OpenGLTexture2D(format, width, height, wrap);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Texture2D* Texture2D::Create(const std::string& path, bool srgb)
|
Texture2D* Texture2D::Create(const std::string& path, bool srgb)
|
||||||
{
|
{
|
||||||
switch (RendererAPI::Current())
|
switch (RendererAPI::Current())
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#ifndef TEXTURE_H
|
#ifndef TEXTURE_H
|
||||||
#define TEXTURE_H
|
#define TEXTURE_H
|
||||||
#include "RendererAPI.h"
|
#include "RendererAPI.h"
|
||||||
|
#include "Prism/Core/Buffer.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -17,24 +18,40 @@ namespace Prism
|
|||||||
RGBA = 2,
|
RGBA = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TextureWrap
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Clamp = 1,
|
||||||
|
Repeat = 2
|
||||||
|
};
|
||||||
|
|
||||||
class PRISM_API Texture
|
class PRISM_API Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Texture() {}
|
virtual ~Texture() {}
|
||||||
|
|
||||||
|
virtual void Bind(uint32_t slot = 0) const = 0;
|
||||||
|
|
||||||
virtual RendererID GetRendererID() const = 0;
|
virtual RendererID GetRendererID() const = 0;
|
||||||
|
|
||||||
|
static uint32_t GetBPP(TextureFormat format);
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Texture2D : public Texture
|
class PRISM_API Texture2D : public Texture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static Texture2D* Create(TextureFormat format, unsigned int width, unsigned int height);
|
static Texture2D* Create(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap = TextureWrap::Clamp);
|
||||||
static Texture2D* Create(const std::string& path, bool srgb = false);
|
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 TextureFormat GetFormat() const = 0;
|
||||||
virtual unsigned int GetWidth() const = 0;
|
virtual uint32_t GetWidth() const = 0;
|
||||||
virtual unsigned int GetHeight() const = 0;
|
virtual uint32_t GetHeight() const = 0;
|
||||||
|
|
||||||
|
virtual void Lock() = 0;
|
||||||
|
virtual void Unlock() = 0;
|
||||||
|
virtual void Resize(uint32_t width, uint32_t height) = 0;
|
||||||
|
virtual Buffer GetWriteableBuffer() = 0;
|
||||||
|
|
||||||
virtual const std::string& GetPath() const = 0;
|
virtual const std::string& GetPath() const = 0;
|
||||||
};
|
};
|
||||||
@ -44,11 +61,9 @@ namespace Prism
|
|||||||
public:
|
public:
|
||||||
static TextureCube* Create(const std::string& path);
|
static TextureCube* Create(const std::string& path);
|
||||||
|
|
||||||
virtual void Bind(unsigned int slot = 0) const = 0;
|
|
||||||
|
|
||||||
virtual TextureFormat GetFormat() const = 0;
|
virtual TextureFormat GetFormat() const = 0;
|
||||||
virtual unsigned int GetWidth() const = 0;
|
virtual uint32_t GetWidth() const = 0;
|
||||||
virtual unsigned int GetHeight() const = 0;
|
virtual uint32_t GetHeight() const = 0;
|
||||||
|
|
||||||
virtual const std::string& GetPath() const = 0;
|
virtual const std::string& GetPath() const = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,21 +7,100 @@
|
|||||||
#include "Prism/Renderer/Renderer.h"
|
#include "Prism/Renderer/Renderer.h"
|
||||||
#include "Prism/Renderer/Shader.h"
|
#include "Prism/Renderer/Shader.h"
|
||||||
|
|
||||||
static void ImGuiShowHelpMarker(const char* desc)
|
|
||||||
{
|
namespace {
|
||||||
ImGui::TextDisabled("(?)");
|
enum class PropertyFlag
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
{
|
||||||
ImGui::BeginTooltip();
|
None = 0, ColorProperty = 1
|
||||||
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
};
|
||||||
ImGui::TextUnformatted(desc);
|
|
||||||
ImGui::PopTextWrapPos();
|
void Property(const std::string& name, bool& value)
|
||||||
ImGui::EndTooltip();
|
{
|
||||||
|
ImGui::Text(name.c_str());
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
std::string id = "##" + name;
|
||||||
|
ImGui::Checkbox(id.c_str(), &value);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Property(const std::string& name, float& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||||
|
{
|
||||||
|
ImGui::Text(name.c_str());
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
std::string id = "##" + name;
|
||||||
|
ImGui::SliderFloat(id.c_str(), &value, min, max);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Property(const std::string& name, glm::vec3& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||||
|
{
|
||||||
|
ImGui::Text(name.c_str());
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
std::string id = "##" + name;
|
||||||
|
if ((int)flags & (int)PropertyFlag::ColorProperty)
|
||||||
|
ImGui::ColorEdit3(id.c_str(), glm::value_ptr(value), ImGuiColorEditFlags_NoInputs);
|
||||||
|
else
|
||||||
|
ImGui::SliderFloat3(id.c_str(), glm::value_ptr(value), min, max);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Property(const std::string& name, glm::vec3& value, PropertyFlag flags)
|
||||||
|
{
|
||||||
|
Property(name, value, -1.0f, 1.0f, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Property(const std::string& name, glm::vec4& value, float min = -1.0f, float max = 1.0f, PropertyFlag flags = PropertyFlag::None)
|
||||||
|
{
|
||||||
|
ImGui::Text(name.c_str());
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
std::string id = "##" + name;
|
||||||
|
if ((int)flags & (int)PropertyFlag::ColorProperty)
|
||||||
|
ImGui::ColorEdit4(id.c_str(), glm::value_ptr(value), ImGuiColorEditFlags_NoInputs);
|
||||||
|
else
|
||||||
|
ImGui::SliderFloat4(id.c_str(), glm::value_ptr(value), min, max);
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Property(const std::string& name, glm::vec4& value, PropertyFlag flags)
|
||||||
|
{
|
||||||
|
Property(name, value, -1.0f, 1.0f, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void ImGuiShowHelpMarker(const char* desc)
|
||||||
|
{
|
||||||
|
ImGui::TextDisabled("(?)");
|
||||||
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
|
||||||
|
ImGui::TextUnformatted(desc);
|
||||||
|
ImGui::PopTextWrapPos();
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DemoLayer::DemoLayer()
|
DemoLayer::DemoLayer()
|
||||||
: m_ClearColor{ 0.1f, 0.1f, 0.1f, 1.0f }, m_Scene(Scene::Spheres),
|
: m_ClearColor{ 0.1f, 0.1f, 0.1f, 1.0f }, m_Scene(Scene::Model),
|
||||||
m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))
|
m_Camera(glm::perspectiveFov(glm::radians(45.0f), 1280.0f, 720.0f, 0.1f, 10000.0f))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -35,8 +114,10 @@ void DemoLayer::OnAttach()
|
|||||||
m_SimplePBRShader.reset(Prism::Shader::Create("assets/shaders/simplepbr.glsl"));
|
m_SimplePBRShader.reset(Prism::Shader::Create("assets/shaders/simplepbr.glsl"));
|
||||||
m_QuadShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
m_QuadShader.reset(Prism::Shader::Create("assets/shaders/quad.glsl"));
|
||||||
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
m_HDRShader.reset(Prism::Shader::Create("assets/shaders/hdr.glsl"));
|
||||||
m_Mesh.reset(new Prism::Mesh("assets/meshes/cerberus.fbx"));
|
m_GridShader.reset(Prism::Shader::Create("assets/shaders/Grid.glsl"));
|
||||||
m_SphereMesh.reset(new Prism::Mesh("assets/models/Sphere.fbx"));
|
m_Mesh.reset(new Prism::Mesh("assets/models/m1911/m1911.fbx"));
|
||||||
|
m_SphereMesh.reset(new Prism::Mesh("assets/models/Sphere1m.fbx"));
|
||||||
|
m_PlaneMesh.reset(new Prism::Mesh("assets/models/Plane1m.fbx"));
|
||||||
|
|
||||||
// Editor
|
// Editor
|
||||||
m_CheckerboardTex.reset(Prism::Texture2D::Create("assets/editor/Checkerboard.tga"));
|
m_CheckerboardTex.reset(Prism::Texture2D::Create("assets/editor/Checkerboard.tga"));
|
||||||
@ -49,8 +130,36 @@ void DemoLayer::OnAttach()
|
|||||||
m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
m_Framebuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA16F));
|
||||||
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
m_FinalPresentBuffer.reset(Prism::FrameBuffer::Create(1280, 720, Prism::FramebufferFormat::RGBA8));
|
||||||
|
|
||||||
|
m_PBRMaterial.reset(new Prism::Material(m_SimplePBRShader));
|
||||||
|
|
||||||
|
float x = -4.0f;
|
||||||
|
float roughness = 0.0f;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
Prism::Ref<Prism::MaterialInstance> mi(new Prism::MaterialInstance(m_PBRMaterial));
|
||||||
|
mi->Set("u_Metalness", 1.0f);
|
||||||
|
mi->Set("u_Roughness", roughness);
|
||||||
|
mi->Set("u_ModelMatrix", glm::translate(glm::mat4(1.0f), glm::vec3(x, 0.0f, 0.0f)));
|
||||||
|
x += 1.1f;
|
||||||
|
roughness += 0.15f;
|
||||||
|
m_MetalSphereMaterialInstances.push_back(mi);
|
||||||
|
}
|
||||||
|
|
||||||
|
x = -4.0f;
|
||||||
|
roughness = 0.0f;
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
Prism::Ref<Prism::MaterialInstance> mi(new Prism::MaterialInstance(m_PBRMaterial));
|
||||||
|
mi->Set("u_Metalness", 0.0f);
|
||||||
|
mi->Set("u_Roughness", roughness);
|
||||||
|
mi->Set("u_ModelMatrix", translate(glm::mat4(1.0f), glm::vec3(x, 1.2f, 0.0f)));
|
||||||
|
x += 1.1f;
|
||||||
|
roughness += 0.15f;
|
||||||
|
m_DielectricSphereMaterialInstances.push_back(mi);
|
||||||
|
}
|
||||||
// Create Quad
|
// Create Quad
|
||||||
float x = -1, y = -1;
|
x = -1;
|
||||||
|
float y = -1;
|
||||||
float width = 2, height = 2;
|
float width = 2, height = 2;
|
||||||
struct QuadVertex
|
struct QuadVertex
|
||||||
{
|
{
|
||||||
@ -77,7 +186,7 @@ void DemoLayer::OnAttach()
|
|||||||
|
|
||||||
uint32_t* indices = new uint32_t[6] { 0, 1, 2, 2, 3, 0, };
|
uint32_t* indices = new uint32_t[6] { 0, 1, 2, 2, 3, 0, };
|
||||||
m_IndexBuffer.reset(Prism::IndexBuffer::Create());
|
m_IndexBuffer.reset(Prism::IndexBuffer::Create());
|
||||||
m_IndexBuffer->SetData(indices, 6 * sizeof(unsigned int));
|
m_IndexBuffer->SetData(indices, 6 * sizeof(uint32_t));
|
||||||
|
|
||||||
m_Light.Direction = { -0.5f, -0.5f, 1.0f };
|
m_Light.Direction = { -0.5f, -0.5f, 1.0f };
|
||||||
m_Light.Radiance = { 1.0f, 1.0f, 1.0f };
|
m_Light.Radiance = { 1.0f, 1.0f, 1.0f };
|
||||||
@ -87,7 +196,7 @@ void DemoLayer::OnDetach()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void DemoLayer::OnUpdate(Prism::TimeStep deltaTime)
|
void DemoLayer::OnUpdate(const Prism::TimeStep deltaTime)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
// THINGS TO LOOK AT:
|
// THINGS TO LOOK AT:
|
||||||
@ -108,12 +217,31 @@ void DemoLayer::OnUpdate(Prism::TimeStep deltaTime)
|
|||||||
m_QuadShader->UploadUniformBuffer(quadShaderUB);
|
m_QuadShader->UploadUniformBuffer(quadShaderUB);
|
||||||
|
|
||||||
m_QuadShader->Bind();
|
m_QuadShader->Bind();
|
||||||
// m_EnvironmentIrradiance->Bind(0);
|
m_QuadShader->SetMat4("u_InverseVP", inverse(viewProjection));
|
||||||
m_EnvironmentCubeMap->Bind(0);
|
m_EnvironmentCubeMap->Bind(0);
|
||||||
m_VertexBuffer->Bind();
|
m_VertexBuffer->Bind();
|
||||||
m_IndexBuffer->Bind();
|
m_IndexBuffer->Bind();
|
||||||
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
|
||||||
|
|
||||||
|
|
||||||
|
m_PBRMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
|
||||||
|
m_PBRMaterial->Set("u_Metalness", m_MetalnessInput.Value);
|
||||||
|
m_PBRMaterial->Set("u_Roughness", m_RoughnessInput.Value);
|
||||||
|
m_PBRMaterial->Set("u_ViewProjectionMatrix", viewProjection);
|
||||||
|
m_PBRMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
|
||||||
|
m_PBRMaterial->Set("lights", m_Light);
|
||||||
|
m_PBRMaterial->Set("u_CameraPosition", m_Camera.GetPosition());
|
||||||
|
m_PBRMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
|
||||||
|
m_PBRMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
m_PBRMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
m_PBRMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
m_PBRMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
|
||||||
|
m_PBRMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
|
||||||
|
|
||||||
|
m_PBRMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
|
||||||
|
m_PBRMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
|
||||||
|
m_PBRMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT);
|
||||||
|
/*
|
||||||
Prism::UniformBufferDeclaration<sizeof(mat4) * 2 + sizeof(vec3) * 4 + sizeof(float) * 8, 14> simplePbrShaderUB;
|
Prism::UniformBufferDeclaration<sizeof(mat4) * 2 + sizeof(vec3) * 4 + sizeof(float) * 8, 14> simplePbrShaderUB;
|
||||||
simplePbrShaderUB.Push("u_ViewProjectionMatrix", viewProjection);
|
simplePbrShaderUB.Push("u_ViewProjectionMatrix", viewProjection);
|
||||||
simplePbrShaderUB.Push("u_ModelMatrix", mat4(1.0f));
|
simplePbrShaderUB.Push("u_ModelMatrix", mat4(1.0f));
|
||||||
@ -134,53 +262,52 @@ void DemoLayer::OnUpdate(Prism::TimeStep deltaTime)
|
|||||||
m_EnvironmentCubeMap->Bind(10);
|
m_EnvironmentCubeMap->Bind(10);
|
||||||
m_EnvironmentIrradiance->Bind(11);
|
m_EnvironmentIrradiance->Bind(11);
|
||||||
m_BRDFLUT->Bind(15);
|
m_BRDFLUT->Bind(15);
|
||||||
|
|
||||||
m_SimplePBRShader->Bind();
|
m_SimplePBRShader->Bind();
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (m_AlbedoInput.TextureMap)
|
if (m_AlbedoInput.TextureMap)
|
||||||
m_AlbedoInput.TextureMap->Bind(1);
|
m_PBRMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
|
||||||
if (m_NormalInput.TextureMap)
|
if (m_NormalInput.TextureMap)
|
||||||
m_NormalInput.TextureMap->Bind(2);
|
m_PBRMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
|
||||||
if (m_MetalnessInput.TextureMap)
|
if (m_MetalnessInput.TextureMap)
|
||||||
m_MetalnessInput.TextureMap->Bind(3);
|
m_PBRMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
|
||||||
if (m_RoughnessInput.TextureMap)
|
if (m_RoughnessInput.TextureMap)
|
||||||
m_RoughnessInput.TextureMap->Bind(4);
|
m_PBRMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
|
||||||
|
|
||||||
if (m_Scene == Scene::Spheres)
|
if (m_Scene == Scene::Spheres)
|
||||||
{
|
{
|
||||||
// Metals
|
// Metals
|
||||||
float roughness = 0.0f;
|
|
||||||
float x = -88.0f;
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
m_SimplePBRShader->SetMat4("u_ModelMatrix", translate(mat4(1.0f), vec3(x, 0.0f, 0.0f)));
|
|
||||||
m_SimplePBRShader->SetFloat("u_Roughness", roughness);
|
|
||||||
m_SimplePBRShader->SetFloat("u_Metalness", 1.0f);
|
|
||||||
m_SphereMesh->Render();
|
|
||||||
|
|
||||||
roughness += 0.15f;
|
m_MetalSphereMaterialInstances[i]->Bind();
|
||||||
x += 22.0f;
|
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dielectrics
|
// Dielectrics
|
||||||
roughness = 0.0f;
|
|
||||||
x = -88.0f;
|
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
{
|
{
|
||||||
m_SimplePBRShader->SetMat4("u_ModelMatrix", translate(mat4(1.0f), vec3(x, 22.0f, 0.0f)));
|
m_DielectricSphereMaterialInstances[i]->Bind();
|
||||||
m_SimplePBRShader->SetFloat("u_Roughness", roughness);
|
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||||
m_SimplePBRShader->SetFloat("u_Metalness", 0.0f);
|
|
||||||
m_SphereMesh->Render();
|
|
||||||
|
|
||||||
roughness += 0.15f;
|
|
||||||
x += 22.0f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (m_Scene == Scene::Model)
|
else if (m_Scene == Scene::Model)
|
||||||
{
|
{
|
||||||
m_Mesh->Render();
|
if (m_Mesh)
|
||||||
|
{
|
||||||
|
m_PBRMaterial->Bind();
|
||||||
|
m_Mesh->Render(deltaTime, m_SimplePBRShader.get());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_GridShader->Bind();
|
||||||
|
m_GridShader->SetMat4("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
|
||||||
|
m_GridShader->SetFloat("u_Scale", m_GridScale);
|
||||||
|
m_GridShader->SetFloat("u_Res", m_GridSize);
|
||||||
|
m_PlaneMesh->Render(deltaTime, m_GridShader.get());
|
||||||
|
|
||||||
m_Framebuffer->Unbind();
|
m_Framebuffer->Unbind();
|
||||||
|
|
||||||
m_FinalPresentBuffer->Bind();
|
m_FinalPresentBuffer->Bind();
|
||||||
@ -311,35 +438,27 @@ void DemoLayer::OnImGuiRender()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Editor Panel ------------------------------------------------------------------------------
|
// Editor Panel ------------------------------------------------------------------------------
|
||||||
ImGui::Begin("Settings");
|
ImGui::Begin("Model");
|
||||||
if (ImGui::TreeNode("Shaders"))
|
|
||||||
{
|
|
||||||
auto& shaders = Prism::Shader::s_AllShaders;
|
|
||||||
for (auto& shader : shaders)
|
|
||||||
{
|
|
||||||
if (ImGui::TreeNode(shader->GetName().c_str()))
|
|
||||||
{
|
|
||||||
std::string buttonName = "Reload##" + shader->GetName();
|
|
||||||
if (ImGui::Button(buttonName.c_str()))
|
|
||||||
shader->Reload();
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ImGui::TreePop();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
|
||||||
|
|
||||||
ImGui::ColorEdit4("Clear Color", m_ClearColor);
|
ImGui::Begin("Environment");
|
||||||
|
|
||||||
ImGui::SliderFloat3("Light Dir", glm::value_ptr(m_Light.Direction), -1, 1);
|
ImGui::Columns(2);
|
||||||
ImGui::ColorEdit3("Light Radiance", glm::value_ptr(m_Light.Radiance));
|
ImGui::AlignTextToFramePadding();
|
||||||
ImGui::SliderFloat("Light Multiplier", &m_LightMultiplier, 0.0f, 5.0f);
|
|
||||||
ImGui::SliderFloat("Exposure", &m_Exposure, 0.0f, 10.0f);
|
Property("Light Direction", m_Light.Direction);
|
||||||
auto cameraForward = m_Camera.GetForwardDirection();
|
Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty);
|
||||||
ImGui::Text("Camera Forward: %.2f, %.2f, %.2f", cameraForward.x, cameraForward.y, cameraForward.z);
|
Property("Light Multiplier", m_LightMultiplier, 0.0f, 5.0f);
|
||||||
|
Property("Exposure", m_Exposure, 0.0f, 5.0f);
|
||||||
|
|
||||||
|
Property("Radiance Prefiltering", m_RadiancePrefilter);
|
||||||
|
Property("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
||||||
|
|
||||||
|
ImGui::Columns(1);
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
{
|
{
|
||||||
@ -357,12 +476,6 @@ void DemoLayer::OnImGuiRender()
|
|||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::Text("Shader Parameters");
|
|
||||||
ImGui::Checkbox("Radiance Prefiltering", &m_RadiancePrefilter);
|
|
||||||
ImGui::SliderFloat("Env Map Rotation", &m_EnvMapRotation, -360.0f, 360.0f);
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
// Textures ------------------------------------------------------------------------------
|
// Textures ------------------------------------------------------------------------------
|
||||||
{
|
{
|
||||||
// Albedo
|
// Albedo
|
||||||
@ -494,6 +607,22 @@ void DemoLayer::OnImGuiRender()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::TreeNode("Shaders"))
|
||||||
|
{
|
||||||
|
auto& shaders = Prism::Shader::GetAllShaders();
|
||||||
|
for (auto& shader : shaders)
|
||||||
|
{
|
||||||
|
if (ImGui::TreeNode(shader->GetName().c_str()))
|
||||||
|
{
|
||||||
|
std::string buttonName = "Reload##" + shader->GetName();
|
||||||
|
if (ImGui::Button(buttonName.c_str()))
|
||||||
|
shader->Reload();
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
@ -509,7 +638,8 @@ void DemoLayer::OnImGuiRender()
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
if (m_Mesh)
|
||||||
|
m_Mesh->OnImGuiRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
#include "Prism.h"
|
#include "Prism.h"
|
||||||
#include "Prism/Renderer/Camera.h"
|
#include "Prism/Renderer/Camera.h"
|
||||||
#include "Prism/Renderer/FrameBuffer.h"
|
#include "Prism/Renderer/FrameBuffer.h"
|
||||||
|
#include "Prism/Renderer/Material.h"
|
||||||
#include "Prism/Renderer/Mesh.h"
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
|
||||||
class DemoLayer : public Prism::Layer
|
class DemoLayer : public Prism::Layer
|
||||||
@ -25,19 +26,28 @@ public:
|
|||||||
private:
|
private:
|
||||||
float m_ClearColor[4];
|
float m_ClearColor[4];
|
||||||
|
|
||||||
std::unique_ptr<Prism::Shader> m_Shader;
|
Prism::Ref<Prism::Shader> m_SimplePBRShader;
|
||||||
std::unique_ptr<Prism::Shader> m_PBRShader;
|
Prism::Scope<Prism::Shader> m_QuadShader;
|
||||||
std::unique_ptr<Prism::Shader> m_SimplePBRShader;
|
Prism::Scope<Prism::Shader> m_HDRShader;
|
||||||
std::unique_ptr<Prism::Shader> m_QuadShader;
|
Prism::Scope<Prism::Shader> m_GridShader;
|
||||||
std::unique_ptr<Prism::Shader> m_HDRShader;
|
Prism::Scope<Prism::Mesh> m_Mesh;
|
||||||
std::unique_ptr<Prism::Mesh> m_Mesh;
|
Prism::Scope<Prism::Mesh> m_SphereMesh, m_PlaneMesh;
|
||||||
std::unique_ptr<Prism::Mesh> m_SphereMesh;
|
Prism::Ref<Prism::Texture2D> m_BRDFLUT;
|
||||||
std::unique_ptr<Prism::Texture2D> m_BRDFLUT;
|
|
||||||
|
Prism::Ref<Prism::Material> m_PBRMaterial;
|
||||||
|
std::vector<Prism::Ref<Prism::MaterialInstance>> m_MetalSphereMaterialInstances;
|
||||||
|
std::vector<Prism::Ref<Prism::MaterialInstance>> m_DielectricSphereMaterialInstances;
|
||||||
|
|
||||||
|
float m_GridScale = 16.025f, m_GridSize = 0.025f;
|
||||||
|
float m_MeshScale = 1.0f;
|
||||||
|
|
||||||
|
Prism::Ref<Prism::Shader> m_Shader;
|
||||||
|
Prism::Ref<Prism::Shader> m_PBRShader;
|
||||||
|
|
||||||
struct AlbedoInput
|
struct AlbedoInput
|
||||||
{
|
{
|
||||||
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
|
||||||
std::unique_ptr<Prism::Texture2D> TextureMap;
|
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||||
bool SRGB = true;
|
bool SRGB = true;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
@ -45,7 +55,7 @@ private:
|
|||||||
|
|
||||||
struct NormalInput
|
struct NormalInput
|
||||||
{
|
{
|
||||||
std::unique_ptr<Prism::Texture2D> TextureMap;
|
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
NormalInput m_NormalInput;
|
NormalInput m_NormalInput;
|
||||||
@ -53,7 +63,7 @@ private:
|
|||||||
struct MetalnessInput
|
struct MetalnessInput
|
||||||
{
|
{
|
||||||
float Value = 1.0f;
|
float Value = 1.0f;
|
||||||
std::unique_ptr<Prism::Texture2D> TextureMap;
|
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
MetalnessInput m_MetalnessInput;
|
MetalnessInput m_MetalnessInput;
|
||||||
@ -61,16 +71,16 @@ private:
|
|||||||
struct RoughnessInput
|
struct RoughnessInput
|
||||||
{
|
{
|
||||||
float Value = 0.5f;
|
float Value = 0.5f;
|
||||||
std::unique_ptr<Prism::Texture2D> TextureMap;
|
Prism::Ref<Prism::Texture2D> TextureMap;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
RoughnessInput m_RoughnessInput;
|
RoughnessInput m_RoughnessInput;
|
||||||
|
|
||||||
std::unique_ptr<Prism::FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
|
Prism::Ref<Prism::FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
|
||||||
|
|
||||||
std::unique_ptr<Prism::VertexBuffer> m_VertexBuffer;
|
Prism::Ref<Prism::VertexBuffer> m_VertexBuffer;
|
||||||
std::unique_ptr<Prism::IndexBuffer> m_IndexBuffer;
|
Prism::Ref<Prism::IndexBuffer> m_IndexBuffer;
|
||||||
std::unique_ptr<Prism::TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
|
Prism::Ref<Prism::TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
|
||||||
|
|
||||||
Prism::Camera m_Camera;
|
Prism::Camera m_Camera;
|
||||||
|
|
||||||
@ -96,7 +106,7 @@ private:
|
|||||||
Scene m_Scene;
|
Scene m_Scene;
|
||||||
|
|
||||||
// Editor resources
|
// Editor resources
|
||||||
std::unique_ptr<Prism::Texture2D> m_CheckerboardTex;
|
Prism::Ref<Prism::Texture2D> m_CheckerboardTex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -208,7 +208,7 @@ void TestLayer::OnUpdate(Prism::TimeStep deltaTime)
|
|||||||
|
|
||||||
m_Shader->Bind();
|
m_Shader->Bind();
|
||||||
|
|
||||||
m_Mesh->Render();
|
m_Mesh->Render(deltaTime, m_Shader.get());
|
||||||
// m_VertexBuffer->Bind();
|
// m_VertexBuffer->Bind();
|
||||||
// m_IndexBuffer->Bind();
|
// m_IndexBuffer->Bind();
|
||||||
|
|
||||||
|
|||||||
BIN
Sandbox/assets/models/Plane1m.fbx
Normal file
BIN
Sandbox/assets/models/Plane1m.fbx
Normal file
Binary file not shown.
17
Sandbox/assets/models/Plane1m.obj
Normal file
17
Sandbox/assets/models/Plane1m.obj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Blender v2.80 (sub 75) OBJ File: 'Plane1m.blend'
|
||||||
|
# www.blender.org
|
||||||
|
mtllib Plane1m.mtl
|
||||||
|
o Plane
|
||||||
|
v -0.500000 0.000000 0.500000
|
||||||
|
v 0.500000 0.000000 0.500000
|
||||||
|
v -0.500000 0.000000 -0.500000
|
||||||
|
v 0.500000 0.000000 -0.500000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
vn 0.0000 1.0000 0.0000
|
||||||
|
usemtl None
|
||||||
|
s off
|
||||||
|
f 2/1/1 3/2/1 1/3/1
|
||||||
|
f 2/1/1 4/4/1 3/2/1
|
||||||
BIN
Sandbox/assets/models/Sphere1m.fbx
Normal file
BIN
Sandbox/assets/models/Sphere1m.fbx
Normal file
Binary file not shown.
Binary file not shown.
BIN
Sandbox/assets/models/m1911/m1911.fbx
Normal file
BIN
Sandbox/assets/models/m1911/m1911.fbx
Normal file
Binary file not shown.
BIN
Sandbox/assets/models/m1911/m1911_color.png
Normal file
BIN
Sandbox/assets/models/m1911/m1911_color.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 MiB |
BIN
Sandbox/assets/models/m1911/m1911_metalness.png
Normal file
BIN
Sandbox/assets/models/m1911/m1911_metalness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 MiB |
BIN
Sandbox/assets/models/m1911/m1911_normal.png
Normal file
BIN
Sandbox/assets/models/m1911/m1911_normal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.7 MiB |
BIN
Sandbox/assets/models/m1911/m1911_roughness.png
Normal file
BIN
Sandbox/assets/models/m1911/m1911_roughness.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 MiB |
50
Sandbox/assets/shaders/Grid.glsl
Normal file
50
Sandbox/assets/shaders/Grid.glsl
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Simple Texture Shader
|
||||||
|
|
||||||
|
#type vertex
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) in vec3 a_Position;
|
||||||
|
layout(location = 4) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
uniform mat4 u_MVP;
|
||||||
|
|
||||||
|
out vec2 v_TexCoord;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec4 position = u_MVP * vec4(a_Position, 1.0);
|
||||||
|
gl_Position = position;
|
||||||
|
|
||||||
|
v_TexCoord = a_TexCoord;
|
||||||
|
}
|
||||||
|
|
||||||
|
#type fragment
|
||||||
|
#version 430
|
||||||
|
|
||||||
|
layout(location = 0) out vec4 color;
|
||||||
|
|
||||||
|
uniform sampler2D u_Texture;
|
||||||
|
uniform float u_Scale;
|
||||||
|
uniform float u_Res;
|
||||||
|
|
||||||
|
in vec2 v_TexCoord;
|
||||||
|
|
||||||
|
/*void main()
|
||||||
|
{
|
||||||
|
color = texture(u_Texture, v_TexCoord * 8.0);
|
||||||
|
}*/
|
||||||
|
|
||||||
|
float grid(vec2 st, float res)
|
||||||
|
{
|
||||||
|
vec2 grid = fract(st);
|
||||||
|
return step(res, grid.x) * step(res, grid.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
float scale = u_Scale;
|
||||||
|
float resolution = u_Res;
|
||||||
|
|
||||||
|
float x = grid(v_TexCoord * scale, resolution);
|
||||||
|
color = vec4(vec3(0.2), 0.5) * (1.0 - x);
|
||||||
|
}
|
||||||
@ -18,25 +18,41 @@ layout(location = 2) in vec3 a_Tangent;
|
|||||||
layout(location = 3) in vec3 a_Binormal;
|
layout(location = 3) in vec3 a_Binormal;
|
||||||
layout(location = 4) in vec2 a_TexCoord;
|
layout(location = 4) in vec2 a_TexCoord;
|
||||||
|
|
||||||
|
layout(location = 5) in ivec4 a_BoneIndices;
|
||||||
|
layout(location = 6) in vec4 a_BoneWeights;
|
||||||
|
|
||||||
uniform mat4 u_ViewProjectionMatrix;
|
uniform mat4 u_ViewProjectionMatrix;
|
||||||
uniform mat4 u_ModelMatrix;
|
uniform mat4 u_ModelMatrix;
|
||||||
|
|
||||||
|
const int MAX_BONES = 100;
|
||||||
|
uniform mat4 u_BoneTransforms[100];
|
||||||
|
|
||||||
out VertexOutput
|
out VertexOutput
|
||||||
{
|
{
|
||||||
vec3 WorldPosition;
|
vec3 WorldPosition;
|
||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
|
vec3 Binormal;
|
||||||
} vs_Output;
|
} vs_Output;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
vs_Output.WorldPosition = vec3(mat4(u_ModelMatrix) * vec4(a_Position, 1.0));
|
mat4 boneTransform = u_BoneTransforms[a_BoneIndices[0]] * a_BoneWeights[0];
|
||||||
vs_Output.Normal = a_Normal;
|
boneTransform += u_BoneTransforms[a_BoneIndices[1]] * a_BoneWeights[1];
|
||||||
|
boneTransform += u_BoneTransforms[a_BoneIndices[2]] * a_BoneWeights[2];
|
||||||
|
boneTransform += u_BoneTransforms[a_BoneIndices[3]] * a_BoneWeights[3];
|
||||||
|
|
||||||
|
vec4 localPosition = boneTransform * vec4(a_Position, 1.0);
|
||||||
|
|
||||||
|
vs_Output.WorldPosition = vec3(u_ModelMatrix * boneTransform * vec4(a_Position, 1.0));
|
||||||
|
vs_Output.Normal = mat3(boneTransform) * a_Normal;
|
||||||
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
vs_Output.TexCoord = vec2(a_TexCoord.x, 1.0 - a_TexCoord.y);
|
||||||
vs_Output.WorldNormals = mat3(u_ModelMatrix) * mat3(a_Tangent, a_Binormal, a_Normal);
|
vs_Output.WorldNormals = mat3(u_ModelMatrix) * mat3(a_Tangent, a_Binormal, a_Normal);
|
||||||
|
vs_Output.Binormal = mat3(boneTransform) * a_Binormal;
|
||||||
|
|
||||||
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
//gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * vec4(a_Position, 1.0);
|
||||||
|
gl_Position = u_ViewProjectionMatrix * u_ModelMatrix * localPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
#type fragment
|
#type fragment
|
||||||
@ -62,6 +78,7 @@ in VertexOutput
|
|||||||
vec3 Normal;
|
vec3 Normal;
|
||||||
vec2 TexCoord;
|
vec2 TexCoord;
|
||||||
mat3 WorldNormals;
|
mat3 WorldNormals;
|
||||||
|
vec3 Binormal;
|
||||||
} vs_Input;
|
} vs_Input;
|
||||||
|
|
||||||
layout(location=0) out vec4 color;
|
layout(location=0) out vec4 color;
|
||||||
|
|||||||
Reference in New Issue
Block a user