add vertexarray, move Sandbox::Demolayer code to EditorLayer

This commit is contained in:
2025-11-29 11:35:49 +08:00
parent abdfdd1858
commit 788081479a
31 changed files with 1327 additions and 97 deletions

View File

@ -1,7 +1,13 @@
project(PrismEditor)
file(GLOB ASSETS assets)
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR}/bin)
file(GLOB_RECURSE SRC_SOURCE ./**.cpp)
add_executable(${PROJECT_NAME} ${SRC_SOURCE})
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-shared)
target_link_libraries(${PROJECT_NAME} PRIVATE Prism-shared)
# Enable ImGui Docking space
target_compile_definitions(${PROJECT_NAME} PRIVATE ENABLE_DOCKSPACE)

View File

@ -3,26 +3,27 @@
//
#include "Prism/Core/Application.h"
#include "EditorLayer.h"
#include "Prism.h"
#include "Prism/Core/EntryPoint.h"
#include "Prism/Core/ImGui/ImGuiLayer.h"
class Editor : public Prism::Application
{
public:
Editor()
Editor(const Prism::ApplicationProps& props)
: Application(props)
{
}
virtual void OnInit() override
{
PushLayer(new Prism::ImGuiLayer("ImGui Layer"));
PushLayer(new Prism::EditorLayer());
}
};
Prism::Application* Prism::CreateApplication()
{
return new Editor();
return new Editor({"hello wrold", 1920, 1080});
}

View File

@ -3,3 +3,705 @@
//
#include "EditorLayer.h"
namespace Prism
{
enum class PropertyFlag
{
None = 0, ColorProperty = 1
};
void Property(const std::string& name, bool& value)
{
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();
}
}
EditorLayer::EditorLayer()
: 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))
{
}
EditorLayer::~EditorLayer()
{
}
void EditorLayer::OnAttach()
{
m_Framebuffer.reset(FrameBuffer::Create(1280, 720, FramebufferFormat::RGBA16F));
m_FinalPresentBuffer.reset(FrameBuffer::Create(1280, 720, FramebufferFormat::RGBA8));
m_QuadShader = Shader::Create("assets/shaders/quad.glsl");
m_HDRShader = Shader::Create("assets/shaders/hdr.glsl");
m_GridShader = Shader::Create("assets/shaders/Grid.glsl");
m_Mesh = CreateRef<Mesh>("assets/models/m1911/m1911.fbx");
m_MeshMaterial = CreateRef<MaterialInstance>(m_Mesh->GetMaterial());
m_SphereMesh = CreateRef<Mesh>("assets/models/Sphere1m.fbx");
m_PlaneMesh = CreateRef<Mesh>("assets/models/Plane1m.fbx");
m_GridShader = Shader::Create("assets/shaders/Grid.glsl");
m_GridMaterial = MaterialInstance::Create(Material::Create(m_GridShader));
m_GridMaterial->Set("u_Scale", m_GridScale);
m_GridMaterial->Set("u_Res", m_GridSize);
// Editor
m_CheckerboardTex.reset(Texture2D::Create("assets/editor/Checkerboard.tga"));
// Environment
m_EnvironmentCubeMap.reset(
TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
m_EnvironmentIrradiance.reset(
TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Irradiance.tga"));
m_BRDFLUT.reset(Texture2D::Create("assets/textures/BRDF_LUT.tga"));
float x = -4.0f;
float roughness = 0.0f;
for (int i = 0; i < 8; i++)
{
Ref<MaterialInstance> mi = CreateRef<MaterialInstance>(
m_SphereMesh->GetMaterial());
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++)
{
Ref<MaterialInstance> mi = CreateRef<MaterialInstance>(
m_SphereMesh->GetMaterial());
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
x = -1;
float y = -1;
float width = 2, height = 2;
struct QuadVertex
{
glm::vec3 Position;
glm::vec2 TexCoord;
};
static float QuadVertex[] = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
static uint32_t QuadIndices[] = {
0, 1, 2, 2, 3, 0
};
m_FullscreenQuadVertexArray = VertexArray::Create();
auto quadVB = VertexBuffer::Create(QuadVertex, sizeof(float) * sizeof(QuadVertex));
quadVB->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float2, "a_TexCoord" }
});
auto quadIB = IndexBuffer::Create(QuadIndices, sizeof(QuadIndices) * sizeof(uint32_t));
m_FullscreenQuadVertexArray->AddVertexBuffer(quadVB);
m_FullscreenQuadVertexArray->SetIndexBuffer(quadIB);
m_Light.Direction = {-0.5f, -0.5f, 1.0f};
m_Light.Radiance = {1.0f, 1.0f, 1.0f};
}
void EditorLayer::OnDetach()
{
}
void EditorLayer::OnUpdate(const TimeStep deltaTime)
{
{
// THINGS TO LOOK AT:
// - BRDF LUT
// - Cubemap mips and filtering
// - Tonemapping and proper HDR pipeline
using namespace Prism;
using namespace glm;
m_Camera.Update(deltaTime);
auto viewProjection = m_Camera.GetProjectionMatrix() * m_Camera.GetViewMatrix();
m_Framebuffer->Bind();
Renderer::Clear(m_ClearColor[0], m_ClearColor[1], m_ClearColor[2], m_ClearColor[3]);
m_QuadShader->Bind();
m_QuadShader->SetMat4("u_InverseVP", inverse(viewProjection));
m_EnvironmentCubeMap->Bind(0);
/*
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
*/
m_FullscreenQuadVertexArray->Bind();
Renderer::DrawIndexed(m_FullscreenQuadVertexArray->GetIndexBuffer()->GetCount(), false);
m_MeshMaterial->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_MeshMaterial->Set("u_Metalness", m_MetalnessInput.Value);
m_MeshMaterial->Set("u_Roughness", m_RoughnessInput.Value);
m_MeshMaterial->Set("u_ViewProjectionMatrix", viewProjection);
m_MeshMaterial->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
m_MeshMaterial->Set("lights", m_Light);
m_MeshMaterial->Set("u_CameraPosition", m_Camera.GetPosition());
m_MeshMaterial->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_MeshMaterial->Set("u_EnvMapRotation", m_EnvMapRotation);
m_MeshMaterial->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
m_MeshMaterial->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
m_MeshMaterial->Set("u_BRDFLUTTexture", m_BRDFLUT);
m_SphereMesh->GetMaterial()->Set("u_AlbedoColor", m_AlbedoInput.Color);
m_SphereMesh->GetMaterial()->Set("u_Metalness", m_MetalnessInput.Value);
m_SphereMesh->GetMaterial()->Set("u_Roughness", m_RoughnessInput.Value);
m_SphereMesh->GetMaterial()->Set("u_ViewProjectionMatrix", viewProjection);
m_SphereMesh->GetMaterial()->Set("u_ModelMatrix", scale(mat4(1.0f), vec3(m_MeshScale)));
m_SphereMesh->GetMaterial()->Set("lights", m_Light);
m_SphereMesh->GetMaterial()->Set("u_CameraPosition", m_Camera.GetPosition());
m_SphereMesh->GetMaterial()->Set("u_RadiancePrefilter", m_RadiancePrefilter ? 1.0f : 0.0f);
m_SphereMesh->GetMaterial()->Set("u_AlbedoTexToggle", m_AlbedoInput.UseTexture ? 1.0f : 0.0f);
m_SphereMesh->GetMaterial()->Set("u_NormalTexToggle", m_NormalInput.UseTexture ? 1.0f : 0.0f);
m_SphereMesh->GetMaterial()->Set("u_MetalnessTexToggle", m_MetalnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereMesh->GetMaterial()->Set("u_RoughnessTexToggle", m_RoughnessInput.UseTexture ? 1.0f : 0.0f);
m_SphereMesh->GetMaterial()->Set("u_EnvMapRotation", m_EnvMapRotation);
m_SphereMesh->GetMaterial()->Set("u_EnvRadianceTex", m_EnvironmentCubeMap);
m_SphereMesh->GetMaterial()->Set("u_EnvIrradianceTex", m_EnvironmentIrradiance);
m_SphereMesh->GetMaterial()->Set("u_BRDFLUTTexture", m_BRDFLUT);
if (m_AlbedoInput.TextureMap)
m_MeshMaterial->Set("u_AlbedoTexture", m_AlbedoInput.TextureMap);
if (m_NormalInput.TextureMap)
m_MeshMaterial->Set("u_NormalTexture", m_NormalInput.TextureMap);
if (m_MetalnessInput.TextureMap)
m_MeshMaterial->Set("u_MetalnessTexture", m_MetalnessInput.TextureMap);
if (m_RoughnessInput.TextureMap)
m_MeshMaterial->Set("u_RoughnessTexture", m_RoughnessInput.TextureMap);
if (m_Scene == Scene::Spheres)
{
// Metals
for (int i = 0; i < 8; i++)
{
m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_MetalSphereMaterialInstances[i]);
/*
m_MetalSphereMaterialInstances[i]->Bind();
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
*/
}
// Dielectrics
for (int i = 0; i < 8; i++)
{
m_SphereMesh->Render(deltaTime, glm::mat4(1.0f), m_DielectricSphereMaterialInstances[i]);
/*
m_DielectricSphereMaterialInstances[i]->Bind();
m_SphereMesh->Render(deltaTime, m_SimplePBRShader.get());
*/
}
}
else if (m_Scene == Scene::Model)
{
if (m_Mesh)
{
m_Mesh->Render(deltaTime, scale(mat4(1.0f), vec3(m_MeshScale)), m_MeshMaterial);
}
}
m_GridMaterial->Set("u_MVP", viewProjection * glm::scale(glm::mat4(1.0f), glm::vec3(16.0f)));
m_PlaneMesh->Render(deltaTime, m_GridMaterial);
m_Framebuffer->Unbind();
m_FinalPresentBuffer->Bind();
m_HDRShader->Bind();
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
m_Framebuffer->BindTexture();
/*
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
*/
m_FullscreenQuadVertexArray->Bind();
Renderer::DrawIndexed(m_FullscreenQuadVertexArray->GetIndexBuffer()->GetCount(), false);
m_FinalPresentBuffer->Unbind();
}
}
void EditorLayer::OnImGuiRender()
{
#if ENABLE_DOCKSPACE
static bool p_open = true;
static bool opt_fullscreen = true;
static bool opt_padding = false;
static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None;
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
// because it would be confusing to have two docking targets within each others.
ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
if (opt_fullscreen)
{
const ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->WorkPos);
ImGui::SetNextWindowSize(viewport->WorkSize);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize |
ImGuiWindowFlags_NoMove;
window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
}
else
{
dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode;
}
// When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background
// and handle the pass-thru hole, so we ask Begin() to not render a background.
if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode)
window_flags |= ImGuiWindowFlags_NoBackground;
// Important: note that we proceed even if Begin() returns false (aka window is collapsed).
// This is because we want to keep our DockSpace() active. If a DockSpace() is inactive,
// all active windows docked into it will lose their parent and become undocked.
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
if (!opt_padding)
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("DockSpace Demo", &p_open, window_flags);
if (!opt_padding)
ImGui::PopStyleVar();
if (opt_fullscreen)
ImGui::PopStyleVar(2);
// Submit the DockSpace
// REMINDER: THIS IS A DEMO FOR ADVANCED USAGE OF DockSpace()!
// MOST REGULAR APPLICATIONS WILL SIMPLY WANT TO CALL DockSpaceOverViewport(). READ COMMENTS ABOVE.
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable)
{
ImGuiID dockspace_id = ImGui::GetID("MyDockSpace");
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
}
// Show demo options and help
if (ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Options"))
{
// Disabling fullscreen would allow the window to be moved to the front of other windows,
// which we can't undo at the moment without finer window depth/z control.
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen);
ImGui::MenuItem("Padding", NULL, &opt_padding);
ImGui::Separator();
if (ImGui::MenuItem("Flag: NoDockingOverCentralNode", "",
(dockspace_flags & ImGuiDockNodeFlags_NoDockingOverCentralNode) != 0))
{
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingOverCentralNode;
}
if (ImGui::MenuItem("Flag: NoDockingSplit", "",
(dockspace_flags & ImGuiDockNodeFlags_NoDockingSplit) != 0))
{
dockspace_flags ^= ImGuiDockNodeFlags_NoDockingSplit;
}
if (ImGui::MenuItem("Flag: NoUndocking", "", (dockspace_flags & ImGuiDockNodeFlags_NoUndocking) != 0))
{
dockspace_flags ^= ImGuiDockNodeFlags_NoUndocking;
}
if (ImGui::MenuItem("Flag: NoResize", "", (dockspace_flags & ImGuiDockNodeFlags_NoResize) != 0))
{
dockspace_flags ^= ImGuiDockNodeFlags_NoResize;
}
if (ImGui::MenuItem("Flag: AutoHideTabBar", "",
(dockspace_flags & ImGuiDockNodeFlags_AutoHideTabBar) != 0))
{
dockspace_flags ^= ImGuiDockNodeFlags_AutoHideTabBar;
}
if (ImGui::MenuItem("Flag: PassthruCentralNode", "",
(dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) != 0, opt_fullscreen))
{
dockspace_flags ^= ImGuiDockNodeFlags_PassthruCentralNode;
}
ImGui::Separator();
if (ImGui::MenuItem("Close", NULL, false, p_open != false))
p_open = false;
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Help"))
{
ImGui::TextUnformatted(
"This demo has nothing to do with enabling docking!" "\n"
"This demo only demonstrate the use of ImGui::DockSpace() which allows you to manually\ncreate a docking node _within_ another window."
"\n"
"Most application can simply call ImGui::DockSpaceOverViewport() and be done with it.");
ImGui::Separator();
ImGui::TextUnformatted(
"When docking is enabled, you can ALWAYS dock MOST window into another! Try it now!" "\n"
"- Drag from window title bar or their tab to dock/undock." "\n"
"- Drag from window menu button (upper-left button) to undock an entire node (all windows)." "\n"
"- Hold SHIFT to disable docking (if io.ConfigDockingWithShift == false, default)" "\n"
"- Hold SHIFT to enable docking (if io.ConfigDockingWithShift == true)");
ImGui::Separator();
ImGui::TextUnformatted("More details:");
ImGui::Bullet();
ImGui::SameLine();
ImGui::TextLinkOpenURL("Docking Wiki page", "https://github.com/ocornut/imgui/wiki/Docking");
ImGui::BulletText("Read comments in ShowExampleAppDockSpace()");
ImGui::EndMenu();
}
ImGuiShowHelpMarker(
"You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!"
"\n"
"This demo app has nothing to do with it!" "\n\n"
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to manually create a docking node _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)."
"\n\n"
"ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame."
"\n\n"
"(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace() node, because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
);
ImGui::EndMenuBar();
}
ImGui::End();
#endif
// Editor Panel ------------------------------------------------------------------------------
ImGui::Begin("Model");
ImGui::RadioButton("Spheres", (int*)&m_Scene, (int)Scene::Spheres);
ImGui::SameLine();
ImGui::RadioButton("Model", (int*)&m_Scene, (int)Scene::Model);
ImGui::Begin("Environment");
ImGui::Columns(2);
ImGui::AlignTextToFramePadding();
Property("Light Direction", m_Light.Direction);
Property("Light Radiance", m_Light.Radiance, PropertyFlag::ColorProperty);
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::Text("Mesh");
std::string fullpath = m_Mesh ? m_Mesh->GetFilePath() : "None";
size_t found = fullpath.find_last_of("/\\");
std::string path = found != std::string::npos ? fullpath.substr(found + 1) : fullpath;
ImGui::Text(path.c_str());
ImGui::SameLine();
if (ImGui::Button("...##Mesh"))
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
m_Mesh.reset(new Mesh(filename));
}
}
ImGui::Separator();
// Textures ------------------------------------------------------------------------------
{
// Albedo
if (ImGui::CollapsingHeader("Albedo", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_AlbedoInput.TextureMap
? m_AlbedoInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_AlbedoInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_AlbedoInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_AlbedoInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
m_AlbedoInput.TextureMap.reset(Texture2D::Create(filename, m_AlbedoInput.SRGB));
}
}
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("Use##AlbedoMap", &m_AlbedoInput.UseTexture);
if (ImGui::Checkbox("sRGB##AlbedoMap", &m_AlbedoInput.SRGB))
{
if (m_AlbedoInput.TextureMap)
m_AlbedoInput.TextureMap.reset(
Texture2D::Create(m_AlbedoInput.TextureMap->GetPath(), m_AlbedoInput.SRGB));
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(m_AlbedoInput.Color), ImGuiColorEditFlags_NoInputs);
}
}
{
// Normals
if (ImGui::CollapsingHeader("Normals", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_NormalInput.TextureMap
? m_NormalInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_NormalInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_NormalInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_NormalInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
m_NormalInput.TextureMap.reset(Texture2D::Create(filename));
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##NormalMap", &m_NormalInput.UseTexture);
}
}
{
// Metalness
if (ImGui::CollapsingHeader("Metalness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_MetalnessInput.TextureMap
? m_MetalnessInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_MetalnessInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_MetalnessInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_MetalnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
m_MetalnessInput.TextureMap.reset(Texture2D::Create(filename));
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##MetalnessMap", &m_MetalnessInput.UseTexture);
ImGui::SameLine();
ImGui::SliderFloat("Value##MetalnessInput", &m_MetalnessInput.Value, 0.0f, 1.0f);
}
}
{
// Roughness
if (ImGui::CollapsingHeader("Roughness", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10));
ImGui::Image((ImTextureRef)(m_RoughnessInput.TextureMap
? m_RoughnessInput.TextureMap->GetRendererID()
: m_CheckerboardTex->GetRendererID()), ImVec2(64, 64));
ImGui::PopStyleVar();
if (ImGui::IsItemHovered())
{
if (m_RoughnessInput.TextureMap)
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
ImGui::TextUnformatted(m_RoughnessInput.TextureMap->GetPath().c_str());
ImGui::PopTextWrapPos();
ImGui::Image((ImTextureRef)m_RoughnessInput.TextureMap->GetRendererID(), ImVec2(384, 384));
ImGui::EndTooltip();
}
if (ImGui::IsItemClicked())
{
std::string filename = Application::Get().OpenFile("");
if (filename != "")
m_RoughnessInput.TextureMap.reset(Texture2D::Create(filename));
}
}
ImGui::SameLine();
ImGui::Checkbox("Use##RoughnessMap", &m_RoughnessInput.UseTexture);
ImGui::SameLine();
ImGui::SliderFloat("Value##RoughnessInput", &m_RoughnessInput.Value, 0.0f, 1.0f);
}
}
if (ImGui::TreeNode("Shaders"))
{
auto& shaders = 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::End();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
ImGui::Begin("Viewport");
auto viewportSize = ImGui::GetContentRegionAvail();
m_Framebuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_FinalPresentBuffer->Resize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
m_Camera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f,
10000.0f));
ImGui::Image((ImTextureRef)m_FinalPresentBuffer->GetColorAttachmentRendererID(), viewportSize, {0, 1}, {1, 0});
ImGui::End();
ImGui::PopStyleVar();
ImGui::Begin("Log");
const auto& cameraPos = m_Camera.GetPosition();
ImGui::Text("cameraPos: (%.2f, %.2f, %.2f)", cameraPos.x, cameraPos.y, cameraPos.z);
const auto& Direct = m_Camera.GetForwardDirection();
ImGui::Text("forward Vec: (%.2f, %.2f, %.2f)", Direct.x, Direct.y, Direct.z);
const auto& distance = m_Camera.GetDistance();
ImGui::Text("distance: %.3f", distance);
ImGui::End();
if (m_Mesh)
m_Mesh->OnImGuiRender();
}
void EditorLayer::OnEvent(Event& e)
{
Layer::OnEvent(e);
}
}

