Updated to use Phong-Bunn Lighting
This commit is contained in:
parent
939941b8f8
commit
20dab3b4a7
@ -14,7 +14,7 @@
|
|||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <yaml-cpp/yaml.h>
|
#include <yaml-cpp/yaml.h>
|
||||||
#include "../Engine/Components/Component.h" // For interface base
|
#include "../Engine/Components/Component.h" // For interface base
|
||||||
|
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
@ -23,16 +23,19 @@ GLuint g_LightIconTex = 0;
|
|||||||
ImTextureID g_LightIconImTex = 0;
|
ImTextureID g_LightIconImTex = 0;
|
||||||
|
|
||||||
// Helper function to load a texture.
|
// Helper function to load a texture.
|
||||||
bool LoadIconTexture(const char* filepath, GLuint &texOut, ImTextureID &imTexOut) {
|
bool LoadIconTexture(const char *filepath, GLuint &texOut, ImTextureID &imTexOut)
|
||||||
|
{
|
||||||
int w, h, channels;
|
int w, h, channels;
|
||||||
unsigned char* data = stbi_load(filepath, &w, &h, &channels, 0);
|
unsigned char *data = stbi_load(filepath, &w, &h, &channels, 0);
|
||||||
if (!data) {
|
if (!data)
|
||||||
|
{
|
||||||
printf("Failed to load icon texture: %s\n", filepath);
|
printf("Failed to load icon texture: %s\n", filepath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Overwrite loaded data with white pixels (all channels set to 255)
|
// Overwrite loaded data with white pixels (all channels set to 255)
|
||||||
int total = w * h * channels;
|
int total = w * h * channels;
|
||||||
for (int i = 0; i < total; i++) {
|
for (int i = 0; i < total; i++)
|
||||||
|
{
|
||||||
data[i] = 255;
|
data[i] = 255;
|
||||||
}
|
}
|
||||||
glGenTextures(1, &texOut);
|
glGenTextures(1, &texOut);
|
||||||
@ -50,7 +53,8 @@ bool LoadIconTexture(const char* filepath, GLuint &texOut, ImTextureID &imTexOut
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Editor camera.
|
// Editor camera.
|
||||||
struct EditorCamera {
|
struct EditorCamera
|
||||||
|
{
|
||||||
glm::vec3 position = glm::vec3(0.0f, 0.0f, 8.0f);
|
glm::vec3 position = glm::vec3(0.0f, 0.0f, 8.0f);
|
||||||
float yaw = -90.0f;
|
float yaw = -90.0f;
|
||||||
float pitch = 0.0f;
|
float pitch = 0.0f;
|
||||||
@ -62,13 +66,14 @@ struct EditorCamera {
|
|||||||
|
|
||||||
EditorCamera editorCamera;
|
EditorCamera editorCamera;
|
||||||
|
|
||||||
void ProcessEditorCamera(GLFWwindow* window, float deltaTime) {
|
void ProcessEditorCamera(GLFWwindow *window, float deltaTime)
|
||||||
|
{
|
||||||
glm::vec3 front;
|
glm::vec3 front;
|
||||||
front.x = cos(glm::radians(editorCamera.yaw)) * cos(glm::radians(editorCamera.pitch));
|
front.x = cos(glm::radians(editorCamera.yaw)) * cos(glm::radians(editorCamera.pitch));
|
||||||
front.y = sin(glm::radians(editorCamera.pitch));
|
front.y = sin(glm::radians(editorCamera.pitch));
|
||||||
front.z = sin(glm::radians(editorCamera.yaw)) * cos(glm::radians(editorCamera.pitch));
|
front.z = sin(glm::radians(editorCamera.yaw)) * cos(glm::radians(editorCamera.pitch));
|
||||||
front = glm::normalize(front);
|
front = glm::normalize(front);
|
||||||
glm::vec3 right = glm::normalize(glm::cross(front, glm::vec3(0,1,0)));
|
glm::vec3 right = glm::normalize(glm::cross(front, glm::vec3(0, 1, 0)));
|
||||||
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
|
||||||
editorCamera.position += front * editorCamera.speed * deltaTime;
|
editorCamera.position += front * editorCamera.speed * deltaTime;
|
||||||
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
|
||||||
@ -78,25 +83,35 @@ void ProcessEditorCamera(GLFWwindow* window, float deltaTime) {
|
|||||||
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
|
||||||
editorCamera.position += right * editorCamera.speed * deltaTime;
|
editorCamera.position += right * editorCamera.speed * deltaTime;
|
||||||
static double lastX = 0, lastY = 0;
|
static double lastX = 0, lastY = 0;
|
||||||
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
|
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
|
||||||
|
{
|
||||||
double xpos, ypos;
|
double xpos, ypos;
|
||||||
glfwGetCursorPos(window, &xpos, &ypos);
|
glfwGetCursorPos(window, &xpos, &ypos);
|
||||||
if (lastX == 0 && lastY == 0) { lastX = xpos; lastY = ypos; }
|
if (lastX == 0 && lastY == 0)
|
||||||
|
{
|
||||||
|
lastX = xpos;
|
||||||
|
lastY = ypos;
|
||||||
|
}
|
||||||
float offsetX = (float)(xpos - lastX);
|
float offsetX = (float)(xpos - lastX);
|
||||||
float offsetY = (float)(lastY - ypos);
|
float offsetY = (float)(lastY - ypos);
|
||||||
lastX = xpos;
|
lastX = xpos;
|
||||||
lastY = ypos;
|
lastY = ypos;
|
||||||
editorCamera.yaw += offsetX * editorCamera.sensitivity;
|
editorCamera.yaw += offsetX * editorCamera.sensitivity;
|
||||||
editorCamera.pitch += offsetY * editorCamera.sensitivity;
|
editorCamera.pitch += offsetY * editorCamera.sensitivity;
|
||||||
if (editorCamera.pitch > 89.0f) editorCamera.pitch = 89.0f;
|
if (editorCamera.pitch > 89.0f)
|
||||||
if (editorCamera.pitch < -89.0f) editorCamera.pitch = -89.0f;
|
editorCamera.pitch = 89.0f;
|
||||||
} else {
|
if (editorCamera.pitch < -89.0f)
|
||||||
|
editorCamera.pitch = -89.0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
lastX = lastY = 0;
|
lastX = lastY = 0;
|
||||||
}
|
}
|
||||||
editorCamera.view = glm::lookAt(editorCamera.position, editorCamera.position + front, glm::vec3(0,1,0));
|
editorCamera.view = glm::lookAt(editorCamera.position, editorCamera.position + front, glm::vec3(0, 1, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
if (!Engine::Init())
|
if (!Engine::Init())
|
||||||
return 1;
|
return 1;
|
||||||
// Load the light icon.
|
// Load the light icon.
|
||||||
@ -104,56 +119,49 @@ int main() {
|
|||||||
|
|
||||||
IMGUI_CHECKVERSION();
|
IMGUI_CHECKVERSION();
|
||||||
ImGui::CreateContext();
|
ImGui::CreateContext();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
ImGuiIO &io = ImGui::GetIO();
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
ImGui::StyleColorsDark();
|
ImGui::StyleColorsDark();
|
||||||
const char* glsl_version = "#version 330";
|
const char *glsl_version = "#version 330";
|
||||||
ImGui_ImplGlfw_InitForOpenGL(Engine::GetWindow(), true);
|
ImGui_ImplGlfw_InitForOpenGL(Engine::GetWindow(), true);
|
||||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||||
|
|
||||||
vector<Entity*> entities;
|
vector<Entity *> entities;
|
||||||
// Create two cube entities.
|
// Create two cube entities.
|
||||||
Entity* cube1 = new Entity(EntityType::CUBE);
|
Entity *cube1 = new Entity(EntityType::CUBE);
|
||||||
cube1->transform.position = glm::vec3(-2.0f, 0.0f, 0.0f);
|
cube1->transform.position = glm::vec3(-2.0f, 0.0f, 0.0f);
|
||||||
cube1->modelComponent = new ModelComponent();
|
cube1->modelComponent = new ModelComponent();
|
||||||
cube1->modelComponent->diffuseColor = glm::vec3(0.8f, 0.2f, 0.2f);
|
cube1->modelComponent->diffuseColor = glm::vec3(0.8f, 0.2f, 0.2f);
|
||||||
cube1->modelComponent->specularColor = glm::vec3(1.0f, 1.0f, 1.0f);
|
cube1->modelComponent->specularColor = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
cube1->modelComponent->shininess = 32.0f;
|
cube1->modelComponent->shininess = 32.0f;
|
||||||
|
|
||||||
Entity* cube2 = new Entity(EntityType::CUBE);
|
|
||||||
cube2->transform.position = glm::vec3(2.0f, 0.0f, 0.0f);
|
|
||||||
cube2->modelComponent = new ModelComponent();
|
|
||||||
cube2->modelComponent->diffuseColor = glm::vec3(0.2f, 0.8f, 0.2f);
|
|
||||||
cube2->modelComponent->specularColor = glm::vec3(1.0f, 1.0f, 1.0f);
|
|
||||||
cube2->modelComponent->shininess = 16.0f;
|
|
||||||
|
|
||||||
// Create two light entities.
|
// Create two light entities.
|
||||||
Entity* light1 = new Entity(EntityType::LIGHT);
|
Entity *light1 = new Entity(EntityType::LIGHT);
|
||||||
light1->transform.position = glm::vec3(0.0f, 10.0f, 0.0f);
|
light1->transform.position = glm::vec3(0.0f, 10.0f, 0.0f);
|
||||||
light1->lightComponent = new LightComponent();
|
light1->lightComponent = new LightComponent();
|
||||||
light1->lightComponent->color = glm::vec3(1.0f, 1.0f, 1.0f);
|
light1->lightComponent->color = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
light1->lightComponent->intensity = 1.5f;
|
light1->lightComponent->intensity = 1.5f;
|
||||||
|
|
||||||
Entity* light2 = new Entity(EntityType::LIGHT);
|
Entity *light2 = new Entity(EntityType::LIGHT);
|
||||||
light2->transform.position = glm::vec3(0.0f, -10.0f, 0.0f);
|
light2->transform.position = glm::vec3(0.0f, -10.0f, 0.0f);
|
||||||
light2->lightComponent = new LightComponent();
|
light2->lightComponent = new LightComponent();
|
||||||
light2->lightComponent->color = glm::vec3(0.2f, 0.2f, 1.0f);
|
light2->lightComponent->color = glm::vec3(0.2f, 0.2f, 1.0f);
|
||||||
light2->lightComponent->intensity = 1.0f;
|
light2->lightComponent->intensity = 1.0f;
|
||||||
|
|
||||||
entities.push_back(cube1);
|
entities.push_back(cube1);
|
||||||
entities.push_back(cube2);
|
|
||||||
entities.push_back(light1);
|
entities.push_back(light1);
|
||||||
entities.push_back(light2);
|
entities.push_back(light2);
|
||||||
|
|
||||||
Entity* selectedEntity = nullptr;
|
Entity *selectedEntity = nullptr;
|
||||||
int selectedIndex = -1;
|
int selectedIndex = -1;
|
||||||
|
|
||||||
// Variables for the "Change Model" popup.
|
// Variables for the "Change Model" popup.
|
||||||
static bool showModelPopup = false;
|
static bool showModelPopup = false;
|
||||||
static char newModelPath[256] = "";
|
static char newModelPath[256] = "";
|
||||||
|
|
||||||
float lastFrameTime = (float)glfwGetTime();
|
float lastFrameTime = (float)glfwGetTime();
|
||||||
while (!glfwWindowShouldClose(Engine::GetWindow())) {
|
while (!glfwWindowShouldClose(Engine::GetWindow()))
|
||||||
|
{
|
||||||
float currentFrameTime = (float)glfwGetTime();
|
float currentFrameTime = (float)glfwGetTime();
|
||||||
float deltaTime = currentFrameTime - lastFrameTime;
|
float deltaTime = currentFrameTime - lastFrameTime;
|
||||||
lastFrameTime = currentFrameTime;
|
lastFrameTime = currentFrameTime;
|
||||||
@ -180,16 +188,19 @@ int main() {
|
|||||||
|
|
||||||
// Left Panel: Entity List with Add/Remove buttons.
|
// Left Panel: Entity List with Add/Remove buttons.
|
||||||
ImGui::Begin("Entity List");
|
ImGui::Begin("Entity List");
|
||||||
for (int i = 0; i < entities.size(); i++) {
|
for (int i = 0; i < entities.size(); i++)
|
||||||
|
{
|
||||||
char label[32];
|
char label[32];
|
||||||
sprintf(label, "Entity %d", i);
|
sprintf(label, "Entity %d", i);
|
||||||
if (ImGui::Selectable(label, selectedIndex == i)) {
|
if (ImGui::Selectable(label, selectedIndex == i))
|
||||||
|
{
|
||||||
selectedEntity = entities[i];
|
selectedEntity = entities[i];
|
||||||
selectedIndex = i;
|
selectedIndex = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ImGui::Button("Add Cube")) {
|
if (ImGui::Button("Add Cube"))
|
||||||
Entity* newCube = new Entity(EntityType::CUBE);
|
{
|
||||||
|
Entity *newCube = new Entity(EntityType::CUBE);
|
||||||
newCube->transform.position = glm::vec3(0.0f);
|
newCube->transform.position = glm::vec3(0.0f);
|
||||||
newCube->modelComponent = new ModelComponent();
|
newCube->modelComponent = new ModelComponent();
|
||||||
// Default global model properties.
|
// Default global model properties.
|
||||||
@ -199,18 +210,21 @@ int main() {
|
|||||||
entities.push_back(newCube);
|
entities.push_back(newCube);
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Add Light")) {
|
if (ImGui::Button("Add Light"))
|
||||||
Entity* newLight = new Entity(EntityType::LIGHT);
|
{
|
||||||
|
Entity *newLight = new Entity(EntityType::LIGHT);
|
||||||
newLight->transform.position = glm::vec3(0.0f);
|
newLight->transform.position = glm::vec3(0.0f);
|
||||||
newLight->lightComponent = new LightComponent();
|
newLight->lightComponent = new LightComponent();
|
||||||
newLight->lightComponent->color = glm::vec3(1.0f);
|
newLight->lightComponent->color = glm::vec3(1.0f);
|
||||||
newLight->lightComponent->intensity = 1.0f;
|
newLight->lightComponent->intensity = 1.0f;
|
||||||
entities.push_back(newLight);
|
entities.push_back(newLight);
|
||||||
}
|
}
|
||||||
if (selectedEntity && ImGui::Button("Remove Selected")) {
|
if (selectedEntity && ImGui::Button("Remove Selected"))
|
||||||
|
{
|
||||||
// Remove selected entity.
|
// Remove selected entity.
|
||||||
auto it = std::find(entities.begin(), entities.end(), selectedEntity);
|
auto it = std::find(entities.begin(), entities.end(), selectedEntity);
|
||||||
if (it != entities.end()) {
|
if (it != entities.end())
|
||||||
|
{
|
||||||
delete *it;
|
delete *it;
|
||||||
entities.erase(it);
|
entities.erase(it);
|
||||||
selectedEntity = nullptr;
|
selectedEntity = nullptr;
|
||||||
@ -221,62 +235,75 @@ int main() {
|
|||||||
|
|
||||||
// Right Panel: Entity Inspector.
|
// Right Panel: Entity Inspector.
|
||||||
ImGui::Begin("Entity Inspector");
|
ImGui::Begin("Entity Inspector");
|
||||||
if (selectedEntity) {
|
if (selectedEntity)
|
||||||
|
{
|
||||||
ImGui::Text("Transform");
|
ImGui::Text("Transform");
|
||||||
ImGui::DragFloat3("Position", glm::value_ptr(selectedEntity->transform.position), 0.1f);
|
ImGui::DragFloat3("Position", glm::value_ptr(selectedEntity->transform.position), 0.1f);
|
||||||
ImGui::DragFloat3("Rotation", glm::value_ptr(selectedEntity->transform.rotation), 0.5f);
|
ImGui::DragFloat3("Rotation", glm::value_ptr(selectedEntity->transform.rotation), 0.5f);
|
||||||
ImGui::DragFloat3("Scale", glm::value_ptr(selectedEntity->transform.scale), 0.1f);
|
ImGui::DragFloat3("Scale", glm::value_ptr(selectedEntity->transform.scale), 0.1f);
|
||||||
if (selectedEntity->GetType() == EntityType::CUBE && selectedEntity->modelComponent) {
|
if (selectedEntity->GetType() == EntityType::CUBE && selectedEntity->modelComponent)
|
||||||
|
{
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Model Properties");
|
ImGui::Text("Model Properties");
|
||||||
ImGui::ColorEdit3("Diffuse", glm::value_ptr(selectedEntity->modelComponent->diffuseColor));
|
ImGui::ColorEdit3("Diffuse", glm::value_ptr(selectedEntity->modelComponent->diffuseColor));
|
||||||
ImGui::ColorEdit3("Specular", glm::value_ptr(selectedEntity->modelComponent->specularColor));
|
ImGui::ColorEdit3("Specular", glm::value_ptr(selectedEntity->modelComponent->specularColor));
|
||||||
ImGui::DragFloat("Shininess", &selectedEntity->modelComponent->shininess, 1.0f, 1.0f, 128.0f);
|
ImGui::DragFloat("Shininess", &selectedEntity->modelComponent->shininess, 1.0f, 1.0f, 128.0f);
|
||||||
// Button to open model editor popup.
|
// Button to open model editor popup.
|
||||||
if (ImGui::Button("Change Model")) {
|
if (ImGui::Button("Change Model"))
|
||||||
|
{
|
||||||
showModelPopup = true;
|
showModelPopup = true;
|
||||||
// Pre-fill popup with current model path.
|
// Pre-fill popup with current model path.
|
||||||
strncpy(newModelPath, selectedEntity->modelComponent->modelPath.c_str(), sizeof(newModelPath));
|
strncpy(newModelPath, selectedEntity->modelComponent->modelPath.c_str(), sizeof(newModelPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (selectedEntity->GetType() == EntityType::LIGHT && selectedEntity->lightComponent) {
|
if (selectedEntity->GetType() == EntityType::LIGHT && selectedEntity->lightComponent)
|
||||||
|
{
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Light Properties");
|
ImGui::Text("Light Properties");
|
||||||
ImGui::ColorEdit3("Light Color", glm::value_ptr(selectedEntity->lightComponent->color));
|
ImGui::ColorEdit3("Light Color", glm::value_ptr(selectedEntity->lightComponent->color));
|
||||||
ImGui::DragFloat("Intensity", &selectedEntity->lightComponent->intensity, 0.1f, 0.0f, 10.0f);
|
ImGui::DragFloat("Intensity", &selectedEntity->lightComponent->intensity, 0.1f, 0.0f, 10.0f);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ImGui::Text("No entity selected.");
|
ImGui::Text("No entity selected.");
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// Model Editor Popup.
|
// Model Editor Popup.
|
||||||
if (showModelPopup && selectedEntity && selectedEntity->modelComponent) {
|
if (showModelPopup && selectedEntity && selectedEntity->modelComponent)
|
||||||
|
{
|
||||||
ImGui::OpenPopup("Edit Model");
|
ImGui::OpenPopup("Edit Model");
|
||||||
showModelPopup = false;
|
showModelPopup = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupModal("Edit Model", NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
if (ImGui::BeginPopupModal("Edit Model", NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
|
{
|
||||||
ImGui::InputText("Model Path", newModelPath, sizeof(newModelPath));
|
ImGui::InputText("Model Path", newModelPath, sizeof(newModelPath));
|
||||||
if (ImGui::Button("Load Model", ImVec2(120, 0))) {
|
if (ImGui::Button("Load Model", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
// Update the model component with the new model path.
|
// Update the model component with the new model path.
|
||||||
selectedEntity->modelComponent->LoadModel(newModelPath);
|
selectedEntity->modelComponent->LoadModel(newModelPath);
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Cancel", ImVec2(120, 0))) {
|
if (ImGui::Button("Cancel", ImVec2(120, 0)))
|
||||||
|
{
|
||||||
ImGui::CloseCurrentPopup();
|
ImGui::CloseCurrentPopup();
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Submesh Textures:");
|
ImGui::Text("Submesh Textures:");
|
||||||
// Display a grid of textures.
|
// Display a grid of textures.
|
||||||
if (selectedEntity->modelComponent->meshes.empty()) {
|
if (selectedEntity->modelComponent->meshes.empty())
|
||||||
|
{
|
||||||
ImGui::Text("None");
|
ImGui::Text("None");
|
||||||
} else {
|
}
|
||||||
int columns = 12; // Change this value for a different number of columns.
|
else
|
||||||
|
{
|
||||||
|
int columns = 12; // Change this value for a different number of columns.
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (size_t i = 0; i < selectedEntity->modelComponent->meshes.size(); i++) {
|
for (size_t i = 0; i < selectedEntity->modelComponent->meshes.size(); i++)
|
||||||
|
{
|
||||||
if (count % columns != 0)
|
if (count % columns != 0)
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
// Convert the diffuse texture to an ImTextureID.
|
// Convert the diffuse texture to an ImTextureID.
|
||||||
@ -288,28 +315,59 @@ int main() {
|
|||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
ImGui::EndPopup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// New Panel: File Operations (Save/Load).
|
// New Panel: File Operations (Save/Load).
|
||||||
ImGui::Begin("Scene File");
|
ImGui::Begin("Scene File");
|
||||||
if (ImGui::Button("Save")) {
|
|
||||||
|
// --- List Files in Scene Directory ---
|
||||||
|
static std::vector<std::string> sceneFiles;
|
||||||
|
static int selectedSceneFile = -1;
|
||||||
|
if (ImGui::Button("Refresh Files"))
|
||||||
|
{
|
||||||
|
sceneFiles.clear();
|
||||||
|
std::cout << "Refreshing" << std::endl;
|
||||||
|
for (const auto &entry : std::filesystem::directory_iterator("./assets/scenes/"))
|
||||||
|
{
|
||||||
|
if (entry.is_regular_file() && entry.path().extension() == ".yaml")
|
||||||
|
{
|
||||||
|
sceneFiles.push_back(entry.path().filename().string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::Text("Available Scenes:");
|
||||||
|
for (int i = 0; i < sceneFiles.size(); i++)
|
||||||
|
{
|
||||||
|
if (ImGui::Selectable(sceneFiles[i].c_str(), selectedSceneFile == i))
|
||||||
|
{
|
||||||
|
selectedSceneFile = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Specify New File Name for Saving ---
|
||||||
|
static char newSceneFileName[128] = "new_scene.yaml";
|
||||||
|
ImGui::InputText("New Scene File", newSceneFileName, IM_ARRAYSIZE(newSceneFileName));
|
||||||
|
|
||||||
|
// --- Save Scene ---
|
||||||
|
if (ImGui::Button("Save"))
|
||||||
|
{
|
||||||
|
std::cout << "[Info] Saving" << std::endl;
|
||||||
|
|
||||||
YAML::Emitter out;
|
YAML::Emitter out;
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
// Save an array of entities.
|
// Save an array of entities.
|
||||||
out << YAML::Key << "entities" << YAML::Value << YAML::BeginSeq;
|
out << YAML::Key << "entities" << YAML::Value << YAML::BeginSeq;
|
||||||
for (auto e : entities) {
|
for (auto e : entities)
|
||||||
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
// Save the type.
|
out << YAML::Key << "type" << YAML::Value
|
||||||
out << YAML::Key << "type" << YAML::Value << (e->GetType() == EntityType::CUBE ? "cube" : "light");
|
<< (e->GetType() == EntityType::CUBE ? "cube" : "light");
|
||||||
// Save transform.
|
|
||||||
out << YAML::Key << "transform" << YAML::Value << e->transform.Save();
|
out << YAML::Key << "transform" << YAML::Value << e->transform.Save();
|
||||||
// Save model component if cube.
|
if (e->modelComponent)
|
||||||
if (e->GetType() == EntityType::CUBE && e->modelComponent) {
|
{
|
||||||
out << YAML::Key << "model" << YAML::Value << e->modelComponent->Save();
|
out << YAML::Key << "model" << YAML::Value << e->modelComponent->Save();
|
||||||
}
|
}
|
||||||
// Save light component if light.
|
if (e->lightComponent)
|
||||||
if (e->GetType() == EntityType::LIGHT && e->lightComponent) {
|
{
|
||||||
out << YAML::Key << "light" << YAML::Value << e->lightComponent->Save();
|
out << YAML::Key << "light" << YAML::Value << e->lightComponent->Save();
|
||||||
}
|
}
|
||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
@ -317,37 +375,80 @@ int main() {
|
|||||||
out << YAML::EndSeq;
|
out << YAML::EndSeq;
|
||||||
out << YAML::EndMap;
|
out << YAML::EndMap;
|
||||||
|
|
||||||
std::ofstream fout("default.yaml");
|
// Save file to the scenes directory.
|
||||||
|
std::string path = std::string("./assets/scenes/") + newSceneFileName;
|
||||||
|
std::ofstream fout(path);
|
||||||
fout << out.c_str();
|
fout << out.c_str();
|
||||||
fout.close();
|
fout.close();
|
||||||
|
std::cout << "[Done] Saving" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (ImGui::Button("Load")) {
|
|
||||||
YAML::Node node = YAML::LoadFile("default.yaml");
|
// --- Load Scene (delete & recreate entities) ---
|
||||||
if (node["entities"]) {
|
if (ImGui::Button("Load"))
|
||||||
YAML::Node entitiesNode = node["entities"];
|
{
|
||||||
int idx = 0;
|
std::cout << "[Info] Loading" << std::endl;
|
||||||
for (auto entityNode : entitiesNode) {
|
|
||||||
if (idx < entities.size()) {
|
// Only proceed if a file is selected from the list.
|
||||||
// Load transform.
|
if (selectedSceneFile >= 0 && selectedSceneFile < sceneFiles.size())
|
||||||
if (entityNode["transform"])
|
{
|
||||||
entities[idx]->transform.Load(entityNode["transform"]);
|
std::string path = "./assests/scenes/" + sceneFiles[selectedSceneFile];
|
||||||
// Load model for cubes.
|
YAML::Node node = YAML::LoadFile(path);
|
||||||
if (entities[idx]->GetType() == EntityType::CUBE && entityNode["model"])
|
if (node["entities"])
|
||||||
entities[idx]->modelComponent->Load(entityNode["model"]);
|
{
|
||||||
// Load light for lights.
|
// Delete current entities.
|
||||||
if (entities[idx]->GetType() == EntityType::LIGHT && entityNode["light"])
|
for (auto e : entities)
|
||||||
entities[idx]->lightComponent->Load(entityNode["light"]);
|
{
|
||||||
|
delete e; // Assumes deletion handles components properly.
|
||||||
|
}
|
||||||
|
entities.clear();
|
||||||
|
|
||||||
|
YAML::Node entitiesNode = node["entities"];
|
||||||
|
for (auto entityNode : entitiesNode)
|
||||||
|
{
|
||||||
|
std::string type = entityNode["type"].as<std::string>();
|
||||||
|
Entity *newEntity = nullptr;
|
||||||
|
// Create entity based on type.
|
||||||
|
if (type == "cube")
|
||||||
|
{
|
||||||
|
newEntity = new Entity(EntityType::CUBE);
|
||||||
|
}
|
||||||
|
else if (type == "light")
|
||||||
|
{
|
||||||
|
newEntity = new Entity(EntityType::LIGHT);
|
||||||
|
}
|
||||||
|
if (newEntity)
|
||||||
|
{
|
||||||
|
// Load transform.
|
||||||
|
if (entityNode["transform"])
|
||||||
|
newEntity->transform.Load(entityNode["transform"]);
|
||||||
|
// Create and load model component for cubes.
|
||||||
|
if (newEntity->GetType() == EntityType::CUBE && entityNode["model"])
|
||||||
|
{
|
||||||
|
newEntity->modelComponent = new ModelComponent();
|
||||||
|
newEntity->modelComponent->Load(entityNode["model"]);
|
||||||
|
}
|
||||||
|
// Create and load light component for lights.
|
||||||
|
if (newEntity->GetType() == EntityType::LIGHT && entityNode["light"])
|
||||||
|
{
|
||||||
|
newEntity->lightComponent = new LightComponent();
|
||||||
|
newEntity->lightComponent->Load(entityNode["light"]);
|
||||||
|
}
|
||||||
|
entities.push_back(newEntity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
idx++;
|
|
||||||
}
|
}
|
||||||
|
std::cout << "[Done] Loading" << std::endl;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// Bottom Panel: Rendered Output.
|
// Bottom Panel: Rendered Output.
|
||||||
ImGui::Begin("Rendered Output");
|
ImGui::Begin("Rendered Output");
|
||||||
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
||||||
ImGui::Image(offscreenTexture, viewportSize, ImVec2(0,1), ImVec2(1,0));
|
ImGui::Image(offscreenTexture, viewportSize, ImVec2(0, 1), ImVec2(1, 0));
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <filesystem> // C++17 filesystem
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#include "Entity/Entity.h"
|
#include "Entity/Entity.h"
|
||||||
|
|
||||||
// Static member definitions.
|
// Static member definitions.
|
||||||
GLFWwindow* Engine::window = nullptr;
|
GLFWwindow *Engine::window = nullptr;
|
||||||
GLuint Engine::framebuffer = 0;
|
GLuint Engine::framebuffer = 0;
|
||||||
GLuint Engine::colorTexture = 0;
|
GLuint Engine::colorTexture = 0;
|
||||||
GLuint Engine::depthRenderbuffer = 0;
|
GLuint Engine::depthRenderbuffer = 0;
|
||||||
@ -15,14 +15,13 @@ float Engine::rotationAngle = 0.0f;
|
|||||||
int Engine::fbWidth = 640;
|
int Engine::fbWidth = 640;
|
||||||
int Engine::fbHeight = 400;
|
int Engine::fbHeight = 400;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Global normal map texture (if needed for legacy models; otherwise each model handles its own)
|
// Global normal map texture (if needed for legacy models; otherwise each model handles its own)
|
||||||
GLuint normalMapTexture = 0;
|
GLuint normalMapTexture = 0;
|
||||||
|
|
||||||
bool Engine::Init() {
|
bool Engine::Init()
|
||||||
if (!glfwInit()) {
|
{
|
||||||
|
if (!glfwInit())
|
||||||
|
{
|
||||||
std::cout << "Failed to initialize GLFW\n";
|
std::cout << "Failed to initialize GLFW\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -31,7 +30,8 @@ bool Engine::Init() {
|
|||||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
|
||||||
window = glfwCreateWindow(1280, 800, "Engine Window", nullptr, nullptr);
|
window = glfwCreateWindow(1280, 800, "Engine Window", nullptr, nullptr);
|
||||||
if (!window) {
|
if (!window)
|
||||||
|
{
|
||||||
std::cout << "Failed to create GLFW window\n";
|
std::cout << "Failed to create GLFW window\n";
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
return false;
|
return false;
|
||||||
@ -39,7 +39,8 @@ bool Engine::Init() {
|
|||||||
glfwMakeContextCurrent(window);
|
glfwMakeContextCurrent(window);
|
||||||
|
|
||||||
glewExperimental = GL_TRUE;
|
glewExperimental = GL_TRUE;
|
||||||
if (glewInit() != GLEW_OK) {
|
if (glewInit() != GLEW_OK)
|
||||||
|
{
|
||||||
std::cout << "Failed to initialize GLEW\n";
|
std::cout << "Failed to initialize GLEW\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -53,21 +54,25 @@ bool Engine::Init() {
|
|||||||
ResizeFramebuffer(fbWidth, fbHeight);
|
ResizeFramebuffer(fbWidth, fbHeight);
|
||||||
|
|
||||||
// Setup scene-wide shader (this shader is now used to render all models)
|
// Setup scene-wide shader (this shader is now used to render all models)
|
||||||
if (!SetupScene()) {
|
if (!SetupScene())
|
||||||
|
{
|
||||||
std::cout << "Failed to set up scene\n";
|
std::cout << "Failed to set up scene\n";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWwindow* Engine::GetWindow() {
|
GLFWwindow *Engine::GetWindow()
|
||||||
|
{
|
||||||
return window;
|
return window;
|
||||||
}
|
}
|
||||||
GLuint Engine::GetShader() {
|
GLuint Engine::GetShader()
|
||||||
|
{
|
||||||
return shaderProgram;
|
return shaderProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::ResizeFramebuffer(int width, int height) {
|
void Engine::ResizeFramebuffer(int width, int height)
|
||||||
|
{
|
||||||
// Avoid division by zero.
|
// Avoid division by zero.
|
||||||
if (height <= 0)
|
if (height <= 0)
|
||||||
height = 1;
|
height = 1;
|
||||||
@ -75,26 +80,31 @@ void Engine::ResizeFramebuffer(int width, int height) {
|
|||||||
// Define the desired target aspect ratio (e.g., 16:9).
|
// Define the desired target aspect ratio (e.g., 16:9).
|
||||||
const float targetAspect = 16.0f / 9.0f;
|
const float targetAspect = 16.0f / 9.0f;
|
||||||
float currentAspect = static_cast<float>(width) / static_cast<float>(height);
|
float currentAspect = static_cast<float>(width) / static_cast<float>(height);
|
||||||
|
|
||||||
// Adjust dimensions to maintain the target aspect ratio.
|
// Adjust dimensions to maintain the target aspect ratio.
|
||||||
int newWidth = width;
|
int newWidth = width;
|
||||||
int newHeight = height;
|
int newHeight = height;
|
||||||
if (currentAspect > targetAspect) {
|
if (currentAspect > targetAspect)
|
||||||
|
{
|
||||||
newWidth = static_cast<int>(height * targetAspect);
|
newWidth = static_cast<int>(height * targetAspect);
|
||||||
} else if (currentAspect < targetAspect) {
|
}
|
||||||
|
else if (currentAspect < targetAspect)
|
||||||
|
{
|
||||||
newHeight = static_cast<int>(width / targetAspect);
|
newHeight = static_cast<int>(width / targetAspect);
|
||||||
}
|
}
|
||||||
|
|
||||||
fbWidth = newWidth;
|
fbWidth = newWidth;
|
||||||
fbHeight = newHeight;
|
fbHeight = newHeight;
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
|
|
||||||
// Delete old attachments if they exist.
|
// Delete old attachments if they exist.
|
||||||
if (colorTexture) {
|
if (colorTexture)
|
||||||
|
{
|
||||||
glDeleteTextures(1, &colorTexture);
|
glDeleteTextures(1, &colorTexture);
|
||||||
}
|
}
|
||||||
if (depthRenderbuffer) {
|
if (depthRenderbuffer)
|
||||||
|
{
|
||||||
glDeleteRenderbuffers(1, &depthRenderbuffer);
|
glDeleteRenderbuffers(1, &depthRenderbuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,19 +123,22 @@ void Engine::ResizeFramebuffer(int width, int height) {
|
|||||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
|
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
|
||||||
|
|
||||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
if (status != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
{
|
||||||
std::cout << "Framebuffer is not complete! Status: " << status << std::endl;
|
std::cout << "Framebuffer is not complete! Status: " << status << std::endl;
|
||||||
}
|
}
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint Engine::CompileShader(const char* vertexSrc, const char* fragmentSrc) {
|
GLuint Engine::CompileShader(const char *vertexSrc, const char *fragmentSrc)
|
||||||
|
{
|
||||||
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||||
glShaderSource(vertexShader, 1, &vertexSrc, nullptr);
|
glShaderSource(vertexShader, 1, &vertexSrc, nullptr);
|
||||||
glCompileShader(vertexShader);
|
glCompileShader(vertexShader);
|
||||||
int success;
|
int success;
|
||||||
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
|
||||||
if (!success) {
|
if (!success)
|
||||||
|
{
|
||||||
char infoLog[512];
|
char infoLog[512];
|
||||||
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
|
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
|
||||||
std::cout << "Vertex shader compilation failed: " << infoLog << std::endl;
|
std::cout << "Vertex shader compilation failed: " << infoLog << std::endl;
|
||||||
@ -135,7 +148,8 @@ GLuint Engine::CompileShader(const char* vertexSrc, const char* fragmentSrc) {
|
|||||||
glShaderSource(fragmentShader, 1, &fragmentSrc, nullptr);
|
glShaderSource(fragmentShader, 1, &fragmentSrc, nullptr);
|
||||||
glCompileShader(fragmentShader);
|
glCompileShader(fragmentShader);
|
||||||
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
|
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
|
||||||
if (!success) {
|
if (!success)
|
||||||
|
{
|
||||||
char infoLog[512];
|
char infoLog[512];
|
||||||
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
|
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
|
||||||
std::cout << "Fragment shader compilation failed: " << infoLog << std::endl;
|
std::cout << "Fragment shader compilation failed: " << infoLog << std::endl;
|
||||||
@ -146,7 +160,8 @@ GLuint Engine::CompileShader(const char* vertexSrc, const char* fragmentSrc) {
|
|||||||
glAttachShader(program, fragmentShader);
|
glAttachShader(program, fragmentShader);
|
||||||
glLinkProgram(program);
|
glLinkProgram(program);
|
||||||
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
glGetProgramiv(program, GL_LINK_STATUS, &success);
|
||||||
if (!success) {
|
if (!success)
|
||||||
|
{
|
||||||
char infoLog[512];
|
char infoLog[512];
|
||||||
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
glGetProgramInfoLog(program, 512, nullptr, infoLog);
|
||||||
std::cout << "Shader program linking failed: " << infoLog << std::endl;
|
std::cout << "Shader program linking failed: " << infoLog << std::endl;
|
||||||
@ -159,105 +174,116 @@ GLuint Engine::CompileShader(const char* vertexSrc, const char* fragmentSrc) {
|
|||||||
|
|
||||||
// SetupScene now creates the shader program used for all models.
|
// SetupScene now creates the shader program used for all models.
|
||||||
// It no longer creates cube-specific VAOs, since ModelComponent will store mesh data.
|
// It no longer creates cube-specific VAOs, since ModelComponent will store mesh data.
|
||||||
bool Engine::SetupScene() {
|
bool Engine::SetupScene()
|
||||||
|
{
|
||||||
|
|
||||||
const char* vertexShaderSrc = R"(
|
// Vertex Shader remains largely unchanged.
|
||||||
#version 330 core
|
const char *vertexShaderSrc = R"(
|
||||||
layout(location = 0) in vec3 aPos;
|
#version 330 core
|
||||||
layout(location = 1) in vec3 aNormal;
|
layout(location = 0) in vec3 aPos;
|
||||||
layout(location = 2) in vec2 aTexCoords;
|
layout(location = 1) in vec3 aNormal;
|
||||||
layout(location = 3) in vec3 aTangent;
|
layout(location = 2) in vec2 aTexCoords;
|
||||||
|
layout(location = 3) in vec3 aTangent;
|
||||||
uniform mat4 model;
|
|
||||||
uniform mat4 view;
|
uniform mat4 model;
|
||||||
uniform mat4 projection;
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
out vec3 FragPos;
|
|
||||||
out vec3 Normal;
|
out vec3 FragPos;
|
||||||
out vec2 TexCoords;
|
out vec3 Normal;
|
||||||
out vec3 Tangent;
|
out vec2 TexCoords;
|
||||||
|
out vec3 Tangent;
|
||||||
void main() {
|
|
||||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
void main() {
|
||||||
Normal = mat3(transpose(inverse(model))) * aNormal;
|
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
TexCoords = aTexCoords;
|
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||||
Tangent = mat3(model) * aTangent;
|
TexCoords = aTexCoords;
|
||||||
gl_Position = projection * view * vec4(FragPos, 1.0);
|
Tangent = mat3(model) * aTangent;
|
||||||
}
|
gl_Position = projection * view * vec4(FragPos, 1.0);
|
||||||
)";
|
}
|
||||||
|
)";
|
||||||
const char* fragmentShaderSrc = R"(
|
|
||||||
#version 330 core
|
// Fragment Shader with support for optional diffuse and normal maps and using Blinn-Phong lighting.
|
||||||
out vec4 FragColor;
|
const char* fragmentShaderSrc = R"(
|
||||||
|
#version 330 core
|
||||||
in vec3 FragPos;
|
out vec4 FragColor;
|
||||||
in vec3 Normal;
|
|
||||||
in vec2 TexCoords;
|
in vec3 FragPos;
|
||||||
in vec3 Tangent;
|
in vec3 Normal;
|
||||||
|
in vec2 TexCoords;
|
||||||
uniform vec3 lightPositions[2];
|
in vec3 Tangent;
|
||||||
uniform vec3 lightColors[2];
|
|
||||||
uniform int numLights;
|
uniform vec3 lightPositions[2];
|
||||||
uniform vec3 viewPos;
|
uniform vec3 lightColors[2];
|
||||||
uniform sampler2D diffuseTexture;
|
uniform int numLights;
|
||||||
uniform sampler2D normalMap;
|
uniform vec3 viewPos;
|
||||||
uniform bool useNormalMap; // Control flag for normal mapping
|
|
||||||
|
// Texture uniforms.
|
||||||
// Material properties.
|
uniform sampler2D diffuseTexture;
|
||||||
uniform vec3 materialDiffuse;
|
uniform sampler2D normalMap;
|
||||||
uniform vec3 materialSpecular;
|
uniform bool useDiffuseTexture;
|
||||||
uniform float materialShininess;
|
uniform bool useNormalMap; // Control flag for normal mapping
|
||||||
|
|
||||||
void main() {
|
// Material properties.
|
||||||
vec3 finalNormal;
|
uniform vec3 materialDiffuse;
|
||||||
if(useNormalMap) {
|
uniform vec3 materialSpecular;
|
||||||
// Sample and transform normal map.
|
uniform float materialShininess;
|
||||||
vec3 normMap = texture(normalMap, TexCoords).rgb;
|
|
||||||
normMap = normalize(normMap * 2.0 - 1.0);
|
void main() {
|
||||||
normMap.z = -normMap.z;
|
// Optionally sample the diffuse texture.
|
||||||
vec3 T = normalize(Tangent);
|
vec3 diffuseTex = useDiffuseTexture ? texture(diffuseTexture, TexCoords).rgb : vec3(1.0);
|
||||||
vec3 B = normalize(cross(Normal, T));
|
|
||||||
mat3 TBN = mat3(T, B, normalize(Normal));
|
// Determine the normal.
|
||||||
finalNormal = normalize(TBN * normMap);
|
vec3 finalNormal;
|
||||||
} else {
|
if(useNormalMap) {
|
||||||
// Compute a flat normal from screen-space derivatives.
|
// Sample the normal map and convert from [0,1] to [-1,1].
|
||||||
finalNormal = normalize(cross(dFdx(FragPos), dFdy(FragPos)));
|
vec3 normMap = texture(normalMap, TexCoords).rgb;
|
||||||
}
|
normMap = normalize(normMap * 2.0 - 1.0);
|
||||||
|
// (The z-flip here depends on your texture convention.)
|
||||||
vec3 diffuseTex = texture(diffuseTexture, TexCoords).rgb;
|
normMap.z = -normMap.z;
|
||||||
vec3 ambient = 0.1 * materialDiffuse * diffuseTex;
|
vec3 T = normalize(Tangent);
|
||||||
vec3 lighting = ambient;
|
vec3 B = normalize(cross(Normal, T));
|
||||||
|
mat3 TBN = mat3(T, B, normalize(Normal));
|
||||||
for(int i = 0; i < numLights; i++) {
|
finalNormal = normalize(TBN * normMap);
|
||||||
vec3 lightDir = normalize(lightPositions[i] - FragPos);
|
} else {
|
||||||
float diff = max(dot(finalNormal, lightDir), 0.0);
|
// Use the interpolated vertex normal if no normal map is provided.
|
||||||
vec3 diffuse = diff * materialDiffuse * diffuseTex * lightColors[i];
|
finalNormal = normalize(Normal);
|
||||||
|
}
|
||||||
vec3 viewDir = normalize(viewPos - FragPos);
|
|
||||||
vec3 reflectDir = reflect(-lightDir, finalNormal);
|
// Start with an ambient term.
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), materialShininess);
|
vec3 ambient = 0.1 * materialDiffuse * diffuseTex;
|
||||||
vec3 specular = materialSpecular * spec * lightColors[i];
|
vec3 lighting = ambient;
|
||||||
|
|
||||||
lighting += diffuse + specular;
|
// Loop through each light.
|
||||||
}
|
for(int i = 0; i < numLights; i++) {
|
||||||
FragColor = vec4(lighting, 1.0);
|
vec3 lightDir = normalize(lightPositions[i] - FragPos);
|
||||||
}
|
// Diffuse term.
|
||||||
)";
|
float diff = max(dot(finalNormal, lightDir), 0.0);
|
||||||
|
vec3 diffuse = diff * materialDiffuse * diffuseTex * lightColors[i];
|
||||||
|
|
||||||
|
// Blinn-Phong Specular term.
|
||||||
|
vec3 viewDir = normalize(viewPos - FragPos);
|
||||||
|
vec3 halfDir = normalize(lightDir + viewDir);
|
||||||
|
float spec = pow(max(dot(finalNormal, halfDir), 0.0), materialShininess);
|
||||||
|
vec3 specular = materialSpecular * spec * lightColors[i];
|
||||||
|
|
||||||
|
lighting += diffuse + specular;
|
||||||
|
}
|
||||||
|
|
||||||
|
FragColor = vec4(lighting, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
shaderProgram = CompileShader(vertexShaderSrc, fragmentShaderSrc);
|
shaderProgram = CompileShader(vertexShaderSrc, fragmentShaderSrc);
|
||||||
if (shaderProgram == 0) {
|
if (shaderProgram == 0)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RenderScene now uses the new model system.
|
|
||||||
// For each entity of type CUBE with a valid ModelComponent, update uniforms and call Draw() on the model.
|
|
||||||
ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projection, const glm::vec3 &viewPos, const std::vector<Entity*>& entities) {
|
ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projection, const glm::vec3 &viewPos, const std::vector<Entity*>& entities) {
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||||
glViewport(0, 0, fbWidth, fbHeight);
|
glViewport(0, 0, fbWidth, fbHeight);
|
||||||
@ -270,7 +296,7 @@ ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projecti
|
|||||||
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
||||||
glUniform3f(glGetUniformLocation(shaderProgram, "viewPos"), viewPos.x, viewPos.y, viewPos.z);
|
glUniform3f(glGetUniformLocation(shaderProgram, "viewPos"), viewPos.x, viewPos.y, viewPos.z);
|
||||||
|
|
||||||
// Gather lights (up to 2) from entities of type LIGHT.
|
// Gather up to 2 lights.
|
||||||
glm::vec3 lightPositions[2] = { glm::vec3(0.0f), glm::vec3(0.0f) };
|
glm::vec3 lightPositions[2] = { glm::vec3(0.0f), glm::vec3(0.0f) };
|
||||||
glm::vec3 lightColors[2] = { glm::vec3(1.0f), glm::vec3(1.0f) };
|
glm::vec3 lightColors[2] = { glm::vec3(1.0f), glm::vec3(1.0f) };
|
||||||
int lightCount = 0;
|
int lightCount = 0;
|
||||||
@ -290,46 +316,58 @@ ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projecti
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Render each cube entity using its ModelComponent.
|
// Render each cube entity using its ModelComponent.
|
||||||
for (auto e : entities) {
|
for (auto e : entities) {
|
||||||
if (e->GetType() == EntityType::CUBE && e->modelComponent) {
|
if (e->GetType() == EntityType::CUBE && e->modelComponent) {
|
||||||
glm::mat4 modelMatrix = e->transform.GetMatrix();
|
glm::mat4 modelMatrix = e->transform.GetMatrix();
|
||||||
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
|
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
|
||||||
|
|
||||||
// Loop through all submeshes in the model component.
|
// Loop through all submeshes in the model component.
|
||||||
for (const auto &mesh : e->modelComponent->meshes) {
|
for (const auto &mesh : e->modelComponent->meshes) {
|
||||||
// Set material properties for the current submesh.
|
// Set material properties.
|
||||||
glUniform3fv(glGetUniformLocation(shaderProgram, "materialDiffuse"), 1, glm::value_ptr(mesh.diffuseColor));
|
glUniform3fv(glGetUniformLocation(shaderProgram, "materialDiffuse"), 1, glm::value_ptr(mesh.diffuseColor));
|
||||||
glUniform3fv(glGetUniformLocation(shaderProgram, "materialSpecular"), 1, glm::value_ptr(mesh.specularColor));
|
glUniform3fv(glGetUniformLocation(shaderProgram, "materialSpecular"), 1, glm::value_ptr(mesh.specularColor));
|
||||||
glUniform1f(glGetUniformLocation(shaderProgram, "materialShininess"), mesh.shininess);
|
glUniform1f(glGetUniformLocation(shaderProgram, "materialShininess"), mesh.shininess);
|
||||||
|
|
||||||
// Bind the diffuse texture.
|
// Bind diffuse texture if available.
|
||||||
glActiveTexture(GL_TEXTURE0);
|
if (mesh.diffuseTexture != 0) {
|
||||||
glBindTexture(GL_TEXTURE_2D, mesh.diffuseTexture);
|
glUniform1i(glGetUniformLocation(shaderProgram, "useDiffuseTexture"), 1);
|
||||||
glUniform1i(glGetUniformLocation(shaderProgram, "diffuseTexture"), 0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mesh.diffuseTexture);
|
||||||
|
glUniform1i(glGetUniformLocation(shaderProgram, "diffuseTexture"), 0);
|
||||||
|
} else {
|
||||||
|
glUniform1i(glGetUniformLocation(shaderProgram, "useDiffuseTexture"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
// If you have a normal texture, bind it similarly (adjust as needed).
|
// Bind normal map if available.
|
||||||
// glActiveTexture(GL_TEXTURE1);
|
if (mesh.normalTexture != 0) {
|
||||||
// glBindTexture(GL_TEXTURE_2D, mesh.normalTexture);
|
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), 1);
|
||||||
// glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, mesh.normalTexture);
|
||||||
|
glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 1);
|
||||||
|
} else {
|
||||||
|
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Bind the submesh's VAO and draw its elements.
|
// Bind the submesh's VAO and draw its elements.
|
||||||
glBindVertexArray(mesh.VAO);
|
glBindVertexArray(mesh.VAO);
|
||||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, 0);
|
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, 0);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
return (ImTextureID)(intptr_t)colorTexture;
|
return (ImTextureID)(intptr_t)colorTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImTextureID Engine::GetFinalRenderingTexture() {
|
|
||||||
|
ImTextureID Engine::GetFinalRenderingTexture()
|
||||||
|
{
|
||||||
return (ImTextureID)(intptr_t)colorTexture;
|
return (ImTextureID)(intptr_t)colorTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Shutdown() {
|
void Engine::Shutdown()
|
||||||
|
{
|
||||||
glDeleteProgram(shaderProgram);
|
glDeleteProgram(shaderProgram);
|
||||||
glDeleteFramebuffers(1, &framebuffer);
|
glDeleteFramebuffers(1, &framebuffer);
|
||||||
glDeleteTextures(1, &colorTexture);
|
glDeleteTextures(1, &colorTexture);
|
||||||
|
BIN
Three-Labs.exe
BIN
Three-Labs.exe
Binary file not shown.
91
assets/scenes/default.yaml
Normal file
91
assets/scenes/default.yaml
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
entities:
|
||||||
|
- type: cube
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- -2
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
model:
|
||||||
|
modelPath: ./assets/models/sponza.obj
|
||||||
|
globalDiffuseColor:
|
||||||
|
- 0.800000012
|
||||||
|
- 0.200000003
|
||||||
|
- 0.200000003
|
||||||
|
globalSpecularColor:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
globalShininess: 32
|
||||||
|
- type: cube
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 0.5
|
||||||
|
- -1.20000005
|
||||||
|
- 5.19999981
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 90
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 0.00999999978
|
||||||
|
- 0.00999999978
|
||||||
|
- 0.00999999978
|
||||||
|
model:
|
||||||
|
modelPath: ./assets/models/sponza.obj
|
||||||
|
globalDiffuseColor:
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 0
|
||||||
|
globalSpecularColor:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
globalShininess: 126
|
||||||
|
- type: light
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 0
|
||||||
|
- 10
|
||||||
|
- 0
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
light:
|
||||||
|
color:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
intensity: 2.0999999
|
||||||
|
- type: light
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 2.9000001
|
||||||
|
- -9.69999981
|
||||||
|
- 7.30000019
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
light:
|
||||||
|
color:
|
||||||
|
- 0.200000003
|
||||||
|
- 0.200000003
|
||||||
|
- 1
|
||||||
|
intensity: 9
|
66
assets/scenes/new_scene.yaml
Normal file
66
assets/scenes/new_scene.yaml
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
entities:
|
||||||
|
- type: cube
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 0
|
||||||
|
- -1.29999995
|
||||||
|
- 0.600000024
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 90
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 0.00999999978
|
||||||
|
- 0.00999999978
|
||||||
|
- 0.00999999978
|
||||||
|
model:
|
||||||
|
modelPath: ./assets/models/sponza.obj
|
||||||
|
globalDiffuseColor:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
globalSpecularColor:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
globalShininess: 32
|
||||||
|
- type: light
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 0
|
||||||
|
- 10
|
||||||
|
- 0
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
light:
|
||||||
|
color:
|
||||||
|
- 0.995098054
|
||||||
|
- 0.878314674
|
||||||
|
- 0.814614594
|
||||||
|
intensity: 2.29999995
|
||||||
|
- type: light
|
||||||
|
transform:
|
||||||
|
position:
|
||||||
|
- 0
|
||||||
|
- -10
|
||||||
|
- 0
|
||||||
|
rotation:
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
scale:
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
- 1
|
||||||
|
light:
|
||||||
|
color:
|
||||||
|
- 0
|
||||||
|
- 2.38418579e-07
|
||||||
|
- 1
|
||||||
|
intensity: 1.79999995
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user