switch renderer submission from macros to lambdas
This commit is contained in:
@ -54,7 +54,7 @@ namespace Prism
|
||||
for (Layer* layer : m_LayerStack)
|
||||
layer->OnUpdate(m_TimeStep);
|
||||
|
||||
PM_RENDER_S({ self->RenderImGui(); });
|
||||
Renderer::Submit([this](){ this->RenderImGui(); });
|
||||
|
||||
Renderer::Get().WaitAndRender();
|
||||
|
||||
@ -189,7 +189,7 @@ namespace Prism
|
||||
}
|
||||
m_Minimized = false;
|
||||
|
||||
PM_RENDER_2(width, height, { glViewport(0, 0, width, height); });
|
||||
Renderer::Submit([=]() { glViewport(0, 0, width, height); });
|
||||
auto& fbs = FrameBufferPool::GetGlobal()->GetAll();
|
||||
for (auto& fb : fbs)
|
||||
{
|
||||
|
||||
@ -28,26 +28,26 @@ namespace Prism
|
||||
{
|
||||
m_LocalData = Buffer::Copy(data, size);
|
||||
|
||||
PM_RENDER_S({
|
||||
glCreateBuffers(1, &self->m_RendererID);
|
||||
glNamedBufferData(self->m_RendererID, self->m_Size, self->m_LocalData.Data, OpenGLUsage(self->m_Usage));
|
||||
Renderer::Submit([=](){
|
||||
glCreateBuffers(1, &m_RendererID);
|
||||
glNamedBufferData(m_RendererID, m_Size, m_LocalData.Data, OpenGLUsage(m_Usage));
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLVertexBuffer::OpenGLVertexBuffer(const uint32_t size, const VertexBufferUsage usage)
|
||||
: m_Size(size), m_Usage(usage)
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glCreateBuffers(1, &self->m_RendererID);
|
||||
glNamedBufferData(self->m_RendererID, self->m_Size, nullptr, OpenGLUsage(self->m_Usage));
|
||||
Renderer::Submit([this](){
|
||||
glCreateBuffers(1, &m_RendererID);
|
||||
glNamedBufferData(m_RendererID, m_Size, nullptr, OpenGLUsage(m_Usage));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
OpenGLVertexBuffer::~OpenGLVertexBuffer()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glDeleteBuffers(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glDeleteBuffers(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
@ -55,15 +55,15 @@ namespace Prism
|
||||
{
|
||||
m_LocalData = Buffer::Copy(buffer, size);
|
||||
m_Size = size;
|
||||
PM_RENDER_S1(offset, {
|
||||
glNamedBufferSubData(self->m_RendererID, offset, self->m_Size, self->m_LocalData.Data);
|
||||
Renderer::Submit([this, offset]() {
|
||||
glNamedBufferSubData(m_RendererID, offset, m_Size, m_LocalData.Data);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLVertexBuffer::Bind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_RendererID);
|
||||
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 5, 0);
|
||||
@ -81,16 +81,16 @@ namespace Prism
|
||||
{
|
||||
m_LocalData = Buffer::Copy(data, size);
|
||||
|
||||
PM_RENDER_S({
|
||||
glCreateBuffers(1, &self->m_RendererID);
|
||||
glNamedBufferData(self->m_RendererID, self->m_Size, self->m_LocalData.Data, GL_STATIC_DRAW);
|
||||
Renderer::Submit([this](){
|
||||
glCreateBuffers(1, &m_RendererID);
|
||||
glNamedBufferData(m_RendererID, m_Size, m_LocalData.Data, GL_STATIC_DRAW);
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLIndexBuffer::~OpenGLIndexBuffer()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glDeleteBuffers(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glDeleteBuffers(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
@ -98,15 +98,15 @@ namespace Prism
|
||||
{
|
||||
m_LocalData = Buffer::Copy(data, size);
|
||||
m_Size = size;
|
||||
PM_RENDER_S1(offset, {
|
||||
glNamedBufferSubData(self->m_RendererID, offset, self->m_Size, self->m_LocalData.Data);
|
||||
Renderer::Submit([this, offset](){
|
||||
glNamedBufferSubData(m_RendererID, offset, m_Size, m_LocalData.Data);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLIndexBuffer::Bind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_RendererID);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,22 +19,22 @@ namespace Prism
|
||||
|
||||
OpenGLFrameBuffer::~OpenGLFrameBuffer()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glDeleteFramebuffers(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glDeleteFramebuffers(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::Bind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
|
||||
glViewport(0, 0, self->m_Specification.Width, self->m_Specification.Height);
|
||||
Renderer::Submit([this](){
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
|
||||
glViewport(0, 0, m_Specification.Width, m_Specification.Height);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLFrameBuffer::Unbind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
Renderer::Submit([this](){
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
});
|
||||
}
|
||||
@ -46,41 +46,41 @@ namespace Prism
|
||||
|
||||
m_Specification.Width = width;
|
||||
m_Specification.Height = height;
|
||||
PM_RENDER_S({
|
||||
if (self->m_RendererID)
|
||||
Renderer::Submit([this](){
|
||||
if (m_RendererID)
|
||||
{
|
||||
glDeleteFramebuffers(1, &self->m_RendererID);
|
||||
glDeleteTextures(1, &self->m_ColorAttachment);
|
||||
glDeleteTextures(1, &self->m_DepthAttachment);
|
||||
glDeleteFramebuffers(1, &m_RendererID);
|
||||
glDeleteTextures(1, &m_ColorAttachment);
|
||||
glDeleteTextures(1, &m_DepthAttachment);
|
||||
}
|
||||
|
||||
glGenFramebuffers(1, &self->m_RendererID);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, self->m_RendererID);
|
||||
glGenFramebuffers(1, &m_RendererID);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_RendererID);
|
||||
|
||||
glGenTextures(1, &self->m_ColorAttachment);
|
||||
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
|
||||
glGenTextures(1, &m_ColorAttachment);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
|
||||
|
||||
// TODO: Create Hazel texture object based on format here
|
||||
if (self->m_Specification.Format == FramebufferFormat::RGBA16F)
|
||||
if (m_Specification.Format == FramebufferFormat::RGBA16F)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, self->m_Specification.Width, self->m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_FLOAT, nullptr);
|
||||
}
|
||||
else if (self->m_Specification.Format == FramebufferFormat::RGBA8)
|
||||
else if (m_Specification.Format == FramebufferFormat::RGBA8)
|
||||
{
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self->m_Specification.Width, self->m_Specification.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_Specification.Width, m_Specification.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->m_ColorAttachment, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_ColorAttachment, 0);
|
||||
|
||||
glGenTextures(1, &self->m_DepthAttachment);
|
||||
glBindTexture(GL_TEXTURE_2D, self->m_DepthAttachment);
|
||||
glGenTextures(1, &m_DepthAttachment);
|
||||
glBindTexture(GL_TEXTURE_2D, m_DepthAttachment);
|
||||
glTexImage2D(
|
||||
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, self->m_Specification.Width, self->m_Specification.Height, 0,
|
||||
GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, m_Specification.Width, m_Specification.Height, 0,
|
||||
GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL
|
||||
);
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, self->m_DepthAttachment, 0);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, m_DepthAttachment, 0);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
|
||||
PM_CORE_ERROR("Framebuffer is incomplete!");
|
||||
@ -91,9 +91,9 @@ namespace Prism
|
||||
|
||||
void OpenGLFrameBuffer::BindTexture(uint32_t slot) const
|
||||
{
|
||||
PM_RENDER_S1(slot, {
|
||||
Renderer::Submit([this, slot](){
|
||||
glActiveTexture(GL_TEXTURE0 + slot);
|
||||
glBindTexture(GL_TEXTURE_2D, self->m_ColorAttachment);
|
||||
glBindTexture(GL_TEXTURE_2D, m_ColorAttachment);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ namespace Prism
|
||||
{
|
||||
static void OpenGLLogMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
|
||||
{
|
||||
/*
|
||||
if (severity != GL_DEBUG_SEVERITY_NOTIFICATION)
|
||||
{
|
||||
|
||||
@ -21,7 +22,98 @@ namespace Prism
|
||||
{
|
||||
PM_CORE_TRACE("{0}", message);
|
||||
}
|
||||
PM_CORE_ASSERT(0);
|
||||
*/
|
||||
|
||||
if (severity == GL_DEBUG_SEVERITY_NOTIFICATION)
|
||||
{
|
||||
if (id == 131185 || id == 131218)
|
||||
{
|
||||
return;
|
||||
}
|
||||
PM_CORE_TRACE("[OpenGL Notification] {0}", message);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string sourceStr;
|
||||
switch (source)
|
||||
{
|
||||
case GL_DEBUG_SOURCE_API: sourceStr = "API";
|
||||
break;
|
||||
case GL_DEBUG_SOURCE_WINDOW_SYSTEM: sourceStr = "Window System";
|
||||
break;
|
||||
case GL_DEBUG_SOURCE_SHADER_COMPILER: sourceStr = "Shader Compiler";
|
||||
break;
|
||||
case GL_DEBUG_SOURCE_THIRD_PARTY: sourceStr = "Third Party";
|
||||
break;
|
||||
case GL_DEBUG_SOURCE_APPLICATION: sourceStr = "Application";
|
||||
break;
|
||||
case GL_DEBUG_SOURCE_OTHER: sourceStr = "Other";
|
||||
break;
|
||||
default: sourceStr = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
std::string typeStr;
|
||||
switch (type)
|
||||
{
|
||||
case GL_DEBUG_TYPE_ERROR: typeStr = "Error";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typeStr = "Deprecated Behavior";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typeStr = "Undefined Behavior";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PORTABILITY: typeStr = "Portability";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PERFORMANCE: typeStr = "Performance";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_MARKER: typeStr = "Marker";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_PUSH_GROUP: typeStr = "Push Group";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_POP_GROUP: typeStr = "Pop Group";
|
||||
break;
|
||||
case GL_DEBUG_TYPE_OTHER: typeStr = "Other";
|
||||
break;
|
||||
default: typeStr = "Unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
switch (severity)
|
||||
{
|
||||
case GL_DEBUG_SEVERITY_HIGH:
|
||||
PM_CORE_ERROR("[OpenGL HIGH] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}",
|
||||
sourceStr, typeStr, id, message);
|
||||
if (type == GL_DEBUG_TYPE_ERROR)
|
||||
{
|
||||
PM_CORE_ASSERT(false, "OpenGL严重错误");
|
||||
}
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_MEDIUM:
|
||||
PM_CORE_WARN("[OpenGL MEDIUM] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}", sourceStr, typeStr, id, message);
|
||||
break;
|
||||
|
||||
case GL_DEBUG_SEVERITY_LOW:
|
||||
PM_CORE_INFO("[OpenGL LOW] Source: {0}, Type: {1}, ID: {2}\nMessage: {3}", sourceStr, typeStr, id, message);
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == GL_DEBUG_TYPE_PERFORMANCE)
|
||||
{
|
||||
PM_CORE_DEBUG("[Performance Tip] {0}", message);
|
||||
}
|
||||
|
||||
if (type == GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR)
|
||||
{
|
||||
PM_CORE_ERROR("[Undefined behavior] This may cause rendering errors!");
|
||||
|
||||
GLint program;
|
||||
glGetIntegerv(GL_CURRENT_PROGRAM, &program);
|
||||
if (program != 0)
|
||||
{
|
||||
PM_CORE_DEBUG("Current Shader Program: {0}", program);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RendererAPI::Init()
|
||||
|
||||
@ -39,28 +39,29 @@ namespace Prism
|
||||
m_ShaderSource = PreProcess(source);
|
||||
Parse();
|
||||
|
||||
PM_RENDER_S({
|
||||
if (self->m_RendererID)
|
||||
glDeleteProgram(self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
auto &a = m_RendererID;
|
||||
if (m_RendererID)
|
||||
glDeleteProgram(m_RendererID);
|
||||
|
||||
self->CompileAndUploadShader();
|
||||
self->ResolveUniforms();
|
||||
self->ValidateUniforms();
|
||||
CompileAndUploadShader();
|
||||
ResolveUniforms();
|
||||
ValidateUniforms();
|
||||
|
||||
if (self->m_Loaded)
|
||||
if (m_Loaded)
|
||||
{
|
||||
for (auto& callback : self->m_ShaderReloadedCallbacks)
|
||||
for (auto& callback : m_ShaderReloadedCallbacks)
|
||||
callback();
|
||||
}
|
||||
|
||||
self->m_Loaded = true;
|
||||
m_Loaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLShader::Bind()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glUseProgram(self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glUseProgram(m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
@ -75,32 +76,32 @@ namespace Prism
|
||||
{
|
||||
const std::string& name = decl.Name;
|
||||
float value = *(float*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||
PM_RENDER_S2(name, value, {
|
||||
self->UploadUniformFloat(name, value);
|
||||
Renderer::Submit([=]() {
|
||||
UploadUniformFloat(name, value);
|
||||
});
|
||||
}
|
||||
case UniformType::Float3:
|
||||
{
|
||||
const std::string& name = decl.Name;
|
||||
glm::vec3& values = *(glm::vec3*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||
PM_RENDER_S2(name, values, {
|
||||
self->UploadUniformFloat3(name, values);
|
||||
Renderer::Submit([=]() {
|
||||
UploadUniformFloat3(name, values);
|
||||
});
|
||||
}
|
||||
case UniformType::Float4:
|
||||
{
|
||||
const std::string& name = decl.Name;
|
||||
glm::vec4& values = *(glm::vec4*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||
PM_RENDER_S2(name, values, {
|
||||
self->UploadUniformFloat4(name, values);
|
||||
Renderer::Submit([=]() {
|
||||
UploadUniformFloat4(name, values);
|
||||
});
|
||||
}
|
||||
case UniformType::Mat4:
|
||||
{
|
||||
const std::string& name = decl.Name;
|
||||
glm::mat4& values = *(glm::mat4*)(uniformBuffer.GetBuffer() + decl.Offset);
|
||||
PM_RENDER_S2(name, values, {
|
||||
self->UploadUniformMat4(name, values);
|
||||
Renderer::Submit([=](){
|
||||
UploadUniformMat4(name, values);
|
||||
});
|
||||
}
|
||||
|
||||
@ -115,38 +116,47 @@ namespace Prism
|
||||
|
||||
void OpenGLShader::SetFloat(const std::string& name, float value)
|
||||
{
|
||||
PM_RENDER_S2(name, value, {
|
||||
self->UploadUniformFloat(name, value);
|
||||
Renderer::Submit([=]() {
|
||||
UploadUniformFloat(name, value);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLShader::SetMat4(const std::string& name, const glm::mat4& value)
|
||||
{
|
||||
PM_RENDER_S2(name, value, {
|
||||
self->UploadUniformMat4(name, value);
|
||||
Renderer::Submit([=]() {
|
||||
UploadUniformMat4(name, value);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLShader::SetVSMaterialUniformBuffer(Buffer buffer)
|
||||
{
|
||||
PM_RENDER_S1(buffer, {
|
||||
glUseProgram(self->m_RendererID);
|
||||
self->ResolveAndSetUniforms(self->m_VSMaterialUniformBuffer, buffer);
|
||||
Renderer::Submit([this, buffer]() {
|
||||
glUseProgram(m_RendererID);
|
||||
ResolveAndSetUniforms(m_VSMaterialUniformBuffer, buffer);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLShader::SetPSMaterialUniformBuffer(Buffer buffer)
|
||||
{
|
||||
PM_RENDER_S1(buffer, {
|
||||
glUseProgram(self->m_RendererID);
|
||||
self->ResolveAndSetUniforms(self->m_PSMaterialUniformBuffer, buffer);
|
||||
Renderer::Submit([this, buffer]() {
|
||||
glUseProgram(m_RendererID);
|
||||
ResolveAndSetUniforms(m_PSMaterialUniformBuffer, buffer);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLShader::SetMat4FromRenderThread(const std::string& name, const glm::mat4& value)
|
||||
void OpenGLShader::SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, const bool bind)
|
||||
{
|
||||
if (bind)
|
||||
{
|
||||
UploadUniformMat4(name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int location = glGetUniformLocation(m_RendererID, name.c_str());
|
||||
if (location != -1)
|
||||
UploadUniformMat4(location, value);
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& OpenGLShader::GetName() const
|
||||
{
|
||||
@ -656,7 +666,7 @@ namespace Prism
|
||||
|
||||
|
||||
// Always detach shaders after a successful link.
|
||||
for (auto id : shaderRendererIDs)
|
||||
for (const auto id : shaderRendererIDs)
|
||||
glDetachShader(program, id);
|
||||
|
||||
m_RendererID = program;
|
||||
@ -850,64 +860,64 @@ namespace Prism
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformInt(uint32_t location, int32_t value)
|
||||
void OpenGLShader::UploadUniformInt(const uint32_t location, const int32_t value)
|
||||
{
|
||||
glUniform1i(location, value);
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformIntArray(uint32_t location, int32_t* values, int32_t count)
|
||||
void OpenGLShader::UploadUniformIntArray(const uint32_t location, const int32_t* values, const int32_t count)
|
||||
{
|
||||
glUniform1iv(location, count, values);
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformFloat(uint32_t location, float value)
|
||||
void OpenGLShader::UploadUniformFloat(const uint32_t location, const float value)
|
||||
{
|
||||
glUniform1f(location, value);
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformFloat2(uint32_t location, const glm::vec2& value)
|
||||
void OpenGLShader::UploadUniformFloat2(const uint32_t location, const glm::vec2& value)
|
||||
{
|
||||
glUniform2f(location, value.x, value.y);
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformFloat3(uint32_t location, const glm::vec3& value)
|
||||
void OpenGLShader::UploadUniformFloat3(const 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)
|
||||
void OpenGLShader::UploadUniformFloat4(const 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)
|
||||
void OpenGLShader::UploadUniformMat3(const 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)
|
||||
void OpenGLShader::UploadUniformMat4(const 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)
|
||||
void OpenGLShader::UploadUniformMat4Array(const uint32_t location, const glm::mat4& values, const uint32_t count)
|
||||
{
|
||||
glUniformMatrix4fv(location, count, GL_FALSE, glm::value_ptr(values));
|
||||
}
|
||||
|
||||
void OpenGLShader::UploadUniformStruct(OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset)
|
||||
void OpenGLShader::UploadUniformStruct(const 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];
|
||||
const 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)
|
||||
void OpenGLShader::UploadUniformIntArray(const std::string& name, const int32_t* values, const int32_t count) const
|
||||
{
|
||||
int32_t location = GetUniformLocation(name);
|
||||
glUniform1iv(location, count, values);
|
||||
|
||||
@ -31,7 +31,7 @@ namespace Prism
|
||||
virtual void SetVSMaterialUniformBuffer(Buffer buffer) override;
|
||||
virtual void SetPSMaterialUniformBuffer(Buffer buffer) override;
|
||||
|
||||
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value) override;
|
||||
virtual void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) override;
|
||||
|
||||
const std::string& GetName() const override;
|
||||
|
||||
@ -69,7 +69,7 @@ namespace Prism
|
||||
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 UploadUniformIntArray(uint32_t location, const 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);
|
||||
@ -78,8 +78,8 @@ namespace Prism
|
||||
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);
|
||||
void UploadUniformStruct(const OpenGLShaderUniformDeclaration* uniform, byte* buffer, uint32_t offset);
|
||||
void UploadUniformIntArray(const std::string& name, const int32_t* values, int32_t count) const;
|
||||
|
||||
inline const ShaderUniformBufferList& GetVSRendererUniforms() const override { return m_VSRendererUniformBuffers; }
|
||||
inline const ShaderUniformBufferList& GetPSRendererUniforms() const override { return m_PSRendererUniformBuffers; }
|
||||
|
||||
@ -36,19 +36,18 @@ namespace Prism
|
||||
OpenGLTexture2D::OpenGLTexture2D(TextureFormat format, unsigned int width, unsigned int height, TextureWrap wrap)
|
||||
: m_Format(format), m_Width(width), m_Height(height), m_Wrap(wrap)
|
||||
{
|
||||
auto self = this;
|
||||
PM_RENDER_1(self, {
|
||||
glGenTextures(1, &self->m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
|
||||
Renderer::Submit([this]() {
|
||||
glGenTextures(1, &m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_RendererID);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
GLenum wrap = self->m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
|
||||
GLenum wrap = m_Wrap == TextureWrap::Clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT;
|
||||
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(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, Prism::PrismToOpenGLTextureFormat(m_Format), m_Width, m_Height, 0, Prism::PrismToOpenGLTextureFormat(m_Format), GL_UNSIGNED_BYTE, nullptr);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
@ -68,50 +67,50 @@ namespace Prism
|
||||
m_Height = height;
|
||||
m_Format = TextureFormat::RGBA;
|
||||
|
||||
PM_RENDER_S1(srgb, {
|
||||
Renderer::Submit([this, srgb]() {
|
||||
// TODO: Consolidate properly
|
||||
if (srgb)
|
||||
{
|
||||
glCreateTextures(GL_TEXTURE_2D, 1, &self->m_RendererID);
|
||||
int levels = CalculateMipMapCount(self->m_Width, self->m_Height);
|
||||
glCreateTextures(GL_TEXTURE_2D, 1, &m_RendererID);
|
||||
int levels = CalculateMipMapCount(m_Width, m_Height);
|
||||
PM_CORE_INFO("Creating srgb texture width {0} mips", levels);
|
||||
glTextureStorage2D(self->m_RendererID, levels, GL_SRGB8, self->m_Width, self->m_Height);
|
||||
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTextureParameteri(self->m_RendererID, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTextureStorage2D(m_RendererID, levels, GL_SRGB8, m_Width, m_Height);
|
||||
glTextureParameteri(m_RendererID, GL_TEXTURE_MIN_FILTER, levels > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
|
||||
glTextureParameteri(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.Data);
|
||||
glGenerateTextureMipmap(self->m_RendererID);
|
||||
glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, GL_RGB, GL_UNSIGNED_BYTE, m_ImageData.Data);
|
||||
glGenerateTextureMipmap(m_RendererID);
|
||||
}
|
||||
else
|
||||
{
|
||||
glGenTextures(1, &self->m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_2D, self->m_RendererID);
|
||||
glGenTextures(1, &m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_2D, m_RendererID);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(self->m_Format), self->m_Width, self->m_Height, 0, srgb ? GL_SRGB8 : PrismToOpenGLTextureFormat(self->m_Format), GL_UNSIGNED_BYTE, self->m_ImageData.Data);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, PrismToOpenGLTextureFormat(m_Format), m_Width, m_Height, 0, srgb ? GL_SRGB8 : PrismToOpenGLTextureFormat(m_Format), GL_UNSIGNED_BYTE, m_ImageData.Data);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
stbi_image_free(self->m_ImageData.Data);
|
||||
stbi_image_free(m_ImageData.Data);
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLTexture2D::~OpenGLTexture2D()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glDeleteTextures(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glDeleteTextures(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLTexture2D::Bind(uint32_t slot) const
|
||||
{
|
||||
PM_RENDER_S1(slot, {
|
||||
glBindTextureUnit(slot, self->m_RendererID);
|
||||
Renderer::Submit([this, slot]() {
|
||||
glBindTextureUnit(slot, m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
@ -123,8 +122,8 @@ namespace Prism
|
||||
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);
|
||||
Renderer::Submit([this](){
|
||||
glTextureSubImage2D(m_RendererID, 0, 0, 0, m_Width, m_Height, PrismToOpenGLTextureFormat(m_Format), GL_UNSIGNED_BYTE, m_ImageData.Data);
|
||||
});
|
||||
}
|
||||
|
||||
@ -205,17 +204,17 @@ namespace Prism
|
||||
}
|
||||
faceIndex++;
|
||||
}
|
||||
PM_RENDER_S3(faces, faceWidth, faceHeight, {
|
||||
glGenTextures(1, &self->m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, self->m_RendererID);
|
||||
Renderer::Submit([=]() {
|
||||
glGenTextures(1, &m_RendererID);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, m_RendererID);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTextureParameterf(self->m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
|
||||
glTextureParameterf(m_RendererID, GL_TEXTURE_MAX_ANISOTROPY, RendererAPI::GetCapabilities().MaxAnisotropy);
|
||||
|
||||
auto format = PrismToOpenGLTextureFormat(self->m_Format);
|
||||
auto format = PrismToOpenGLTextureFormat(m_Format);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[2]);
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, format, faceWidth, faceHeight, 0, format, GL_UNSIGNED_BYTE, faces[0]);
|
||||
|
||||
@ -232,22 +231,21 @@ namespace Prism
|
||||
for (size_t i = 0; i < faces.size(); i++)
|
||||
delete[] faces[i];
|
||||
|
||||
stbi_image_free(self->m_ImageData);
|
||||
stbi_image_free(m_ImageData);
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLTextureCube::~OpenGLTextureCube()
|
||||
{
|
||||
auto self = this;
|
||||
PM_RENDER_1(self, {
|
||||
glDeleteTextures(1, &self->m_RendererID);
|
||||
Renderer::Submit([this]() {
|
||||
glDeleteTextures(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLTextureCube::Bind(uint32_t slot) const
|
||||
{
|
||||
PM_RENDER_S1(slot, {
|
||||
glBindTextureUnit(slot, self->m_RendererID);
|
||||
Renderer::Submit([this, slot]() {
|
||||
glBindTextureUnit(slot, m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -12,17 +12,17 @@ namespace Prism
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Prism::ShaderDataType::Float: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Float2: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Float3: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Float4: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Mat3: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Mat4: return GL_FLOAT;
|
||||
case Prism::ShaderDataType::Int: return GL_INT;
|
||||
case Prism::ShaderDataType::Int2: return GL_INT;
|
||||
case Prism::ShaderDataType::Int3: return GL_INT;
|
||||
case Prism::ShaderDataType::Int4: return GL_INT;
|
||||
case Prism::ShaderDataType::Bool: return GL_BOOL;
|
||||
case ShaderDataType::Float: return GL_FLOAT;
|
||||
case ShaderDataType::Float2: return GL_FLOAT;
|
||||
case ShaderDataType::Float3: return GL_FLOAT;
|
||||
case ShaderDataType::Float4: return GL_FLOAT;
|
||||
case ShaderDataType::Mat3: return GL_FLOAT;
|
||||
case ShaderDataType::Mat4: return GL_FLOAT;
|
||||
case ShaderDataType::Int: return GL_INT;
|
||||
case ShaderDataType::Int2: return GL_INT;
|
||||
case ShaderDataType::Int3: return GL_INT;
|
||||
case ShaderDataType::Int4: return GL_INT;
|
||||
case ShaderDataType::Bool: return GL_BOOL;
|
||||
}
|
||||
|
||||
PM_CORE_ASSERT(false, "Unknown ShaderDataType!");
|
||||
@ -31,28 +31,28 @@ namespace Prism
|
||||
|
||||
OpenGLVertexArray::OpenGLVertexArray()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glCreateVertexArrays(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glCreateVertexArrays(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
OpenGLVertexArray::~OpenGLVertexArray()
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glDeleteVertexArrays(1, &self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glDeleteVertexArrays(1, &m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLVertexArray::Bind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
glBindVertexArray(self->m_RendererID);
|
||||
Renderer::Submit([this](){
|
||||
glBindVertexArray(m_RendererID);
|
||||
});
|
||||
}
|
||||
|
||||
void OpenGLVertexArray::Unbind() const
|
||||
{
|
||||
PM_RENDER_S({
|
||||
Renderer::Submit([this](){
|
||||
glBindVertexArray(0);
|
||||
});
|
||||
}
|
||||
@ -64,15 +64,15 @@ namespace Prism
|
||||
Bind();
|
||||
vertexBuffer->Bind();
|
||||
|
||||
PM_RENDER_S1(vertexBuffer, {
|
||||
Renderer::Submit([this, vertexBuffer](){
|
||||
const auto& layout = vertexBuffer->GetLayout();
|
||||
for (const auto& element : layout)
|
||||
{
|
||||
auto glBaseType = ShaderDataTypeToOpenGLBaseType(element.Type);
|
||||
glEnableVertexAttribArray(self->m_VertexBufferIndex);
|
||||
glEnableVertexAttribArray(m_VertexBufferIndex);
|
||||
if (glBaseType == GL_INT)
|
||||
{
|
||||
glVertexAttribIPointer(self->m_VertexBufferIndex,
|
||||
glVertexAttribIPointer(m_VertexBufferIndex,
|
||||
element.GetComponentCount(),
|
||||
glBaseType,
|
||||
layout.GetStride(),
|
||||
@ -80,14 +80,14 @@ namespace Prism
|
||||
}
|
||||
else
|
||||
{
|
||||
glVertexAttribPointer(self->m_VertexBufferIndex,
|
||||
glVertexAttribPointer(m_VertexBufferIndex,
|
||||
element.GetComponentCount(),
|
||||
glBaseType,
|
||||
element.Normalized ? GL_TRUE : GL_FALSE,
|
||||
layout.GetStride(),
|
||||
(const void*)(intptr_t)element.Offset);
|
||||
}
|
||||
self->m_VertexBufferIndex++;
|
||||
m_VertexBufferIndex++;
|
||||
}
|
||||
});
|
||||
m_VertexBuffers.push_back(vertexBuffer);
|
||||
|
||||
@ -73,7 +73,7 @@ namespace Prism
|
||||
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)
|
||||
void VertexBoneData::AddBoneData(const uint32_t BoneID, const float Weight)
|
||||
{
|
||||
for (size_t i = 0; i < 4; i++)
|
||||
{
|
||||
@ -177,11 +177,7 @@ namespace Prism
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PM_CORE_TRACE("NODES:");
|
||||
PM_CORE_TRACE("-----------------------------");
|
||||
TraverseNodes(scene->mRootNode);
|
||||
PM_CORE_TRACE("-----------------------------");
|
||||
|
||||
// Bones
|
||||
if (m_IsAnimated)
|
||||
@ -195,7 +191,7 @@ namespace Prism
|
||||
{
|
||||
aiBone* bone = mesh->mBones[i];
|
||||
std::string boneName(bone->mName.data);
|
||||
int boneIndex = 0;
|
||||
uint32_t boneIndex = 0;
|
||||
|
||||
if (m_BoneMapping.find(boneName) == m_BoneMapping.end())
|
||||
{
|
||||
@ -215,7 +211,7 @@ namespace Prism
|
||||
|
||||
for (size_t j = 0; j < bone->mNumWeights; j++)
|
||||
{
|
||||
int VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId;
|
||||
uint32_t VertexID = submesh.BaseVertex + bone->mWeights[j].mVertexId;
|
||||
float Weight = bone->mWeights[j].mWeight;
|
||||
m_AnimatedVertices[VertexID].AddBoneData(boneIndex, Weight);
|
||||
}
|
||||
@ -267,11 +263,9 @@ namespace Prism
|
||||
m_Scene = scene;
|
||||
}
|
||||
|
||||
Mesh::~Mesh()
|
||||
{
|
||||
}
|
||||
Mesh::~Mesh() = default;
|
||||
|
||||
void Mesh::Render(TimeStep deltaTime, const Ref<MaterialInstance>& materialInstance)
|
||||
void Mesh::Render(const TimeStep deltaTime, const Ref<MaterialInstance>& materialInstance)
|
||||
{
|
||||
Render(deltaTime, glm::mat4(1.0f), materialInstance);
|
||||
}
|
||||
@ -305,15 +299,15 @@ namespace Prism
|
||||
bool materialOverride = !!materialInstance;
|
||||
|
||||
// TODO: replace with render API calls
|
||||
PM_RENDER_S2(transform, materialOverride,{
|
||||
for (Submesh& submesh : self->m_Submeshes)
|
||||
Renderer::Submit([=](){
|
||||
for (const Submesh& submesh : m_Submeshes)
|
||||
{
|
||||
if (self->m_IsAnimated)
|
||||
if (m_IsAnimated)
|
||||
{
|
||||
for (size_t i = 0; i < self->m_BoneTransforms.size(); i++)
|
||||
for (size_t i = 0; i < m_BoneTransforms.size(); i++)
|
||||
{
|
||||
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
|
||||
self->m_MeshShader->SetMat4FromRenderThread(uniformName, self->m_BoneTransforms[i]);
|
||||
m_MeshShader->SetMat4FromRenderThread(uniformName, m_BoneTransforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -321,65 +315,6 @@ namespace Prism
|
||||
// self->m_MeshShader->SetMat4FromRenderThread("u_ModelMatrix", transform * submesh.Transform);
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
|
||||
}
|
||||
|
||||
/*
|
||||
for (const Submesh& submesh : self->m_Submeshes)
|
||||
{
|
||||
if (self->m_IsAnimated)
|
||||
{
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Position));
|
||||
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Normal));
|
||||
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Tangent));
|
||||
|
||||
glEnableVertexAttribArray(3);
|
||||
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Binormal));
|
||||
|
||||
glEnableVertexAttribArray(4);
|
||||
glVertexAttribPointer(4, 2, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Texcoord));
|
||||
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribIPointer(5, 4, GL_INT, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, IDs));
|
||||
|
||||
glEnableVertexAttribArray(6);
|
||||
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Weights));
|
||||
#1#
|
||||
|
||||
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("]");
|
||||
self->m_MeshShader->SetMat4FromRenderThread(uniformName, self->m_BoneTransforms[i]);
|
||||
}
|
||||
}
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
|
||||
}else
|
||||
{
|
||||
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));
|
||||
}
|
||||
if (!materialOverride)
|
||||
self->m_MeshShader->SetMat4FromRenderThread("u_ModelMatrix", transform * submesh.Transform);
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
|
||||
}
|
||||
*/
|
||||
});
|
||||
}
|
||||
|
||||
@ -448,32 +383,32 @@ namespace Prism
|
||||
m_BoneTransforms[i] = m_BoneInfo[i].FinalTransformation;
|
||||
}
|
||||
|
||||
void Mesh::ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform)
|
||||
void Mesh::ReadNodeHierarchy(const float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform)
|
||||
{
|
||||
std::string name(pNode->mName.data);
|
||||
const 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));
|
||||
const glm::vec3 translation = InterpolateTranslation(AnimationTime, nodeAnim);
|
||||
const 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);
|
||||
const glm::quat rotation = InterpolateRotation(AnimationTime, nodeAnim);
|
||||
const 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));
|
||||
const glm::vec3 scale = InterpolateScale(AnimationTime, nodeAnim);
|
||||
const 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;
|
||||
const glm::mat4 transform = ParentTransform * nodeTransform;
|
||||
|
||||
if (m_BoneMapping.find(name) != m_BoneMapping.end())
|
||||
{
|
||||
uint32_t BoneIndex = m_BoneMapping[name];
|
||||
const uint32_t BoneIndex = m_BoneMapping[name];
|
||||
m_BoneInfo[BoneIndex].FinalTransformation = m_InverseTransform * transform * m_BoneInfo[BoneIndex].BoneOffset;
|
||||
}
|
||||
|
||||
@ -481,12 +416,14 @@ namespace Prism
|
||||
ReadNodeHierarchy(AnimationTime, pNode->mChildren[i], transform);
|
||||
}
|
||||
|
||||
void Mesh::TraverseNodes(aiNode* node, int level)
|
||||
void Mesh::TraverseNodes(const aiNode* node)
|
||||
{
|
||||
/*
|
||||
std::string levelText;
|
||||
for (int i = 0; i < level; i++)
|
||||
levelText += "-";
|
||||
PM_CORE_TRACE("{0}Node name: {1}", levelText, std::string(node->mName.data));
|
||||
*/
|
||||
for (uint32_t i = 0; i < node->mNumMeshes; i++)
|
||||
{
|
||||
uint32_t mesh = node->mMeshes[i];
|
||||
@ -495,8 +432,7 @@ namespace Prism
|
||||
|
||||
for (uint32_t i = 0; i < node->mNumChildren; i++)
|
||||
{
|
||||
aiNode* child = node->mChildren[i];
|
||||
TraverseNodes(child, level + 1);
|
||||
TraverseNodes(node->mChildren[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -511,7 +447,7 @@ namespace Prism
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t Mesh::FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
uint32_t Mesh::FindPosition(const float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
{
|
||||
for (uint32_t i = 0; i < pNodeAnim->mNumPositionKeys - 1; i++)
|
||||
{
|
||||
@ -522,7 +458,7 @@ namespace Prism
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Mesh::FindRotation(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
uint32_t Mesh::FindRotation(const float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
{
|
||||
PM_CORE_ASSERT(pNodeAnim->mNumRotationKeys > 0);
|
||||
|
||||
@ -535,7 +471,7 @@ namespace Prism
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Mesh::FindScaling(float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
uint32_t Mesh::FindScaling(const float AnimationTime, const aiNodeAnim* pNodeAnim)
|
||||
{
|
||||
PM_CORE_ASSERT(pNodeAnim->mNumScalingKeys > 0);
|
||||
|
||||
@ -548,7 +484,7 @@ namespace Prism
|
||||
return 0;
|
||||
}
|
||||
|
||||
glm::vec3 Mesh::InterpolateTranslation(float animationTime, const aiNodeAnim* nodeAnim)
|
||||
glm::vec3 Mesh::InterpolateTranslation(const float animationTime, const aiNodeAnim* nodeAnim)
|
||||
{
|
||||
if (nodeAnim->mNumPositionKeys == 1)
|
||||
{
|
||||
@ -572,7 +508,7 @@ namespace Prism
|
||||
return { aiVec.x, aiVec.y, aiVec.z };
|
||||
}
|
||||
|
||||
glm::quat Mesh::InterpolateRotation(float animationTime, const aiNodeAnim* nodeAnim)
|
||||
glm::quat Mesh::InterpolateRotation(const float animationTime, const aiNodeAnim* nodeAnim)
|
||||
{
|
||||
if (nodeAnim->mNumRotationKeys == 1)
|
||||
{
|
||||
@ -597,7 +533,7 @@ namespace Prism
|
||||
return glm::quat(q.w, q.x, q.y, q.z);
|
||||
}
|
||||
|
||||
glm::vec3 Mesh::InterpolateScale(float animationTime, const aiNodeAnim* nodeAnim)
|
||||
glm::vec3 Mesh::InterpolateScale(const float animationTime, const aiNodeAnim* nodeAnim)
|
||||
{
|
||||
if (nodeAnim->mNumScalingKeys == 1)
|
||||
{
|
||||
|
||||
@ -60,6 +60,8 @@ namespace Prism
|
||||
{
|
||||
glm::mat4 BoneOffset;
|
||||
glm::mat4 FinalTransformation;
|
||||
|
||||
BoneInfo() : BoneOffset(glm::mat4(1.0f)), FinalTransformation(glm::mat4(1.0f)) {}
|
||||
};
|
||||
|
||||
struct VertexBoneData
|
||||
@ -106,7 +108,7 @@ namespace Prism
|
||||
private:
|
||||
void BoneTransform(float time);
|
||||
void ReadNodeHierarchy(float AnimationTime, const aiNode* pNode, const glm::mat4& ParentTransform);
|
||||
void TraverseNodes(aiNode* node, int level = 0);
|
||||
void TraverseNodes(const aiNode* node);
|
||||
|
||||
const aiNodeAnim* FindNodeAnim(const aiAnimation* animation, const std::string& nodeName);
|
||||
uint32_t FindPosition(float AnimationTime, const aiNodeAnim* pNodeAnim);
|
||||
@ -153,6 +155,8 @@ namespace Prism
|
||||
bool m_AnimationPlaying = true;
|
||||
|
||||
std::string m_FilePath;
|
||||
private:
|
||||
friend class Renderer;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ namespace Prism
|
||||
{
|
||||
RenderCommandQueue::RenderCommandQueue()
|
||||
{
|
||||
m_CommandBuffer = new unsigned char[10 * 1024 * 1024]; // 10mb buffer
|
||||
m_CommandBuffer = new uint8_t[10 * 1024 * 1024]; // 10mb buffer
|
||||
m_CommandBufferPtr = m_CommandBuffer;
|
||||
memset(m_CommandBuffer, 0, 10 * 1024 * 1024);
|
||||
}
|
||||
@ -23,13 +23,13 @@ namespace Prism
|
||||
delete[] m_CommandBuffer;
|
||||
}
|
||||
|
||||
void* RenderCommandQueue::Allocate(RenderCommandFn func, unsigned int size)
|
||||
void* RenderCommandQueue::Allocate(RenderCommandFn func, uint32_t size)
|
||||
{
|
||||
*(RenderCommandFn*)m_CommandBufferPtr = func;
|
||||
m_CommandBufferPtr += sizeof(RenderCommandFn);
|
||||
|
||||
*(int*)m_CommandBufferPtr = size;
|
||||
m_CommandBufferPtr += sizeof(unsigned int);
|
||||
*(uint32_t*)m_CommandBufferPtr = size;
|
||||
m_CommandBufferPtr += sizeof(uint32_t);
|
||||
|
||||
void* memory = m_CommandBufferPtr;
|
||||
m_CommandBufferPtr += size;
|
||||
@ -44,13 +44,13 @@ namespace Prism
|
||||
|
||||
byte* buffer = m_CommandBuffer;
|
||||
|
||||
for (unsigned i = 0 ; i < m_CommandCount ; i++)
|
||||
for (uint32_t i = 0 ; i < m_CommandCount ; i++)
|
||||
{
|
||||
RenderCommandFn function = *(RenderCommandFn*)(buffer);
|
||||
buffer += sizeof(RenderCommandFn);
|
||||
|
||||
unsigned int size = *(unsigned int*)buffer;
|
||||
buffer += sizeof(unsigned int);
|
||||
uint32_t size = *(uint32_t*)buffer;
|
||||
buffer += sizeof(uint32_t);
|
||||
function(buffer);
|
||||
buffer += size;
|
||||
}
|
||||
|
||||
@ -16,13 +16,13 @@ namespace Prism
|
||||
RenderCommandQueue();
|
||||
~RenderCommandQueue();
|
||||
|
||||
void* Allocate(RenderCommandFn func, unsigned int size);
|
||||
void* Allocate(RenderCommandFn func, uint32_t size);
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
unsigned char* m_CommandBuffer = nullptr;
|
||||
unsigned char* m_CommandBufferPtr = nullptr;
|
||||
unsigned int m_CommandCount = 0;
|
||||
uint8_t* m_CommandBuffer = nullptr;
|
||||
uint8_t* m_CommandBufferPtr = nullptr;
|
||||
uint32_t m_CommandCount = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "Renderer.h"
|
||||
|
||||
#include "RendererAPI.h"
|
||||
#include "glad/glad.h"
|
||||
|
||||
|
||||
namespace Prism
|
||||
@ -14,11 +15,15 @@ namespace Prism
|
||||
|
||||
void Renderer::Clear()
|
||||
{
|
||||
Submit([]()
|
||||
{
|
||||
RendererAPI::Clear(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
});
|
||||
}
|
||||
|
||||
void Renderer::Clear(float r, float g, float b, float a)
|
||||
{
|
||||
PM_RENDER_4(r, g, b, a, {
|
||||
Submit([=](){
|
||||
RendererAPI::Clear(r, g, b, a);
|
||||
});
|
||||
}
|
||||
@ -29,7 +34,7 @@ namespace Prism
|
||||
|
||||
void Renderer::DrawIndexed(uint32_t count, bool depthTest)
|
||||
{
|
||||
PM_RENDER_2(count, depthTest, {
|
||||
Submit([=]() {
|
||||
RendererAPI::DrawIndexed(count, depthTest);
|
||||
});
|
||||
}
|
||||
@ -42,7 +47,7 @@ namespace Prism
|
||||
void Renderer::Init()
|
||||
{
|
||||
s_Instance->m_ShaderLibrary = std::make_unique<ShaderLibrary>();
|
||||
PM_RENDER({ RendererAPI::Init(); });
|
||||
Submit([](){ RendererAPI::Init(); });
|
||||
|
||||
GetShaderLibrary()->Load("assets/shaders/simplepbr_Static.glsl");
|
||||
GetShaderLibrary()->Load("assets/shaders/simplepbr_Anim.glsl");
|
||||
@ -63,9 +68,10 @@ namespace Prism
|
||||
s_Instance->IEndRenderPass();
|
||||
}
|
||||
|
||||
void Renderer::SubmitMesh(const Ref<Mesh>& mesh)
|
||||
void Renderer::SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform,
|
||||
const Ref<MaterialInstance>& overrideMaterial)
|
||||
{
|
||||
s_Instance->SubmitMeshI(mesh);
|
||||
s_Instance->SubmitMeshI(mesh, transform, overrideMaterial);
|
||||
}
|
||||
|
||||
void Renderer::IBeginRenderPass(const Ref<RenderPass>& renderPass)
|
||||
@ -74,6 +80,11 @@ namespace Prism
|
||||
m_ActiveRenderPass = renderPass;
|
||||
|
||||
renderPass->GetSpecification().TargetFramebuffer->Bind();
|
||||
|
||||
const glm::vec4& clearColor = renderPass->GetSpecification().TargetFramebuffer->GetSpecification().ClearColor;
|
||||
Submit([=]() {
|
||||
RendererAPI::Clear(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
||||
});
|
||||
}
|
||||
|
||||
void Renderer::IEndRenderPass()
|
||||
@ -83,7 +94,35 @@ namespace Prism
|
||||
m_ActiveRenderPass = nullptr;
|
||||
}
|
||||
|
||||
void Renderer::SubmitMeshI(const Ref<Mesh>& mesh)
|
||||
void Renderer::SubmitMeshI(const Ref<Mesh>& mesh, const glm::mat4& transform,
|
||||
const Ref<MaterialInstance>& overrideMaterial)
|
||||
{
|
||||
if (overrideMaterial)
|
||||
{
|
||||
overrideMaterial->Bind();
|
||||
}else
|
||||
{
|
||||
// bind mesh material here
|
||||
}
|
||||
|
||||
mesh->m_VertexArray->Bind();
|
||||
|
||||
// TODO: temp test , use RenderAPI replace this
|
||||
Submit([=]()
|
||||
{
|
||||
for (const Submesh& submesh : mesh->m_Submeshes)
|
||||
{
|
||||
if (mesh->m_IsAnimated)
|
||||
{
|
||||
for (size_t i = 0; i < mesh->m_BoneTransforms.size(); i++)
|
||||
{
|
||||
std::string uniformName = std::string("u_BoneTransforms[") + std::to_string(i) + std::string("]");
|
||||
mesh->m_MeshShader->SetMat4FromRenderThread(uniformName, mesh->m_BoneTransforms[i]);
|
||||
}
|
||||
}
|
||||
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, submesh.IndexCount, GL_UNSIGNED_INT, (void*)(sizeof(uint32_t) * submesh.BaseIndex), submesh.BaseVertex);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,10 +30,27 @@ namespace Prism
|
||||
|
||||
static const Scope<ShaderLibrary>& GetShaderLibrary() { return Get().m_ShaderLibrary; }
|
||||
|
||||
template<typename FuncT>
|
||||
static void Submit(FuncT&& func)
|
||||
{
|
||||
auto renderCmd = [](void* ptr) {
|
||||
auto pFunc = static_cast<FuncT*>(ptr);
|
||||
(*pFunc)();
|
||||
|
||||
// NOTE: Instead of destroying we could try and enforce all items to be trivally destructible
|
||||
// however some items like uniforms which contain std::strings still exist for now
|
||||
// static_assert(std::is_trivially_destructible_v<FuncT>, "FuncT must be trivially destructible");
|
||||
pFunc->~FuncT();
|
||||
};
|
||||
auto storageBuffer = s_Instance->m_CommandQueue.Allocate(renderCmd, sizeof(func));
|
||||
new (storageBuffer) FuncT(std::forward<FuncT>(func));
|
||||
}
|
||||
/*
|
||||
static void* Submit(const RenderCommandFn func, const unsigned int size)
|
||||
{
|
||||
return s_Instance->m_CommandQueue.Allocate(func, size);
|
||||
}
|
||||
*/
|
||||
|
||||
void WaitAndRender();
|
||||
inline static Renderer& Get() { return *s_Instance; }
|
||||
@ -43,13 +60,13 @@ namespace Prism
|
||||
static void BeginRenderPass(const Ref<RenderPass>& renderPass);
|
||||
static void EndRenderPass();
|
||||
|
||||
static void SubmitMesh(const Ref<Mesh>& mesh);
|
||||
static void SubmitMesh(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr);
|
||||
|
||||
private:
|
||||
void IBeginRenderPass(const Ref<RenderPass>& renderPass);
|
||||
void IEndRenderPass();
|
||||
|
||||
void SubmitMeshI(const Ref<Mesh>& mesh);
|
||||
void SubmitMeshI(const Ref<Mesh>& mesh, const glm::mat4& transform, const Ref<MaterialInstance>& overrideMaterial = nullptr);
|
||||
|
||||
|
||||
private:
|
||||
@ -60,6 +77,7 @@ namespace Prism
|
||||
RenderCommandQueue m_CommandQueue;
|
||||
};
|
||||
|
||||
#if 0
|
||||
#define PM_RENDER_PASTE2(a, b) a ## b
|
||||
#define PM_RENDER_PASTE(a, b) PM_RENDER_PASTE2(a, b)
|
||||
#define PM_RENDER_UNIQUE(x) PM_RENDER_PASTE(x, __LINE__)
|
||||
@ -183,6 +201,7 @@ PM_RENDER_3(self, arg0, arg1, code)
|
||||
|
||||
#define PM_RENDER_S3(arg0, arg1, arg2, code) auto self = this;\
|
||||
PM_RENDER_4(self, arg0, arg1, arg2, code)
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif //RENDERER_H
|
||||
|
||||
@ -108,7 +108,7 @@ namespace Prism
|
||||
|
||||
virtual void SetFloat(const std::string& name, float 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 void SetMat4FromRenderThread(const std::string& name, const glm::mat4& value, bool bind = true) = 0;
|
||||
|
||||
virtual const std::string& GetName() const = 0;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user