View File

@ -5,12 +5,114 @@
#ifndef EDITORLAYER_H
#define EDITORLAYER_H
#include "Prism.h"
namespace Prism
{
class EditorLayer : public Layer
{
public:
EditorLayer();
virtual ~EditorLayer();
virtual void OnAttach() override;
virtual void OnDetach() override;
virtual void OnUpdate(TimeStep deltaTime) override;
virtual void OnImGuiRender() override;
virtual void OnEvent(Event& e) override;
private:
float m_ClearColor[4];
Ref<FrameBuffer> m_Framebuffer, m_FinalPresentBuffer;
/*
Ref<VertexBuffer> m_VertexBuffer;
Ref<IndexBuffer> m_IndexBuffer;
*/
Ref<VertexArray> m_FullscreenQuadVertexArray;
Ref<TextureCube> m_EnvironmentCubeMap, m_EnvironmentIrradiance;
Camera m_Camera;
Ref<Shader> m_QuadShader;
Ref<Shader> m_HDRShader;
Ref<Shader> m_GridShader;
Ref<Mesh> m_Mesh;
Ref<Mesh> m_SphereMesh, m_PlaneMesh;
Ref<Texture2D> m_BRDFLUT;
Ref<MaterialInstance> m_MeshMaterial;
Ref<MaterialInstance> m_GridMaterial;
std::vector<Ref<MaterialInstance>> m_MetalSphereMaterialInstances;
std::vector<Ref<MaterialInstance>> m_DielectricSphereMaterialInstances;
float m_GridScale = 16.025f, m_GridSize = 0.025f;
float m_MeshScale = 1.0f;
Ref<Shader> m_Shader;
Ref<Shader> m_PBRShader;
class EditorLayer {
struct AlbedoInput
{
glm::vec3 Color = { 0.972f, 0.96f, 0.915f }; // Silver, from https://docs.unrealengine.com/en-us/Engine/Rendering/Materials/PhysicallyBased
Ref<Texture2D> TextureMap;
bool SRGB = true;
bool UseTexture = false;
};
AlbedoInput m_AlbedoInput;
struct NormalInput
{
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
NormalInput m_NormalInput;
struct MetalnessInput
{
float Value = 1.0f;
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
MetalnessInput m_MetalnessInput;
struct RoughnessInput
{
float Value = 0.5f;
Ref<Texture2D> TextureMap;
bool UseTexture = false;
};
RoughnessInput m_RoughnessInput;
struct Light
{
glm::vec3 Direction;
glm::vec3 Radiance;
};
Light m_Light;
float m_LightMultiplier = 0.3f;
// PBR params
float m_Exposure = 1.0f;
bool m_RadiancePrefilter = false;
float m_EnvMapRotation = 0.0f;
enum class Scene : uint32_t
{
Spheres = 0, Model = 1
};
Scene m_Scene;
// Editor resources
Ref<Texture2D> m_CheckerboardTex;
};
}
#endif //EDITORLAYER_H

View File

@ -7,13 +7,23 @@
#include "Prism/Core/Application.h"
#include "Prism/Core/Events/ApplicationEvent.h"
#include "Prism/Core/TimeStep.h"
#include "Prism/Core/Events/Event.h"
#include "Prism/Core/Events/ApplicationEvent.h"
#include "Prism/Core/Events/KeyEvent.h"
#include "Prism/Core/Events/MouseEvent.h"
// ImGui
#include "imgui.h"
#include "Prism/Renderer/Buffer.h"
#include "Prism/Renderer/Renderer.h"
#include "Prism/Renderer/Shader.h"
#include "Prism/Renderer/Texture.h"
#include "Prism/Renderer/FrameBuffer.h"
#include "Prism/Renderer/Shader.h"
#include "Prism/Renderer/Mesh.h"
#include "Prism/Renderer/Camera.h"
#include "Prism/Renderer/Material.h"
#endif //PRISM_H

View File

@ -23,13 +23,13 @@ namespace Prism
#endif
// Application* Application::s_Instance = nullptr;
Application* Application::s_Instance = nullptr;
Application::Application()
Application::Application(const ApplicationProps& props)
{
s_Instance = this;
m_Window = std::unique_ptr<Window>(Window::Create());
m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height}));
m_Window->SetEventCallback(BIND_EVENT_FN(OnEvent));
m_ImGuiLayer = new ImGuiLayer("ImGui Layer");
@ -162,6 +162,11 @@ namespace Prism
}
Application& Application::Get()
{
return *s_Instance;
}
void Application::PushLayer(Layer* layer)
{
m_LayerStack.PushLayer(layer);

View File

@ -13,10 +13,16 @@
namespace Prism
{
struct ApplicationProps
{
std::string Name;
uint32_t Width, Height;
};
class PRISM_API Application
{
public:
Application();
Application(const ApplicationProps& props = { "Prism Engine", 1920, 1080});
virtual ~Application();
void Run();
@ -33,7 +39,7 @@ namespace Prism
inline Window& GetWindow() { return *m_Window; }
inline static Application& Get() { return *s_Instance; }
static Application& Get();
void PushLayer(Layer* layer);
void PushOverlay(Layer* layer);
@ -54,7 +60,7 @@ namespace Prism
LayerStack m_LayerStack;
ImGuiLayer* m_ImGuiLayer;
static inline Application* s_Instance = nullptr;
static Application* s_Instance;
};

View File

@ -36,6 +36,14 @@ namespace Prism
Size = size;
}
static Buffer Copy(void* data, uint32_t size)
{
Buffer buffer;
buffer.Allocate(size);
memcpy(buffer.Data, data, size);
return buffer;
}
void ZeroInitialize() const
{
if (Data)

View File

@ -43,7 +43,7 @@ namespace Prism
virtual void SetVSync(bool enable) = 0;
virtual bool const IsVSync() const = 0;
static Window* Create(const WindowProps& props = WindowProps());
static Window* Create(const WindowProps& props);
virtual void* GetNativeWindow() const = 0;
};

View File

@ -9,17 +9,41 @@
namespace Prism
{
static GLenum OpenGLUsage(VertexBufferUsage usage)
{
switch (usage)
{
case VertexBufferUsage::Static: return GL_STATIC_DRAW;
case VertexBufferUsage::Dynamic: return GL_DYNAMIC_DRAW;
}
PM_CORE_ASSERT(false, "Unknown vertex buffer usage");
return 0;
}
// ******************************************
// Vertex
// ******************************************
OpenGLVertexBuffer::OpenGLVertexBuffer(unsigned int size)
: m_RendererID(0), m_Size(size)
OpenGLVertexBuffer::OpenGLVertexBuffer(void* data, const uint32_t size, const VertexBufferUsage usage)
: m_Size(size), m_Usage(usage)
{
m_LocalData = Buffer::Copy(data, size);
PM_RENDER_S({
glGenBuffers(1, &self->m_RendererID);
glCreateBuffers(1, &self->m_RendererID);
glNamedBufferData(self->m_RendererID, self->m_Size, self->m_LocalData.Data, OpenGLUsage(self->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));
});
}
OpenGLVertexBuffer::~OpenGLVertexBuffer()
{
PM_RENDER_S({
@ -27,12 +51,12 @@ namespace Prism
});
}
void OpenGLVertexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
void OpenGLVertexBuffer::SetData(void* buffer, uint32_t size, uint32_t offset)
{
m_LocalData = Buffer::Copy(buffer, size);
m_Size = size;
PM_RENDER_S3(buffer, size, offset, {
glBindBuffer(GL_ARRAY_BUFFER, self->m_RendererID);
glBufferData(GL_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
PM_RENDER_S1(offset, {
glNamedBufferSubData(self->m_RendererID, offset, self->m_Size, self->m_LocalData.Data);
});
}
@ -52,11 +76,14 @@ namespace Prism
// ******************************************
// IndexBuffer
// ******************************************
OpenGLIndexBuffer::OpenGLIndexBuffer(unsigned int size)
: m_RendererID(0), m_Size(size)
OpenGLIndexBuffer::OpenGLIndexBuffer(void* data, const uint32_t size)
: m_Size(size)
{
m_LocalData = Buffer::Copy(data, size);
PM_RENDER_S({
glGenBuffers(1, &self->m_RendererID);
glCreateBuffers(1, &self->m_RendererID);
glNamedBufferData(self->m_RendererID, self->m_Size, self->m_LocalData.Data, GL_STATIC_DRAW);
});
}
@ -67,12 +94,12 @@ namespace Prism
});
}
void OpenGLIndexBuffer::SetData(void* buffer, unsigned int size, unsigned int offset)
void OpenGLIndexBuffer::SetData(void* data, uint32_t size, uint32_t offset)
{
m_LocalData = Buffer::Copy(data, size);
m_Size = size;
PM_RENDER_S3(buffer, size, offset, {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self->m_RendererID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, buffer, GL_STATIC_DRAW);
PM_RENDER_S1(offset, {
glNamedBufferSubData(self->m_RendererID, offset, self->m_Size, self->m_LocalData.Data);
});
}

View File

@ -6,6 +6,7 @@
#define OPENGLBUFFER_H
#include "glad/glad.h"
#include "Prism/Core/Buffer.h"
#include "Prism/Renderer/Buffer.h"
namespace Prism
@ -17,17 +18,26 @@ namespace Prism
class OpenGLVertexBuffer : public VertexBuffer
{
public:
OpenGLVertexBuffer(unsigned int size);
OpenGLVertexBuffer(void* data, uint32_t size, VertexBufferUsage usage = VertexBufferUsage::Static);
OpenGLVertexBuffer(uint32_t size, VertexBufferUsage usage = VertexBufferUsage::Dynamic);
virtual ~OpenGLVertexBuffer();
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0);
virtual void SetData(void* buffer, uint32_t size, uint32_t offset = 0);
virtual void Bind() const;
virtual unsigned int GetSize() const { return m_Size; }
virtual const BufferLayout& GetLayout() const override { return m_Layout; }
virtual void SetLayout(const BufferLayout& layout) override { m_Layout = layout; }
virtual uint32_t GetSize() const { return m_Size; }
virtual RendererID GetRendererID() const { return m_RendererID; }
private:
RendererID m_RendererID;
unsigned int m_Size;
RendererID m_RendererID = 0;
uint32_t m_Size;
VertexBufferUsage m_Usage;
BufferLayout m_Layout;
Buffer m_LocalData;
};
// ******************************************
@ -37,19 +47,20 @@ namespace Prism
class OpenGLIndexBuffer : public IndexBuffer
{
public:
OpenGLIndexBuffer(unsigned int size);
OpenGLIndexBuffer(void* data, uint32_t size);
virtual ~OpenGLIndexBuffer();
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0);
virtual void SetData(void* data, uint32_t size, uint32_t offset = 0);
virtual void Bind() const;
virtual uint32_t GetCount() const { return m_Size / sizeof(uint32_t); }
virtual unsigned int GetSize() const { return m_Size; }
virtual uint32_t GetSize() const { return m_Size; }
virtual RendererID GetRendererID() const { return m_RendererID; }
private:
RendererID m_RendererID;
unsigned int m_Size;
RendererID m_RendererID = 0;
uint32_t m_Size;
Buffer m_LocalData;
};
}

