Added some scene editor stuff
This commit is contained in:
parent
fdddafe980
commit
82d561c921
@ -2,12 +2,54 @@
|
|||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "imgui_impl_glfw.h"
|
#include "imgui_impl_glfw.h"
|
||||||
#include "imgui_impl_opengl3.h"
|
#include "imgui_impl_opengl3.h"
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdio>
|
||||||
|
#include "../Engine/Entity/Entity.h"
|
||||||
|
#include "../Engine/Components/TransformComponent.h"
|
||||||
|
#include "../Engine/Components/ModelComponent.h"
|
||||||
|
#include "../Engine/Components/LightComponent.h"
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
// Simple editor camera.
|
using std::vector;
|
||||||
|
|
||||||
|
// Global light icon texture.
|
||||||
|
GLuint g_LightIconTex = 0;
|
||||||
|
ImTextureID g_LightIconImTex = 0;
|
||||||
|
|
||||||
|
// Helper function to load a texture.
|
||||||
|
bool LoadIconTexture(const char* filepath, GLuint &texOut, ImTextureID &imTexOut) {
|
||||||
|
int w, h, channels;
|
||||||
|
unsigned char* data = stbi_load(filepath, &w, &h, &channels, 0);
|
||||||
|
if (!data) {
|
||||||
|
printf("Failed to load icon texture: %s\n", filepath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Overwrite loaded data with white pixels (all channels set to 255)
|
||||||
|
int total = w * h * channels;
|
||||||
|
for (int i = 0; i < total; i++) {
|
||||||
|
data[i] = 255;
|
||||||
|
}
|
||||||
|
glGenTextures(1, &texOut);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texOut);
|
||||||
|
GLenum format = (channels == 3) ? GL_RGB : GL_RGBA;
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, data);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
stbi_image_free(data);
|
||||||
|
imTexOut = (ImTextureID)(intptr_t)texOut;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Editor camera.
|
||||||
struct EditorCamera {
|
struct EditorCamera {
|
||||||
glm::vec3 position = glm::vec3(0.0f, 0.0f, 5.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;
|
||||||
float speed = 5.0f;
|
float speed = 5.0f;
|
||||||
@ -25,7 +67,6 @@ void ProcessEditorCamera(GLFWwindow* window, float deltaTime) {
|
|||||||
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)
|
||||||
@ -34,7 +75,6 @@ void ProcessEditorCamera(GLFWwindow* window, float deltaTime) {
|
|||||||
editorCamera.position -= right * editorCamera.speed * deltaTime;
|
editorCamera.position -= right * editorCamera.speed * 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;
|
||||||
@ -57,20 +97,56 @@ void ProcessEditorCamera(GLFWwindow* window, float deltaTime) {
|
|||||||
int main() {
|
int main() {
|
||||||
if (!Engine::Init())
|
if (!Engine::Init())
|
||||||
return 1;
|
return 1;
|
||||||
|
// Load the light icon.
|
||||||
|
LoadIconTexture("assets/icons/light.png", g_LightIconTex, g_LightIconImTex);
|
||||||
|
|
||||||
// Setup ImGui.
|
|
||||||
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);
|
||||||
|
|
||||||
float lastFrameTime = (float)glfwGetTime();
|
vector<Entity*> entities;
|
||||||
|
// Create two cube entities.
|
||||||
|
Entity* cube1 = new Entity(EntityType::CUBE);
|
||||||
|
cube1->transform.position = glm::vec3(-2.0f, 0.0f, 0.0f);
|
||||||
|
cube1->modelComponent = new ModelComponent();
|
||||||
|
cube1->modelComponent->diffuseColor = glm::vec3(0.8f, 0.2f, 0.2f);
|
||||||
|
cube1->modelComponent->specularColor = glm::vec3(1.0f, 1.0f, 1.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.
|
||||||
|
Entity* light1 = new Entity(EntityType::LIGHT);
|
||||||
|
light1->transform.position = glm::vec3(0.0f, 10.0f, 0.0f);
|
||||||
|
light1->lightComponent = new LightComponent();
|
||||||
|
light1->lightComponent->color = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||||
|
light1->lightComponent->intensity = 1.5f;
|
||||||
|
|
||||||
|
Entity* light2 = new Entity(EntityType::LIGHT);
|
||||||
|
light2->transform.position = glm::vec3(0.0f, -10.0f, 0.0f);
|
||||||
|
light2->lightComponent = new LightComponent();
|
||||||
|
light2->lightComponent->color = glm::vec3(0.2f, 0.2f, 1.0f);
|
||||||
|
light2->lightComponent->intensity = 1.0f;
|
||||||
|
|
||||||
|
entities.push_back(cube1);
|
||||||
|
entities.push_back(cube2);
|
||||||
|
entities.push_back(light1);
|
||||||
|
entities.push_back(light2);
|
||||||
|
|
||||||
|
Entity* selectedEntity = nullptr;
|
||||||
|
int selectedIndex = -1;
|
||||||
|
|
||||||
|
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;
|
||||||
@ -78,45 +154,71 @@ int main() {
|
|||||||
|
|
||||||
ProcessEditorCamera(Engine::GetWindow(), deltaTime);
|
ProcessEditorCamera(Engine::GetWindow(), deltaTime);
|
||||||
|
|
||||||
// Update editor camera projection based on the window size.
|
|
||||||
int winWidth, winHeight;
|
int winWidth, winHeight;
|
||||||
glfwGetFramebufferSize(Engine::GetWindow(), &winWidth, &winHeight);
|
glfwGetFramebufferSize(Engine::GetWindow(), &winWidth, &winHeight);
|
||||||
editorCamera.projection = glm::perspective(glm::radians(45.0f), (float)winWidth / winHeight, 0.1f, 100.0f);
|
editorCamera.projection = glm::perspective(glm::radians(45.0f), (float)winWidth / winHeight, 0.1f, 100.0f);
|
||||||
|
|
||||||
// Offscreen rendering: Resize framebuffer and render scene.
|
|
||||||
Engine::ResizeFramebuffer(winWidth, winHeight);
|
Engine::ResizeFramebuffer(winWidth, winHeight);
|
||||||
ImTextureID offscreenTexture = Engine::RenderScene(editorCamera.view, editorCamera.projection, editorCamera.position);
|
ImTextureID offscreenTexture = Engine::RenderScene(editorCamera.view, editorCamera.projection, editorCamera.position, entities);
|
||||||
|
|
||||||
// Clear the default framebuffer background.
|
|
||||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
glViewport(0, 0, winWidth, winHeight);
|
glViewport(0, 0, winWidth, winHeight);
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Clear with black (or choose any color).
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// Start a single ImGui frame.
|
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
|
||||||
// Create a full-viewport dock space.
|
|
||||||
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
|
||||||
|
|
||||||
|
// Left Panel: Entity List.
|
||||||
// Create an "Editor Panel" window.
|
ImGui::Begin("Entity List");
|
||||||
ImGui::Begin("Editor Panel");
|
for (int i = 0; i < entities.size(); i++) {
|
||||||
ImGui::Text("Welcome to the Editor!");
|
char label[32];
|
||||||
// (Additional UI elements can go here.)
|
sprintf(label, "Entity %d", i);
|
||||||
|
if (ImGui::Selectable(label, selectedIndex == i))
|
||||||
|
selectedIndex = i;
|
||||||
|
if (ImGui::IsItemClicked()) {
|
||||||
|
selectedEntity = entities[i];
|
||||||
|
selectedIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// Create a "Rendered Output" window.
|
// Right Panel: Entity Inspector.
|
||||||
|
ImGui::Begin("Entity Inspector");
|
||||||
|
if (selectedEntity) {
|
||||||
|
ImGui::Text("Transform");
|
||||||
|
ImGui::DragFloat3("Position", glm::value_ptr(selectedEntity->transform.position), 0.1f);
|
||||||
|
ImGui::DragFloat3("Rotation", glm::value_ptr(selectedEntity->transform.rotation), 0.5f);
|
||||||
|
ImGui::DragFloat3("Scale", glm::value_ptr(selectedEntity->transform.scale), 0.1f);
|
||||||
|
if (selectedEntity->GetType() == EntityType::CUBE && selectedEntity->modelComponent) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Model Properties");
|
||||||
|
ImGui::ColorEdit3("Diffuse", glm::value_ptr(selectedEntity->modelComponent->diffuseColor));
|
||||||
|
ImGui::ColorEdit3("Specular", glm::value_ptr(selectedEntity->modelComponent->specularColor));
|
||||||
|
ImGui::DragFloat("Shininess", &selectedEntity->modelComponent->shininess, 1.0f, 1.0f, 128.0f);
|
||||||
|
}
|
||||||
|
if (selectedEntity->GetType() == EntityType::LIGHT && selectedEntity->lightComponent) {
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("Light Properties");
|
||||||
|
ImGui::ColorEdit3("Light Color", glm::value_ptr(selectedEntity->lightComponent->color));
|
||||||
|
ImGui::DragFloat("Intensity", &selectedEntity->lightComponent->intensity, 0.1f, 0.0f, 10.0f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::Text("No entity selected.");
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
// Bottom Panel: Rendered Output.
|
||||||
ImGui::Begin("Rendered Output");
|
ImGui::Begin("Rendered Output");
|
||||||
// Get available region size for the rendered output.
|
|
||||||
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
ImVec2 viewportSize = ImGui::GetContentRegionAvail();
|
||||||
// Display the offscreen texture. The UVs are flipped to correct the upside-down image.
|
|
||||||
ImGui::Image(offscreenTexture, viewportSize, ImVec2(0,1), ImVec2(1,0));
|
ImGui::Image(offscreenTexture, viewportSize, ImVec2(0,1), ImVec2(1,0));
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
// Finalize and render the ImGui frame.
|
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
@ -124,6 +226,9 @@ int main() {
|
|||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto e : entities)
|
||||||
|
delete e;
|
||||||
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui_ImplGlfw_Shutdown();
|
ImGui_ImplGlfw_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
9
Engine/Components/LightComponent.cpp
Normal file
9
Engine/Components/LightComponent.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "LightComponent.h"
|
||||||
|
|
||||||
|
LightComponent::LightComponent()
|
||||||
|
: color(1.0f, 1.0f, 1.0f),
|
||||||
|
intensity(1.0f) {
|
||||||
|
}
|
||||||
|
|
||||||
|
LightComponent::~LightComponent() {
|
||||||
|
}
|
16
Engine/Components/LightComponent.h
Normal file
16
Engine/Components/LightComponent.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef LIGHT_COMPONENT_H
|
||||||
|
#define LIGHT_COMPONENT_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
class LightComponent {
|
||||||
|
public:
|
||||||
|
LightComponent();
|
||||||
|
~LightComponent();
|
||||||
|
|
||||||
|
// Light properties.
|
||||||
|
glm::vec3 color;
|
||||||
|
float intensity;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // LIGHT_COMPONENT_H
|
10
Engine/Components/ModelComponent.cpp
Normal file
10
Engine/Components/ModelComponent.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "ModelComponent.h"
|
||||||
|
|
||||||
|
ModelComponent::ModelComponent()
|
||||||
|
: diffuseColor(1.0f, 1.0f, 1.0f),
|
||||||
|
specularColor(1.0f, 1.0f, 1.0f),
|
||||||
|
shininess(32.0f) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelComponent::~ModelComponent() {
|
||||||
|
}
|
17
Engine/Components/ModelComponent.h
Normal file
17
Engine/Components/ModelComponent.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef MODEL_COMPONENT_H
|
||||||
|
#define MODEL_COMPONENT_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
class ModelComponent {
|
||||||
|
public:
|
||||||
|
ModelComponent();
|
||||||
|
~ModelComponent();
|
||||||
|
|
||||||
|
// Material properties.
|
||||||
|
glm::vec3 diffuseColor;
|
||||||
|
glm::vec3 specularColor;
|
||||||
|
float shininess;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MODEL_COMPONENT_H
|
18
Engine/Components/TransformComponent.cpp
Normal file
18
Engine/Components/TransformComponent.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#include "TransformComponent.h"
|
||||||
|
|
||||||
|
TransformComponent::TransformComponent()
|
||||||
|
: position(0.0f), rotation(0.0f), scale(1.0f) {
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformComponent::~TransformComponent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 TransformComponent::GetMatrix() const {
|
||||||
|
glm::mat4 trans = glm::translate(glm::mat4(1.0f), position);
|
||||||
|
glm::mat4 rotX = glm::rotate(glm::mat4(1.0f), glm::radians(rotation.x), glm::vec3(1,0,0));
|
||||||
|
glm::mat4 rotY = glm::rotate(glm::mat4(1.0f), glm::radians(rotation.y), glm::vec3(0,1,0));
|
||||||
|
glm::mat4 rotZ = glm::rotate(glm::mat4(1.0f), glm::radians(rotation.z), glm::vec3(0,0,1));
|
||||||
|
glm::mat4 rot = rotZ * rotY * rotX;
|
||||||
|
glm::mat4 scl = glm::scale(glm::mat4(1.0f), scale);
|
||||||
|
return trans * rot * scl;
|
||||||
|
}
|
20
Engine/Components/TransformComponent.h
Normal file
20
Engine/Components/TransformComponent.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef TRANSFORM_COMPONENT_H
|
||||||
|
#define TRANSFORM_COMPONENT_H
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
class TransformComponent {
|
||||||
|
public:
|
||||||
|
TransformComponent();
|
||||||
|
~TransformComponent();
|
||||||
|
|
||||||
|
glm::vec3 position;
|
||||||
|
glm::vec3 rotation; // Euler angles (pitch, yaw, roll) in degrees.
|
||||||
|
glm::vec3 scale;
|
||||||
|
|
||||||
|
// Returns the world transform matrix.
|
||||||
|
glm::mat4 GetMatrix() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TRANSFORM_COMPONENT_H
|
@ -2,6 +2,7 @@
|
|||||||
#define ENGINE_H
|
#define ENGINE_H
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
@ -14,6 +15,8 @@
|
|||||||
#include "Components/Component.h"
|
#include "Components/Component.h"
|
||||||
#include "Components/Camera.h"
|
#include "Components/Camera.h"
|
||||||
|
|
||||||
|
// Forward declaration of Entity.
|
||||||
|
class Entity;
|
||||||
|
|
||||||
class Engine {
|
class Engine {
|
||||||
public:
|
public:
|
||||||
@ -22,17 +25,14 @@ public:
|
|||||||
|
|
||||||
// Initializes GLFW, GLEW, and sets up the main window and offscreen framebuffer.
|
// Initializes GLFW, GLEW, and sets up the main window and offscreen framebuffer.
|
||||||
static bool Init();
|
static bool Init();
|
||||||
|
|
||||||
// Returns the main GLFW window.
|
// Returns the main GLFW window.
|
||||||
static GLFWwindow* GetWindow();
|
static GLFWwindow* GetWindow();
|
||||||
|
|
||||||
// Clean up resources and shutdown GLFW.
|
// Clean up resources and shutdown GLFW.
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
||||||
// Offscreen render function that uses the provided camera parameters.
|
// Offscreen render function that uses the provided camera parameters and renders the scene
|
||||||
// It renders the scene (e.g., a spinning cube with red lighting) offscreen
|
// (with entities) offscreen. Returns the color attachment as an ImTextureID.
|
||||||
// and returns its color attachment as an ImTextureID.
|
static ImTextureID RenderScene(const glm::mat4 &view, const glm::mat4 &projection, const glm::vec3 &viewPos, const std::vector<Entity*>& entities);
|
||||||
static ImTextureID RenderScene(const glm::mat4 &view, const glm::mat4 &projection, const glm::vec3 &viewPos);
|
|
||||||
|
|
||||||
// Resizes the offscreen framebuffer to the given dimensions.
|
// Resizes the offscreen framebuffer to the given dimensions.
|
||||||
static void ResizeFramebuffer(int width, int height);
|
static void ResizeFramebuffer(int width, int height);
|
||||||
@ -40,29 +40,35 @@ public:
|
|||||||
// Retrieves the final rendered texture.
|
// Retrieves the final rendered texture.
|
||||||
static ImTextureID GetFinalRenderingTexture();
|
static ImTextureID GetFinalRenderingTexture();
|
||||||
|
|
||||||
|
// --- Billboard Rendering for 3D Icons ---
|
||||||
|
// Billboard shader and VAO for drawing icons (e.g., light icons) as billboards in 3D space.
|
||||||
|
static GLuint billboardShaderProgram;
|
||||||
|
static GLuint billboardVAO;
|
||||||
|
// Sets up billboard resources.
|
||||||
|
static bool SetupBillboard();
|
||||||
|
// Draws a billboarded icon at the given world position with a specified size.
|
||||||
|
static void DrawIconIn3DSpace(const glm::vec3 &worldPos, const glm::vec2 &size, ImTextureID texture, const glm::mat4 &view, const glm::mat4 &projection);
|
||||||
|
// Iterates over entities and draws icons for those of the appropriate type.
|
||||||
|
static void DrawIconsIn3DSpace(const std::vector<Entity*>& entities, const glm::mat4 &view, const glm::mat4 &projection, ImTextureID iconTexture);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Offscreen framebuffer and its attachments.
|
// Offscreen framebuffer and its attachments.
|
||||||
static GLuint framebuffer;
|
static GLuint framebuffer;
|
||||||
static GLuint colorTexture;
|
static GLuint colorTexture;
|
||||||
static GLuint depthRenderbuffer;
|
static GLuint depthRenderbuffer;
|
||||||
|
|
||||||
// Geometry for a simple cube.
|
// Geometry for a simple cube.
|
||||||
static GLuint cubeVAO;
|
static GLuint cubeVAO;
|
||||||
static GLuint cubeVBO;
|
static GLuint cubeVBO;
|
||||||
|
|
||||||
// Shader program used for rendering the scene.
|
// Shader program used for rendering the scene.
|
||||||
static GLuint shaderProgram;
|
static GLuint shaderProgram;
|
||||||
|
// Rotation angle for the spinning cube (or animated models).
|
||||||
// Rotation angle for the spinning cube.
|
|
||||||
static float rotationAngle;
|
static float rotationAngle;
|
||||||
|
|
||||||
// Current offscreen framebuffer dimensions.
|
// Current offscreen framebuffer dimensions.
|
||||||
static int fbWidth;
|
static int fbWidth;
|
||||||
static int fbHeight;
|
static int fbHeight;
|
||||||
|
|
||||||
// Helper function to compile and link shaders.
|
// Helper function to compile and link shaders.
|
||||||
static GLuint CompileShader(const char* vertexSrc, const char* fragmentSrc);
|
static GLuint CompileShader(const char* vertexSrc, const char* fragmentSrc);
|
||||||
|
|
||||||
// Sets up cube geometry and shader (called during initialization).
|
// Sets up cube geometry and shader (called during initialization).
|
||||||
static bool SetupScene();
|
static bool SetupScene();
|
||||||
};
|
};
|
||||||
|
20
Engine/Entity/Entity.cpp
Normal file
20
Engine/Entity/Entity.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "Entity.h"
|
||||||
|
|
||||||
|
Entity::Entity(EntityType type)
|
||||||
|
: type(type), modelComponent(nullptr), lightComponent(nullptr) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity::~Entity() {
|
||||||
|
if(modelComponent) {
|
||||||
|
delete modelComponent;
|
||||||
|
modelComponent = nullptr;
|
||||||
|
}
|
||||||
|
if(lightComponent) {
|
||||||
|
delete lightComponent;
|
||||||
|
lightComponent = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EntityType Entity::GetType() const {
|
||||||
|
return type;
|
||||||
|
}
|
30
Engine/Entity/Entity.h
Normal file
30
Engine/Entity/Entity.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef ENTITY_H
|
||||||
|
#define ENTITY_H
|
||||||
|
|
||||||
|
#include "../Components/TransformComponent.h"
|
||||||
|
#include "../Components/ModelComponent.h"
|
||||||
|
#include "../Components/LightComponent.h"
|
||||||
|
|
||||||
|
enum class EntityType {
|
||||||
|
CUBE,
|
||||||
|
LIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
class Entity {
|
||||||
|
public:
|
||||||
|
Entity(EntityType type);
|
||||||
|
virtual ~Entity();
|
||||||
|
|
||||||
|
EntityType GetType() const;
|
||||||
|
|
||||||
|
// Components.
|
||||||
|
TransformComponent transform;
|
||||||
|
// Optional components (set to non-null if the entity has them).
|
||||||
|
ModelComponent* modelComponent;
|
||||||
|
LightComponent* lightComponent;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EntityType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ENTITY_H
|
@ -3,7 +3,7 @@
|
|||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "stb_image.h"
|
#include "stb_image.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;
|
||||||
@ -18,6 +18,9 @@ int Engine::fbHeight = 400;
|
|||||||
|
|
||||||
GLuint normalMapTexture = 0; // Global texture for the normal map
|
GLuint normalMapTexture = 0; // Global texture for the normal map
|
||||||
|
|
||||||
|
GLuint Engine::billboardShaderProgram = 0;
|
||||||
|
GLuint Engine::billboardVAO = 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";
|
||||||
@ -153,6 +156,111 @@ GLuint Engine::CompileShader(const char* vertexSrc, const char* fragmentSrc) {
|
|||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool Engine::SetupBillboard() {
|
||||||
|
// Simple billboard vertex shader.
|
||||||
|
const char* billboardVertexSrc = R"(
|
||||||
|
#version 330 core
|
||||||
|
layout(location = 0) in vec3 aPos;
|
||||||
|
layout(location = 1) in vec2 aTexCoords;
|
||||||
|
|
||||||
|
uniform mat4 model;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
out vec2 TexCoords;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
TexCoords = aTexCoords;
|
||||||
|
gl_Position = projection * view * model * vec4(aPos, 1.0);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
// Simple billboard fragment shader.
|
||||||
|
const char* billboardFragmentSrc = R"(
|
||||||
|
#version 330 core
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 TexCoords;
|
||||||
|
uniform sampler2D billboardTexture;
|
||||||
|
void main() {
|
||||||
|
FragColor = texture(billboardTexture, TexCoords);
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
billboardShaderProgram = CompileShader(billboardVertexSrc, billboardFragmentSrc);
|
||||||
|
if (billboardShaderProgram == 0) return false;
|
||||||
|
|
||||||
|
// Define a quad (two triangles) for the billboard.
|
||||||
|
float quadVertices[] = {
|
||||||
|
// positions // texcoords
|
||||||
|
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||||
|
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
|
||||||
|
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
||||||
|
|
||||||
|
-0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
|
||||||
|
0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
|
||||||
|
0.5f, 0.5f, 0.0f, 1.0f, 1.0f
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint VBO;
|
||||||
|
glGenVertexArrays(1, &billboardVAO);
|
||||||
|
glGenBuffers(1, &VBO);
|
||||||
|
glBindVertexArray(billboardVAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
|
||||||
|
// position attribute.
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
// texcoord attribute.
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glDeleteBuffers(1, &VBO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Engine::DrawIconIn3DSpace(const glm::vec3 &worldPos, const glm::vec2 &size, ImTextureID texture, const glm::mat4 &view, const glm::mat4 &projection) {
|
||||||
|
// Compute billboard matrix (extract inverse rotation from view).
|
||||||
|
glm::mat4 billboard = glm::mat4(1.0f);
|
||||||
|
billboard[0] = glm::vec4(view[0][0], view[1][0], view[2][0], 0.0f);
|
||||||
|
billboard[1] = glm::vec4(view[0][1], view[1][1], view[2][1], 0.0f);
|
||||||
|
billboard[2] = glm::vec4(view[0][2], view[1][2], view[2][2], 0.0f);
|
||||||
|
billboard = glm::transpose(billboard);
|
||||||
|
|
||||||
|
glm::mat4 model = glm::translate(glm::mat4(1.0f), worldPos);
|
||||||
|
model *= billboard;
|
||||||
|
model = glm::scale(model, glm::vec3(size, 1.0f));
|
||||||
|
|
||||||
|
glUseProgram(billboardShaderProgram);
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(billboardShaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(billboardShaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(billboardShaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
|
||||||
|
|
||||||
|
// Bind icon texture.
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)texture);
|
||||||
|
glUniform1i(glGetUniformLocation(billboardShaderProgram, "billboardTexture"), 0);
|
||||||
|
|
||||||
|
// Disable depth test so icon appears on top.
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glBindVertexArray(billboardVAO);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glEnable(GL_DEPTH_TEST); // Re-enable depth testing.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Engine::DrawIconsIn3DSpace(const std::vector<Entity*>& entities, const glm::mat4 &view, const glm::mat4 &projection, ImTextureID iconTexture) {
|
||||||
|
for(auto e : entities) {
|
||||||
|
if(e->GetType() == EntityType::LIGHT) {
|
||||||
|
// Draw a billboard icon at the light's world position.
|
||||||
|
DrawIconIn3DSpace(e->transform.position, glm::vec2(1.0f, 1.0f), iconTexture, view, projection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Engine::SetupScene() {
|
bool Engine::SetupScene() {
|
||||||
// Updated cube vertices: each vertex has:
|
// Updated cube vertices: each vertex has:
|
||||||
// position (3), normal (3), texcoord (2), tangent (3) = 11 floats per vertex.
|
// position (3), normal (3), texcoord (2), tangent (3) = 11 floats per vertex.
|
||||||
@ -226,84 +334,91 @@ bool Engine::SetupScene() {
|
|||||||
glEnableVertexAttribArray(3);
|
glEnableVertexAttribArray(3);
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
// Vertex shader source.
|
|
||||||
const char* vertexShaderSrc = R"(
|
const char* vertexShaderSrc = R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
layout(location = 0) in vec3 aPos;
|
layout(location = 0) in vec3 aPos;
|
||||||
layout(location = 1) in vec3 aNormal;
|
layout(location = 1) in vec3 aNormal;
|
||||||
layout(location = 2) in vec2 aTexCoords;
|
layout(location = 2) in vec2 aTexCoords;
|
||||||
layout(location = 3) in vec3 aTangent;
|
layout(location = 3) in vec3 aTangent;
|
||||||
|
|
||||||
uniform mat4 model;
|
uniform mat4 model;
|
||||||
uniform mat4 view;
|
uniform mat4 view;
|
||||||
uniform mat4 projection;
|
uniform mat4 projection;
|
||||||
|
|
||||||
out vec3 FragPos;
|
out vec3 FragPos;
|
||||||
out vec3 Normal;
|
out vec3 Normal;
|
||||||
out vec2 TexCoords;
|
out vec2 TexCoords;
|
||||||
out vec3 Tangent;
|
out vec3 Tangent;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
FragPos = vec3(model * vec4(aPos, 1.0));
|
FragPos = vec3(model * vec4(aPos, 1.0));
|
||||||
Normal = mat3(transpose(inverse(model))) * aNormal;
|
Normal = mat3(transpose(inverse(model))) * aNormal;
|
||||||
TexCoords = aTexCoords;
|
TexCoords = aTexCoords;
|
||||||
Tangent = mat3(model) * aTangent;
|
Tangent = mat3(model) * aTangent;
|
||||||
gl_Position = projection * view * vec4(FragPos, 1.0);
|
gl_Position = projection * view * vec4(FragPos, 1.0);
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
// Fragment shader source with normal mapping.
|
|
||||||
const char* fragmentShaderSrc = R"(
|
const char* fragmentShaderSrc = R"(
|
||||||
#version 330 core
|
#version 330 core
|
||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
in vec3 FragPos;
|
in vec3 FragPos;
|
||||||
in vec3 Normal;
|
in vec3 Normal;
|
||||||
in vec2 TexCoords;
|
in vec2 TexCoords;
|
||||||
in vec3 Tangent;
|
in vec3 Tangent;
|
||||||
|
|
||||||
uniform vec3 lightPos;
|
uniform vec3 lightPositions[2];
|
||||||
|
uniform vec3 lightColors[2];
|
||||||
|
uniform int numLights;
|
||||||
uniform vec3 viewPos;
|
uniform vec3 viewPos;
|
||||||
uniform sampler2D normalMap;
|
uniform sampler2D normalMap;
|
||||||
|
|
||||||
|
// Material properties.
|
||||||
|
uniform vec3 materialDiffuse;
|
||||||
|
uniform vec3 materialSpecular;
|
||||||
|
uniform float materialShininess;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// Obtain the normal from the normal map in range [0,1] and remap to [-1,1].
|
|
||||||
vec3 normMap = texture(normalMap, TexCoords).rgb;
|
vec3 normMap = texture(normalMap, TexCoords).rgb;
|
||||||
normMap = normalize(normMap);
|
normMap = normalize(normMap * 2.0 - 1.0);
|
||||||
|
normMap.z = -normMap.z;
|
||||||
// Calculate TBN matrix. For simplicity, compute bitangent as cross(normal, tangent).
|
|
||||||
vec3 N = normalize(Normal);
|
vec3 N = normalize(Normal);
|
||||||
vec3 T = normalize(Tangent);
|
vec3 T = normalize(Tangent);
|
||||||
vec3 B = normalize(cross(N, T));
|
vec3 B = normalize(cross(N, T));
|
||||||
mat3 TBN = mat3(T, B, N);
|
mat3 TBN = mat3(T, B, N);
|
||||||
vec3 perturbedNormal = normalize(TBN * normMap);
|
vec3 perturbedNormal = normalize(TBN * normMap);
|
||||||
|
|
||||||
// Ambient.
|
vec3 ambient = 0.1 * materialDiffuse;
|
||||||
float ambientStrength = 0.5;
|
vec3 lighting = ambient;
|
||||||
vec3 ambient = ambientStrength * vec3(1.0, 0.0, 1.0);
|
for(int i = 0; i < numLights; i++) {
|
||||||
|
vec3 lightDir = normalize(lightPositions[i] - FragPos);
|
||||||
// Diffuse.
|
float diff = max(dot(perturbedNormal, lightDir), 0.0);
|
||||||
vec3 lightDir = normalize(lightPos - FragPos);
|
vec3 diffuse = diff * materialDiffuse * lightColors[i];
|
||||||
float diff = max(dot(perturbedNormal, lightDir), 0.0);
|
|
||||||
vec3 diffuse = diff * vec3(1.0, 1.0, 1.0);
|
vec3 viewDir = normalize(viewPos - FragPos);
|
||||||
|
vec3 reflectDir = reflect(-lightDir, perturbedNormal);
|
||||||
// Specular.
|
float spec = pow(max(dot(viewDir, reflectDir), 0.0), materialShininess);
|
||||||
float specularStrength = 0.2;
|
vec3 specular = materialSpecular * spec * lightColors[i];
|
||||||
vec3 viewDir = normalize(viewPos - FragPos);
|
|
||||||
vec3 reflectDir = reflect(-lightDir, perturbedNormal);
|
lighting += diffuse + specular;
|
||||||
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
|
}
|
||||||
vec3 specular = specularStrength * spec * vec3(1.0);
|
FragColor = vec4(lighting, 1.0);
|
||||||
|
|
||||||
vec3 result = ambient + diffuse + specular;
|
|
||||||
FragColor = vec4(result, 1.0);
|
|
||||||
}
|
}
|
||||||
)";
|
)";
|
||||||
|
|
||||||
|
|
||||||
shaderProgram = CompileShader(vertexShaderSrc, fragmentShaderSrc);
|
shaderProgram = CompileShader(vertexShaderSrc, fragmentShaderSrc);
|
||||||
if (shaderProgram == 0) {
|
if (shaderProgram == 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!SetupBillboard()) {
|
||||||
|
std::cout << "Failed to set up billboard resources." << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Load normal map from "./normal.png"
|
// Load normal map from "./normal.png"
|
||||||
int texWidth, texHeight, texChannels;
|
int texWidth, texHeight, texChannels;
|
||||||
unsigned char* data = stbi_load("./normal.jpg", &texWidth, &texHeight, &texChannels, 0);
|
unsigned char* data = stbi_load("./normal.jpg", &texWidth, &texHeight, &texChannels, 0);
|
||||||
@ -330,7 +445,7 @@ bool Engine::SetupScene() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projection, const glm::vec3 &viewPos) {
|
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);
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
@ -342,24 +457,50 @@ 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);
|
||||||
|
|
||||||
rotationAngle += 0.001f;
|
// Gather lights (up to 2) from entities of type LIGHT.
|
||||||
glm::mat4 model = glm::rotate(glm::mat4(1.0f), rotationAngle, glm::vec3(1,1,0));
|
glm::vec3 lightPositions[2] = { glm::vec3(0.0f), glm::vec3(0.0f) };
|
||||||
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(model));
|
glm::vec3 lightColors[2] = { glm::vec3(1.0f), glm::vec3(1.0f) };
|
||||||
|
int lightCount = 0;
|
||||||
|
for (auto e : entities) {
|
||||||
|
if (e->GetType() == EntityType::LIGHT && lightCount < 2) {
|
||||||
|
lightPositions[lightCount] = e->transform.position;
|
||||||
|
if (e->lightComponent) {
|
||||||
|
lightColors[lightCount] = e->lightComponent->color * e->lightComponent->intensity;
|
||||||
|
}
|
||||||
|
lightCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glUniform1i(glGetUniformLocation(shaderProgram, "numLights"), lightCount);
|
||||||
|
if (lightCount > 0) {
|
||||||
|
glUniform3fv(glGetUniformLocation(shaderProgram, "lightPositions"), lightCount, glm::value_ptr(lightPositions[0]));
|
||||||
|
glUniform3fv(glGetUniformLocation(shaderProgram, "lightColors"), lightCount, glm::value_ptr(lightColors[0]));
|
||||||
|
}
|
||||||
|
|
||||||
glUniform3f(glGetUniformLocation(shaderProgram, "lightPos"), 0.0f, 20.0f, 0.0f);
|
// Bind the normal map on texture unit 1.
|
||||||
|
|
||||||
// Activate texture unit 1 and bind the normal map.
|
|
||||||
glActiveTexture(GL_TEXTURE1);
|
glActiveTexture(GL_TEXTURE1);
|
||||||
glBindTexture(GL_TEXTURE_2D, normalMapTexture);
|
glBindTexture(GL_TEXTURE_2D, normalMapTexture);
|
||||||
|
// (Assumes that the uniform "normalMap" is already set to 1.)
|
||||||
|
|
||||||
glBindVertexArray(cubeVAO);
|
// Render cube entities.
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 36);
|
for (auto e : entities) {
|
||||||
|
if (e->GetType() == EntityType::CUBE && e->modelComponent) {
|
||||||
|
glm::mat4 modelMatrix = e->transform.GetMatrix();
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
|
||||||
|
glUniform3fv(glGetUniformLocation(shaderProgram, "materialDiffuse"), 1, glm::value_ptr(e->modelComponent->diffuseColor));
|
||||||
|
glUniform3fv(glGetUniformLocation(shaderProgram, "materialSpecular"), 1, glm::value_ptr(e->modelComponent->specularColor));
|
||||||
|
glUniform1f(glGetUniformLocation(shaderProgram, "materialShininess"), e->modelComponent->shininess);
|
||||||
|
glBindVertexArray(cubeVAO);
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
||||||
|
}
|
||||||
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
2
Makefile
2
Makefile
@ -6,7 +6,7 @@ CXXFLAGS := -std=c++20 -Wall -Wextra -O2 -I/c/msys64/mingw64/include -Ivendor/im
|
|||||||
LDFLAGS := -Llib -lglfw3 -lopengl32 -lglew32 -lglu32
|
LDFLAGS := -Llib -lglfw3 -lopengl32 -lglew32 -lglu32
|
||||||
|
|
||||||
# Source and build directories (including vendor folder)
|
# Source and build directories (including vendor folder)
|
||||||
SRC_DIRS := . Editor Engine vendor/imgui-docking Engine/Components
|
SRC_DIRS := . Editor Engine vendor/imgui-docking Engine/Components Engine/Entity
|
||||||
BUILD_DIR := build
|
BUILD_DIR := build
|
||||||
|
|
||||||
# Find all source files
|
# Find all source files
|
||||||
|
BIN
Three-Labs.exe
BIN
Three-Labs.exe
Binary file not shown.
BIN
assets/icons/light.png
Normal file
BIN
assets/icons/light.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
Binary file not shown.
BIN
build/Engine/Components/LightComponent.o
Normal file
BIN
build/Engine/Components/LightComponent.o
Normal file
Binary file not shown.
BIN
build/Engine/Components/ModelComponent.o
Normal file
BIN
build/Engine/Components/ModelComponent.o
Normal file
Binary file not shown.
BIN
build/Engine/Components/TransformComponent.o
Normal file
BIN
build/Engine/Components/TransformComponent.o
Normal file
Binary file not shown.
BIN
build/Engine/Entity/Entity.o
Normal file
BIN
build/Engine/Entity/Entity.o
Normal file
Binary file not shown.
Binary file not shown.
31
imgui.ini
31
imgui.ini
@ -9,14 +9,13 @@ Size=400,400
|
|||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Window][Editor Panel]
|
[Window][Editor Panel]
|
||||||
Pos=0,0
|
Size=272,800
|
||||||
Size=333,800
|
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000001,0
|
DockId=0x00000001,0
|
||||||
|
|
||||||
[Window][Rendered Output]
|
[Window][Rendered Output]
|
||||||
Pos=335,0
|
Pos=247,0
|
||||||
Size=945,800
|
Size=772,800
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
DockId=0x00000002,0
|
DockId=0x00000002,0
|
||||||
|
|
||||||
@ -25,8 +24,24 @@ Pos=176,231
|
|||||||
Size=680,444
|
Size=680,444
|
||||||
Collapsed=0
|
Collapsed=0
|
||||||
|
|
||||||
[Docking][Data]
|
[Window][Entity Inspector]
|
||||||
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,0 Size=1280,800 Split=X Selected=0xB6999AB4
|
Pos=1021,0
|
||||||
DockNode ID=0x00000001 Parent=0x08BD597D SizeRef=333,800 Selected=0x5098C5B2
|
Size=259,800
|
||||||
DockNode ID=0x00000002 Parent=0x08BD597D SizeRef=945,800 CentralNode=1 Selected=0xB6999AB4
|
Collapsed=0
|
||||||
|
DockId=0x00000004,0
|
||||||
|
|
||||||
|
[Window][Entity List]
|
||||||
|
Pos=0,0
|
||||||
|
Size=245,800
|
||||||
|
Collapsed=0
|
||||||
|
DockId=0x00000005,0
|
||||||
|
|
||||||
|
[Docking][Data]
|
||||||
|
DockSpace ID=0x08BD597D Window=0x1BBC0F80 Pos=0,0 Size=1280,800 Split=X Selected=0xB6999AB4
|
||||||
|
DockNode ID=0x00000005 Parent=0x08BD597D SizeRef=245,800 Selected=0x5A1EAB5B
|
||||||
|
DockNode ID=0x00000006 Parent=0x08BD597D SizeRef=1033,800 Split=X
|
||||||
|
DockNode ID=0x00000003 Parent=0x00000006 SizeRef=772,800 Split=X
|
||||||
|
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=272,800 Selected=0x5098C5B2
|
||||||
|
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1006,800 CentralNode=1 Selected=0xB6999AB4
|
||||||
|
DockNode ID=0x00000004 Parent=0x00000006 SizeRef=259,800 Selected=0x82A01C92
|
||||||
|
|
||||||
|
28
test.cap
Normal file
28
test.cap
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"rdocCaptureSettings": 1,
|
||||||
|
"settings": {
|
||||||
|
"autoStart": false,
|
||||||
|
"commandLine": "",
|
||||||
|
"environment": [
|
||||||
|
],
|
||||||
|
"executable": "C:\\Users\\spenc\\OneDrive\\Documents\\GitHub\\Test\\ThreeLab\\Three-Labs.exe",
|
||||||
|
"inject": false,
|
||||||
|
"numQueuedFrames": 0,
|
||||||
|
"options": {
|
||||||
|
"allowFullscreen": true,
|
||||||
|
"allowVSync": true,
|
||||||
|
"apiValidation": false,
|
||||||
|
"captureAllCmdLists": false,
|
||||||
|
"captureCallstacks": false,
|
||||||
|
"captureCallstacksOnlyDraws": false,
|
||||||
|
"debugOutputMute": true,
|
||||||
|
"delayForDebugger": 0,
|
||||||
|
"hookIntoChildren": false,
|
||||||
|
"refAllResources": false,
|
||||||
|
"softMemoryLimit": 0,
|
||||||
|
"verifyBufferAccess": false
|
||||||
|
},
|
||||||
|
"queuedFrameCap": 0,
|
||||||
|
"workingDir": ""
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user