View File

@ -21,7 +21,7 @@ namespace Prism
{
PM_CORE_TRACE("{0}", message);
}
PM_CORE_ASSERT(0);
}
void RendererAPI::Init()

View File

@ -22,9 +22,20 @@ namespace Prism
}
Ref<OpenGLShader> OpenGLShader::CreateFromString(const std::string& source)
{
Ref<OpenGLShader> shader = std::make_shared<OpenGLShader>();
shader->Load(source);
return shader;
}
void OpenGLShader::Reload()
{
const std::string source = ReadShaderFromFile(m_AssetPath);
Load(source);
}
void OpenGLShader::Load(const std::string& source)
{
m_ShaderSource = PreProcess(source);
Parse();
@ -142,6 +153,7 @@ namespace Prism
return m_Name;
}
std::string OpenGLShader::ReadShaderFromFile(const std::string& filepath) const
{
std::string result;

View File

@ -15,7 +15,9 @@ namespace Prism
class OpenGLShader : public Shader
{
public:
OpenGLShader() = default;
OpenGLShader(const std::string& filepath);
static Ref<OpenGLShader> CreateFromString(const std::string& source);
virtual void Reload();
virtual void Bind() override;
@ -35,6 +37,8 @@ namespace Prism
private:
void Load(const std::string& source);
std::string ReadShaderFromFile(const std::string& filepath) const;
std::unordered_map<GLenum, std::string> PreProcess(const std::string& source);
void Parse();

View File

@ -3,3 +3,101 @@
//
#include "OpenGLVertexArray.h"
#include "glad/glad.h"
#include "Prism/Renderer/Renderer.h"
namespace Prism
{
static GLenum ShaderDataTypeToOpenGLBaseType(ShaderDataType type)
{
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;
}
PM_CORE_ASSERT(false, "Unknown ShaderDataType!");
return 0;
}
OpenGLVertexArray::OpenGLVertexArray()
{
PM_RENDER_S({
glCreateVertexArrays(1, &self->m_RendererID);
});
}
OpenGLVertexArray::~OpenGLVertexArray()
{
PM_RENDER_S({
glDeleteVertexArrays(1, &self->m_RendererID);
});
}
void OpenGLVertexArray::Bind() const
{
PM_RENDER_S({
glBindVertexArray(self->m_RendererID);
});
}
void OpenGLVertexArray::Unbind() const
{
PM_RENDER_S({
glBindVertexArray(0);
});
}
void OpenGLVertexArray::AddVertexBuffer(const Ref<VertexBuffer>& vertexBuffer)
{
PM_CORE_ASSERT(vertexBuffer->GetLayout().GetElements().size(), "Vertex Buffer has no layout!");
Bind();
vertexBuffer->Bind();
PM_RENDER_S1(vertexBuffer, {
const auto& layout = vertexBuffer->GetLayout();
for (const auto& element : layout)
{
auto glBaseType = ShaderDataTypeToOpenGLBaseType(element.Type);
glEnableVertexAttribArray(self->m_VertexBufferIndex);
if (glBaseType == GL_INT)
{
glVertexAttribIPointer(self->m_VertexBufferIndex,
element.GetComponentCount(),
glBaseType,
layout.GetStride(),
(const void*)(intptr_t)element.Offset);
}
else
{
glVertexAttribPointer(self->m_VertexBufferIndex,
element.GetComponentCount(),
glBaseType,
element.Normalized ? GL_TRUE : GL_FALSE,
layout.GetStride(),
(const void*)(intptr_t)element.Offset);
}
self->m_VertexBufferIndex++;
}
});
m_VertexBuffers.push_back(vertexBuffer);
}
void OpenGLVertexArray::SetIndexBuffer(const Ref<IndexBuffer>& indexBuffer)
{
Bind();
indexBuffer->Bind();
m_IndexBuffer = indexBuffer;
}
}

View File

@ -5,12 +5,31 @@
#ifndef OPENGLVERTEXARRAY_H
#define OPENGLVERTEXARRAY_H
#include "Prism/Renderer/VertexArray.h"
namespace Prism
{
class OpenGLVertexArray : public VertexArray
{
public:
OpenGLVertexArray();
virtual ~OpenGLVertexArray();
class OpenGLVertexArray {
virtual void Bind() const override;
virtual void Unbind() const override;
};
virtual void AddVertexBuffer(const Ref<VertexBuffer>& vertexBuffer) override;
virtual void SetIndexBuffer(const Ref<IndexBuffer>& indexBuffer) override;
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const { return m_VertexBuffers; }
virtual const Ref<IndexBuffer>& GetIndexBuffer() const { return m_IndexBuffer; }
private:
RendererID m_RendererID = 0;
uint32_t m_VertexBufferIndex = 0;
std::vector<std::shared_ptr<VertexBuffer>> m_VertexBuffers;
std::shared_ptr<IndexBuffer> m_IndexBuffer;
};
}
#endif //OPENGLVERTEXARRAY_H

View File

@ -62,7 +62,7 @@ namespace Prism
{
int x, y;
glfwGetWindowPos(m_Window, &x, &y);
return { x, y };
return { (float)x, (float)y };
}
void WindowsWindow::Init(const WindowProps& props)

View File

@ -8,24 +8,39 @@
namespace Prism
{
VertexBuffer* VertexBuffer::Create(unsigned int size)
Ref<VertexBuffer> VertexBuffer::Create(void* data, uint32_t size, VertexBufferUsage usage)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return new OpenGLVertexBuffer(size);
case RendererAPIType::OpenGL: return CreateRef<OpenGLVertexBuffer>(data, size, usage);
}
PM_CORE_ASSERT(false, "Unknown RendererAPI");
return nullptr;
}
Ref<VertexBuffer> VertexBuffer::Create(uint32_t size, VertexBufferUsage usage)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return CreateRef<OpenGLVertexBuffer>(size, usage);
}
PM_CORE_ASSERT(false, "Unknown RendererAPI");
return nullptr;
}
IndexBuffer* IndexBuffer::Create(const unsigned int size)
Ref<IndexBuffer> IndexBuffer::Create(void* data, uint32_t size)
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: return new OpenGLIndexBuffer(size);
case RendererAPIType::OpenGL: return CreateRef<OpenGLIndexBuffer>(data, size);
}
PM_CORE_ASSERT(false, "Unknown RendererAPI");
return nullptr;
}
}

View File

@ -9,18 +9,130 @@
namespace Prism
{
enum class ShaderDataType
{
None = 0, Float, Float2, Float3, Float4, Mat3, Mat4, Int, Int2, Int3, Int4, Bool
};
static uint32_t ShaderDataTypeSize(ShaderDataType type)
{
switch (type)
{
case ShaderDataType::Float: return 4;
case ShaderDataType::Float2: return 4 * 2;
case ShaderDataType::Float3: return 4 * 3;
case ShaderDataType::Float4: return 4 * 4;
case ShaderDataType::Mat3: return 4 * 3 * 3;
case ShaderDataType::Mat4: return 4 * 4 * 4;
case ShaderDataType::Int: return 4;
case ShaderDataType::Int2: return 4 * 2;
case ShaderDataType::Int3: return 4 * 3;
case ShaderDataType::Int4: return 4 * 4;
case ShaderDataType::Bool: return 1;
}
PM_CORE_ASSERT(false, "Unknown ShaderDataType!");
return 0;
}
struct BufferElement
{
std::string Name;
ShaderDataType Type;
uint32_t Size;
uint32_t Offset;
bool Normalized;
BufferElement() = default;
BufferElement(ShaderDataType type, const std::string& name, bool normalized = false)
: Name(name), Type(type), Size(ShaderDataTypeSize(type)), Offset(0), Normalized(normalized)
{
}
uint32_t GetComponentCount() const
{
switch (Type)
{
case ShaderDataType::Float: return 1;
case ShaderDataType::Float2: return 2;
case ShaderDataType::Float3: return 3;
case ShaderDataType::Float4: return 4;
case ShaderDataType::Mat3: return 3 * 3;
case ShaderDataType::Mat4: return 4 * 4;
case ShaderDataType::Int: return 1;
case ShaderDataType::Int2: return 2;
case ShaderDataType::Int3: return 3;
case ShaderDataType::Int4: return 4;
case ShaderDataType::Bool: return 1;
}
PM_CORE_ASSERT(false, "Unknown ShaderDataType!");
return 0;
}
};
class BufferLayout
{
public:
BufferLayout() {}
BufferLayout(const std::initializer_list<BufferElement>& elements)
: m_Elements(elements)
{
CalculateOffsetsAndStride();
}
inline uint32_t GetStride() const { return m_Stride; }
inline const std::vector<BufferElement>& GetElements() const { return m_Elements; }
std::vector<BufferElement>::iterator begin() { return m_Elements.begin(); }
std::vector<BufferElement>::iterator end() { return m_Elements.end(); }
std::vector<BufferElement>::const_iterator begin() const { return m_Elements.begin(); }
std::vector<BufferElement>::const_iterator end() const { return m_Elements.end(); }
private:
void CalculateOffsetsAndStride()
{
uint32_t offset = 0;
m_Stride = 0;
for (auto& element : m_Elements)
{
element.Offset = offset;
offset += element.Size;
m_Stride += element.Size;
}
}
private:
std::vector<BufferElement> m_Elements;
uint32_t m_Stride = 0;
};
enum class VertexBufferUsage
{
None = 0, Static = 1, Dynamic = 2
};
class PRISM_API VertexBuffer
{
public:
virtual ~VertexBuffer() {}
static Ref<VertexBuffer> Create(void* data, uint32_t size, VertexBufferUsage usage = VertexBufferUsage::Static);
static Ref<VertexBuffer> Create(uint32_t size, VertexBufferUsage usage = VertexBufferUsage::Dynamic);
virtual void SetData(void* buffer, uint32_t size, uint32_t offset = 0) = 0;
virtual void Bind() const = 0;
virtual const BufferLayout& GetLayout() const = 0;
virtual void SetLayout(const BufferLayout& layout) = 0;
virtual unsigned int GetSize() const = 0;
virtual RendererID GetRendererID() const = 0;
static VertexBuffer* Create(unsigned int size = 0);
};
@ -29,14 +141,15 @@ namespace Prism
public:
virtual ~IndexBuffer() {}
virtual void SetData(void* buffer, unsigned int size, unsigned int offset = 0) = 0;
static Ref<IndexBuffer> Create(void* data, uint32_t size = 0);
virtual void SetData(void* buffer, uint32_t size, uint32_t offset = 0) = 0;
virtual void Bind() const = 0;
virtual uint32_t GetCount() const = 0;
virtual unsigned int GetSize() const = 0;
virtual RendererID GetRendererID() const = 0;
static IndexBuffer* Create(unsigned int size = 0);
};
}

View File

@ -223,6 +223,35 @@ namespace Prism
}
}
m_VertexArray = VertexArray::Create();
if (m_IsAnimated)
{
auto vb = VertexBuffer::Create(m_AnimatedVertices.data(), (uint32_t)m_AnimatedVertices.size() * sizeof(AnimatedVertex));
vb->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float3, "a_Normal" },
{ ShaderDataType::Float3, "a_Tangent" },
{ ShaderDataType::Float3, "a_Binormal" },
{ ShaderDataType::Float2, "a_TexCoord" },
{ ShaderDataType::Int4, "a_BoneIDs" },
{ ShaderDataType::Float4, "a_BoneWeights" },
});
m_VertexArray->AddVertexBuffer(vb);
}else
{
auto vb = VertexBuffer::Create(m_StaticVertices.data(), (uint32_t)m_StaticVertices.size() * sizeof(Vertex));
vb->SetLayout({
{ ShaderDataType::Float3, "a_Position" },
{ ShaderDataType::Float3, "a_Normal" },
{ ShaderDataType::Float3, "a_Tangent" },
{ ShaderDataType::Float3, "a_Binormal" },
{ ShaderDataType::Float2, "a_TexCoord" },
});
m_VertexArray->AddVertexBuffer(vb);
}
/*
m_VertexBuffer.reset(VertexBuffer::Create());
if (m_IsAnimated)
m_VertexBuffer->SetData(m_AnimatedVertices.data(), m_AnimatedVertices.size() * sizeof(AnimatedVertex));
@ -231,7 +260,10 @@ namespace Prism
m_IndexBuffer.reset(IndexBuffer::Create());
m_IndexBuffer->SetData(m_Indices.data(), m_Indices.size() * sizeof(Index));
*/
auto ib = IndexBuffer::Create(m_Indices.data(), (uint32_t)m_Indices.size() * sizeof(Index));
m_VertexArray->SetIndexBuffer(ib);
m_Scene = scene;
}
@ -264,13 +296,33 @@ namespace Prism
materialInstance->Bind();
// TODO: Sort this out
/*
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
*/
m_VertexArray->Bind();
bool materialOverride = !!materialInstance;
// TODO: replace with render API calls
PM_RENDER_S2(transform, materialOverride,{
for (Submesh& submesh : self->m_Submeshes)
{
if (self->m_IsAnimated)
{
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]);
}
}
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);
}
/*
for (const Submesh& submesh : self->m_Submeshes)
{
if (self->m_IsAnimated)
@ -295,6 +347,7 @@ namespace Prism
glEnableVertexAttribArray(6);
glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, sizeof(AnimatedVertex), (const void*)offsetof(AnimatedVertex, Weights));
#1#
if (self->m_Scene->mAnimations)
{
@ -326,6 +379,7 @@ 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);
}
*/
});
}

View File

@ -10,6 +10,7 @@
#include "Buffer.h"
#include "Material.h"
#include "Shader.h"
#include "VertexArray.h"
#include "Prism/Core/TimeStep.h"
struct aiNode;
@ -125,8 +126,12 @@ namespace Prism
uint32_t m_BoneCount = 0;
std::vector<BoneInfo> m_BoneInfo;
Ref<VertexArray> m_VertexArray;
/*
std::unique_ptr<VertexBuffer> m_VertexBuffer;
std::unique_ptr<IndexBuffer> m_IndexBuffer;
*/
std::vector<Vertex> m_StaticVertices;

View File

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

View File

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

View File

@ -26,6 +26,21 @@ namespace Prism
return result;
}
Ref<Shader> Shader::CreateFromSring(const std::string& source)
{
Ref<Shader> result = nullptr;
switch (RendererAPI::Current())
{
case RendererAPIType::None: return nullptr;
case RendererAPIType::OpenGL: result = OpenGLShader::CreateFromSring(source);
}
s_AllShaders.push_back(result);
return result;
}
std::vector<Ref<Shader>>& Shader::GetAllShaders()
{
return s_AllShaders;

View File

@ -99,6 +99,8 @@ namespace Prism
public:
using ShaderReloadedCallback = std::function<void()>;
static Ref<Shader> Create(const std::string& filepath);
static Ref<Shader> CreateFromSring(const std::string& source);
virtual void Reload() = 0;
virtual void Bind() = 0;
@ -122,7 +124,6 @@ namespace Prism
virtual void AddShaderReloadedCallback(const ShaderReloadedCallback& callback) = 0;
static Ref<Shader> Create(const std::string& filepath);
static std::vector<Ref<Shader>>& GetAllShaders();
private:

View File

@ -3,3 +3,21 @@
//
#include "VertexArray.h"
#include "Prism/Platform/OpenGL/OpenGLVertexArray.h"
namespace Prism
{
Ref<VertexArray> VertexArray::Create()
{
switch (RendererAPI::Current())
{
case RendererAPIType::None: PM_CORE_ASSERT(false, "RendererAPI::None is currently not supported!");
return nullptr;
case RendererAPIType::OpenGL: return std::make_shared<OpenGLVertexArray>();
}
PM_CORE_ASSERT(false, "Unknown RendererAPI");
return nullptr;
}
}

View File

@ -4,13 +4,29 @@
#ifndef VERTEXARRAY_H
#define VERTEXARRAY_H
#include "Buffer.h"
namespace Prism
{
class PRISM_API VertexArray
{
public:
virtual ~VertexArray() {}
class VertexArray {
static Ref<VertexArray> Create();
};
virtual void Bind() const = 0;
virtual void Unbind() const = 0;
virtual void AddVertexBuffer(const Ref<VertexBuffer>& vertexBuffer) = 0;
virtual void SetIndexBuffer(const Ref<IndexBuffer>& indexBuffer) = 0;
virtual const std::vector<Ref<VertexBuffer>>& GetVertexBuffers() const = 0;
virtual const Ref<IndexBuffer>& GetIndexBuffer() const = 0;
};
}
#endif //VERTEXARRAY_H

View File

@ -2,8 +2,6 @@ project(Sandbox)
file(GLOB_RECURSE SRC_SOURCE ./**.cpp)
file(GLOB ASSETS assets)
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR}/bin)
add_executable(${PROJECT_NAME} ${SRC_SOURCE})

View File

@ -4,12 +4,8 @@
#include "TestLayer.h"
#include <memory>
#include "imgui.h"
#include "glm/gtc/type_ptr.hpp"
#include "Prism/Renderer/Renderer.h"
#include "Prism/Renderer/Shader.h"
#include "Prism.h"
static void EnableDockSpace(const bool enable)
@ -162,15 +158,20 @@ void TestLayer::OnAttach()
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
static unsigned int QuadIndices[] = {
static uint32_t QuadIndices[] = {
0, 1, 2, 2, 3, 0
};
m_VertexBuffer = std::unique_ptr<Prism::VertexBuffer>(Prism::VertexBuffer::Create());
m_VertexBuffer->SetData(QuadVertex, sizeof(QuadVertex));
m_VertexArray = Prism::VertexArray::Create();
auto quadVB = Prism::VertexBuffer::Create(QuadVertex, sizeof(QuadVertex) * sizeof(float));
quadVB->SetLayout({
{ Prism::ShaderDataType::Float3, "a_Position" },
{ Prism::ShaderDataType::Float2, "a_TexCoord" }
});
m_VertexArray->AddVertexBuffer(quadVB);
m_IndexBuffer = std::unique_ptr<Prism::IndexBuffer>(Prism::IndexBuffer::Create());
m_IndexBuffer->SetData(QuadIndices, sizeof(QuadIndices));
auto ib = Prism::IndexBuffer::Create(QuadIndices, 6 * sizeof(uint32_t));
m_VertexArray->SetIndexBuffer(ib);
m_SkyBoxTextureCube.reset(Prism::TextureCube::Create("assets/textures/environments/Arches_E_PineTree_Radiance.tga"));
@ -178,7 +179,8 @@ void TestLayer::OnAttach()
m_Shader = Prism::Shader::Create("assets/shaders/demo.glsl");
m_HDRShader = Prism::Shader::Create("assets/shaders/hdr.glsl");
m_Mesh = std::make_unique<Prism::Mesh>("assets/meshes/cerberus.fbx");
// m_Mesh = std::make_unique<Prism::Mesh>("assets/meshes/cerberus.fbx");
// m_MeshMaterial = Prism::CreateRef<Prism::MaterialInstance>(m_Mesh->GetMaterial());
}
void TestLayer::OnDetach()
@ -194,38 +196,22 @@ void TestLayer::OnUpdate(Prism::TimeStep deltaTime)
m_FrameBuffer->Bind();
Prism::Renderer::Clear(m_clearColor[0], m_clearColor[1], m_clearColor[2], m_clearColor[3]);
Prism::UniformBufferDeclaration<sizeof(glm::mat4), 1> skyboxShaderUB;
skyboxShaderUB.Push("u_InverseVP", inverse(viewProjection));
m_SkyboxShader->UploadUniformBuffer(skyboxShaderUB);
// SkyBox
m_SkyboxShader->Bind();
m_SkyboxShader->SetMat4("u_InverseVP", inverse(viewProjection));
m_SkyBoxTextureCube->Bind(0);
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
Prism::Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
m_VertexArray->Bind();
Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false);
Prism::UniformBufferDeclaration<sizeof(glm::vec4) + sizeof(glm::mat4), 2> uniformbuffer;
uniformbuffer.Push("u_Color", m_TriangleColor);
uniformbuffer.Push("u_MVP", viewProjection);
m_Shader->UploadUniformBuffer(uniformbuffer);
m_Shader->Bind();
// m_Mesh->Render(deltaTime, m_Shader);
// m_VertexBuffer->Bind();
// m_IndexBuffer->Bind();
// m_Mesh->Render();
// Prism::Renderer::DrawIndexed(3, false);
m_FrameBuffer->Unbind();
// HDR
m_FinalPresentBuffer->Bind();
m_HDRShader->Bind();
m_HDRShader->SetFloat("u_Exposure", m_Exposure);
m_FrameBuffer->BindTexture();
m_VertexBuffer->Bind();
m_IndexBuffer->Bind();
Prism::Renderer::DrawIndexed(m_IndexBuffer->GetCount(), false);
Prism::Renderer::DrawIndexed(m_VertexArray->GetIndexBuffer()->GetCount(), false);
m_FinalPresentBuffer->Unbind();
}

View File

@ -29,16 +29,15 @@ private:
glm::vec4 m_TriangleColor = glm::vec4(1.0f);
Prism::Ref<Prism::FrameBuffer> m_FrameBuffer, m_FinalPresentBuffer;
Prism::Ref<Prism::VertexBuffer> m_VertexBuffer;
Prism::Ref<Prism::IndexBuffer> m_IndexBuffer;
Prism::Ref<Prism::TextureCube> m_SkyBoxTextureCube;
Prism::Ref<Prism::VertexArray> m_VertexArray;
Prism::Ref<Prism::Shader> m_SkyboxShader;
Prism::Ref<Prism::Shader> m_Shader;
Prism::Ref<Prism::Shader> m_HDRShader;
Prism::Ref<Prism::Mesh> m_Mesh;
Prism::Ref<Prism::MaterialInstance> m_MeshMaterial;
Prism::Camera m_Camera;

View File

@ -6,7 +6,6 @@
#include "Prism.h"
#include "Prism/Core/EntryPoint.h"
#include "Layer/DemoLayer.h"
#include "Layer/TestLayer.h"
class Sandbox : public Prism::Application
@ -18,8 +17,8 @@ public:
virtual void OnInit() override
{
// PushLayer(new TestLayer());
PushLayer(new DemoLayer());
PushLayer(new TestLayer());
// PushLayer(new DemoLayer());
}
};