ThreeLab/Engine/engine.cpp

576 lines
18 KiB
C++
Raw Normal View History

2025-04-01 01:25:39 +00:00
#include "Engine.h"
#include <iostream>
2025-04-01 16:45:59 +00:00
#include <glm/gtc/type_ptr.hpp>
2025-04-01 17:22:57 +00:00
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
2025-04-01 20:03:18 +00:00
#include "Entity/Entity.h"
2025-04-01 20:19:00 +00:00
2025-04-01 16:45:59 +00:00
// Static member definitions.
2025-04-02 15:41:31 +00:00
GLFWwindow *Engine::window = nullptr;
2025-04-01 16:45:59 +00:00
GLuint Engine::framebuffer = 0;
GLuint Engine::colorTexture = 0;
GLuint Engine::depthRenderbuffer = 0;
GLuint Engine::shaderProgram = 0;
2025-04-02 16:25:09 +00:00
GLuint Engine::skyboxShaderProgram = 0;
GLuint Engine::skyboxVAO = 0;
GLuint Engine::skyboxVBO = 0;
GLuint Engine::skyboxEBO = 0;
GLuint Engine::skyboxCubemap = 0;
2025-04-01 16:45:59 +00:00
float Engine::rotationAngle = 0.0f;
int Engine::fbWidth = 640;
int Engine::fbHeight = 400;
2025-04-01 01:25:39 +00:00
2025-04-01 20:19:00 +00:00
// Global normal map texture (if needed for legacy models; otherwise each model handles its own)
GLuint normalMapTexture = 0;
2025-04-01 20:03:18 +00:00
2025-04-02 16:25:09 +00:00
unsigned int loadCubemap(const std::vector<std::string>& faces)
{
unsigned int textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
// Disable vertical flipping for cubemaps.
stbi_set_flip_vertically_on_load(false);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++)
{
std::cout << "Loading Cubemap: " << faces[i] << std::endl;
unsigned char *data = stbi_load(faces[i].c_str(), &width, &height, &nrChannels, 0);
if (data)
{
GLenum format = GL_RGB;
if(nrChannels == 1)
format = GL_RED;
else if(nrChannels == 3)
format = GL_RGB;
else if(nrChannels == 4)
format = GL_RGBA;
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
// Set texture parameters
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
return textureID;
}
2025-04-02 15:41:31 +00:00
bool Engine::Init()
{
if (!glfwInit())
{
2025-04-01 16:02:52 +00:00
std::cout << "Failed to initialize GLFW\n";
2025-04-01 01:25:39 +00:00
return false;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
window = glfwCreateWindow(1280, 800, "Engine Window", nullptr, nullptr);
2025-04-02 15:41:31 +00:00
if (!window)
{
2025-04-01 16:02:52 +00:00
std::cout << "Failed to create GLFW window\n";
2025-04-01 01:25:39 +00:00
glfwTerminate();
return false;
}
glfwMakeContextCurrent(window);
2025-04-01 16:45:59 +00:00
glewExperimental = GL_TRUE;
2025-04-02 15:41:31 +00:00
if (glewInit() != GLEW_OK)
{
2025-04-01 16:45:59 +00:00
std::cout << "Failed to initialize GLEW\n";
return false;
}
2025-04-01 01:25:39 +00:00
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
2025-04-01 16:45:59 +00:00
// Create framebuffer.
glGenFramebuffers(1, &framebuffer);
ResizeFramebuffer(fbWidth, fbHeight);
2025-04-01 20:19:00 +00:00
// Setup scene-wide shader (this shader is now used to render all models)
2025-04-02 15:41:31 +00:00
if (!SetupScene())
{
2025-04-01 16:45:59 +00:00
std::cout << "Failed to set up scene\n";
return false;
}
2025-04-01 01:25:39 +00:00
return true;
}
2025-04-02 15:41:31 +00:00
GLFWwindow *Engine::GetWindow()
{
2025-04-01 16:45:59 +00:00
return window;
}
2025-04-02 15:41:31 +00:00
GLuint Engine::GetShader()
{
2025-04-02 01:28:37 +00:00
return shaderProgram;
}
2025-04-01 16:45:59 +00:00
2025-04-02 15:41:31 +00:00
void Engine::ResizeFramebuffer(int width, int height)
{
// Avoid division by zero.
if (height <= 0)
height = 1;
// Define the desired target aspect ratio (e.g., 16:9).
const float targetAspect = 16.0f / 9.0f;
float currentAspect = static_cast<float>(width) / static_cast<float>(height);
2025-04-02 15:41:31 +00:00
// Adjust dimensions to maintain the target aspect ratio.
int newWidth = width;
int newHeight = height;
2025-04-02 15:41:31 +00:00
if (currentAspect > targetAspect)
{
newWidth = static_cast<int>(height * targetAspect);
2025-04-02 15:41:31 +00:00
}
else if (currentAspect < targetAspect)
{
newHeight = static_cast<int>(width / targetAspect);
}
2025-04-02 15:41:31 +00:00
fbWidth = newWidth;
fbHeight = newHeight;
2025-04-02 15:41:31 +00:00
2025-04-01 16:45:59 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Delete old attachments if they exist.
2025-04-02 15:41:31 +00:00
if (colorTexture)
{
2025-04-01 16:45:59 +00:00
glDeleteTextures(1, &colorTexture);
}
2025-04-02 15:41:31 +00:00
if (depthRenderbuffer)
{
2025-04-01 16:45:59 +00:00
glDeleteRenderbuffers(1, &depthRenderbuffer);
}
// Create color texture using GL_RGBA.
glGenTextures(1, &colorTexture);
glBindTexture(GL_TEXTURE_2D, colorTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fbWidth, fbHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTexture, 0);
// Create depth renderbuffer.
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, fbWidth, fbHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
2025-04-02 15:41:31 +00:00
if (status != GL_FRAMEBUFFER_COMPLETE)
{
2025-04-01 16:45:59 +00:00
std::cout << "Framebuffer is not complete! Status: " << status << std::endl;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
2025-04-01 01:25:39 +00:00
}
2025-04-02 15:41:31 +00:00
GLuint Engine::CompileShader(const char *vertexSrc, const char *fragmentSrc)
{
2025-04-01 16:45:59 +00:00
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSrc, nullptr);
glCompileShader(vertexShader);
int success;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
2025-04-02 15:41:31 +00:00
if (!success)
{
2025-04-01 16:45:59 +00:00
char infoLog[512];
glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
std::cout << "Vertex shader compilation failed: " << infoLog << std::endl;
return 0;
}
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSrc, nullptr);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
2025-04-02 15:41:31 +00:00
if (!success)
{
2025-04-01 16:45:59 +00:00
char infoLog[512];
glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
std::cout << "Fragment shader compilation failed: " << infoLog << std::endl;
return 0;
}
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
glLinkProgram(program);
glGetProgramiv(program, GL_LINK_STATUS, &success);
2025-04-02 15:41:31 +00:00
if (!success)
{
2025-04-01 16:45:59 +00:00
char infoLog[512];
glGetProgramInfoLog(program, 512, nullptr, infoLog);
std::cout << "Shader program linking failed: " << infoLog << std::endl;
return 0;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return program;
2025-04-01 01:25:39 +00:00
}
2025-04-02 15:41:31 +00:00
bool Engine::SetupScene()
{
2025-04-02 16:25:09 +00:00
// --- Scene Shader Program ---
2025-04-02 15:41:31 +00:00
const char *vertexShaderSrc = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNormal;
layout(location = 2) in vec2 aTexCoords;
layout(location = 3) in vec3 aTangent;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
out vec3 Tangent;
void main() {
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoords = aTexCoords;
Tangent = mat3(model) * aTangent;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
2025-04-02 16:25:09 +00:00
)";
2025-04-02 15:41:31 +00:00
2025-04-02 16:25:09 +00:00
const char *fragmentShaderSrc = R"(
2025-04-02 15:41:31 +00:00
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
in vec3 Tangent;
uniform vec3 lightPositions[2];
uniform vec3 lightColors[2];
uniform int numLights;
uniform vec3 viewPos;
// Texture uniforms.
uniform sampler2D diffuseTexture;
uniform sampler2D normalMap;
uniform bool useDiffuseTexture;
2025-04-02 16:25:09 +00:00
uniform bool useNormalMap;
// Skybox cubemap for ambient lighting.
uniform samplerCube skybox;
2025-04-02 15:41:31 +00:00
// Material properties.
uniform vec3 materialDiffuse;
uniform vec3 materialSpecular;
uniform float materialShininess;
void main() {
// Optionally sample the diffuse texture.
vec3 diffuseTex = useDiffuseTexture ? texture(diffuseTexture, TexCoords).rgb : vec3(1.0);
2025-04-02 16:25:09 +00:00
// Determine the final normal.
2025-04-02 15:41:31 +00:00
vec3 finalNormal;
if(useNormalMap) {
vec3 normMap = texture(normalMap, TexCoords).rgb;
normMap = normalize(normMap * 2.0 - 1.0);
normMap.z = -normMap.z;
vec3 T = normalize(Tangent);
vec3 B = normalize(cross(Normal, T));
mat3 TBN = mat3(T, B, normalize(Normal));
finalNormal = normalize(TBN * normMap);
} else {
finalNormal = normalize(Normal);
2025-04-01 16:45:59 +00:00
}
2025-04-02 15:41:31 +00:00
2025-04-02 16:25:09 +00:00
// Sample ambient from the skybox cubemap.
vec3 ambient = texture(skybox, finalNormal).rgb * 0.1 * materialDiffuse;
2025-04-02 15:41:31 +00:00
vec3 lighting = ambient;
2025-04-02 16:25:09 +00:00
// Loop through lights.
2025-04-02 15:41:31 +00:00
for(int i = 0; i < numLights; i++) {
vec3 lightDir = normalize(lightPositions[i] - FragPos);
float diff = max(dot(finalNormal, lightDir), 0.0);
vec3 diffuse = diff * materialDiffuse * diffuseTex * lightColors[i];
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;
2025-04-02 01:28:37 +00:00
}
2025-04-02 00:19:53 +00:00
2025-04-02 15:41:31 +00:00
FragColor = vec4(lighting, 1.0);
}
2025-04-02 16:25:09 +00:00
)";
2025-04-02 00:19:53 +00:00
2025-04-01 16:45:59 +00:00
shaderProgram = CompileShader(vertexShaderSrc, fragmentShaderSrc);
2025-04-02 15:41:31 +00:00
if (shaderProgram == 0)
{
2025-04-01 16:45:59 +00:00
return false;
}
2025-04-02 15:41:31 +00:00
2025-04-02 16:25:09 +00:00
// --- Skybox Shader Program ---
const char *skyboxVertexShaderSrc = R"(
#version 330 core
layout(location = 0) in vec3 aPos;
out vec3 TexCoords;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aPos;
// Remove translation by setting w equal to z component.
vec4 pos = projection * view * vec4(aPos, 1.0);
gl_Position = pos.xyww;
}
)";
const char *skyboxFragmentShaderSrc = R"(
#version 330 core
in vec3 TexCoords;
out vec4 FragColor;
uniform samplerCube skybox;
void main()
{
FragColor = texture(skybox, TexCoords);
}
)";
skyboxShaderProgram = CompileShader(skyboxVertexShaderSrc, skyboxFragmentShaderSrc);
if (skyboxShaderProgram == 0)
{
return false;
}
// Define the full cube (36 vertices) for the skybox.
float skyboxVertices[] = {
// positions
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f,
-1.0f, -1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, -1.0f,
-1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
-1.0f, -1.0f, 1.0f,
1.0f, -1.0f, 1.0f};
unsigned int skyboxVAO, skyboxVBO;
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glBindVertexArray(0);
std::vector<std::string> faces{
"assets/skybox/right.jpg",
"assets/skybox/left.jpg",
"assets/skybox/top.jpg",
"assets/skybox/bottom.jpg",
"assets/skybox/front.jpg",
"assets/skybox/back.jpg"
};
skyboxCubemap = loadCubemap(faces);
2025-04-01 16:45:59 +00:00
return true;
}
2025-04-02 16:25:09 +00:00
ImTextureID Engine::RenderScene(const glm::mat4 &view, const glm::mat4 &projection,
const glm::vec3 &viewPos, const std::vector<Entity *> &entities)
{
2025-04-01 16:45:59 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, fbWidth, fbHeight);
glEnable(GL_DEPTH_TEST);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2025-04-02 16:25:09 +00:00
// --- Draw Scene Objects ---
2025-04-01 16:45:59 +00:00
glUseProgram(shaderProgram);
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniform3f(glGetUniformLocation(shaderProgram, "viewPos"), viewPos.x, viewPos.y, viewPos.z);
2025-04-02 16:25:09 +00:00
// Bind skybox cubemap for ambient sampling in the scene shader.
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxCubemap);
glUniform1i(glGetUniformLocation(shaderProgram, "skybox"), 2);
// Set up lights (up to 2).
glm::vec3 lightPositions[2] = {glm::vec3(0.0f), glm::vec3(0.0f)};
glm::vec3 lightColors[2] = {glm::vec3(1.0f), glm::vec3(1.0f)};
2025-04-01 20:03:18 +00:00
int lightCount = 0;
2025-04-02 16:25:09 +00:00
for (auto e : entities)
{
if (e->GetType() == EntityType::LIGHT && lightCount < 2)
{
2025-04-01 20:03:18 +00:00
lightPositions[lightCount] = e->transform.position;
2025-04-02 16:25:09 +00:00
if (e->lightComponent)
{
2025-04-01 20:03:18 +00:00
lightColors[lightCount] = e->lightComponent->color * e->lightComponent->intensity;
}
lightCount++;
}
}
glUniform1i(glGetUniformLocation(shaderProgram, "numLights"), lightCount);
2025-04-02 16:25:09 +00:00
if (lightCount > 0)
{
2025-04-01 20:03:18 +00:00
glUniform3fv(glGetUniformLocation(shaderProgram, "lightPositions"), lightCount, glm::value_ptr(lightPositions[0]));
glUniform3fv(glGetUniformLocation(shaderProgram, "lightColors"), lightCount, glm::value_ptr(lightColors[0]));
}
2025-04-01 16:45:59 +00:00
2025-04-01 20:19:00 +00:00
// Render each cube entity using its ModelComponent.
2025-04-02 16:25:09 +00:00
for (auto e : entities)
{
if (e->GetType() == EntityType::CUBE && e->modelComponent)
{
2025-04-02 15:41:31 +00:00
glm::mat4 modelMatrix = e->transform.GetMatrix();
glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix));
2025-04-02 16:25:09 +00:00
for (const auto &mesh : e->modelComponent->meshes)
{
2025-04-02 15:41:31 +00:00
glUniform3fv(glGetUniformLocation(shaderProgram, "materialDiffuse"), 1, glm::value_ptr(mesh.diffuseColor));
glUniform3fv(glGetUniformLocation(shaderProgram, "materialSpecular"), 1, glm::value_ptr(mesh.specularColor));
glUniform1f(glGetUniformLocation(shaderProgram, "materialShininess"), mesh.shininess);
2025-04-02 16:25:09 +00:00
if (mesh.diffuseTexture != 0)
{
2025-04-02 15:41:31 +00:00
glUniform1i(glGetUniformLocation(shaderProgram, "useDiffuseTexture"), 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, mesh.diffuseTexture);
glUniform1i(glGetUniformLocation(shaderProgram, "diffuseTexture"), 0);
2025-04-02 16:25:09 +00:00
}
else
{
2025-04-02 15:41:31 +00:00
glUniform1i(glGetUniformLocation(shaderProgram, "useDiffuseTexture"), 0);
}
2025-04-02 16:25:09 +00:00
if (mesh.normalTexture != 0)
{
2025-04-02 15:41:31 +00:00
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), 1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, mesh.normalTexture);
glUniform1i(glGetUniformLocation(shaderProgram, "normalMap"), 1);
2025-04-02 16:25:09 +00:00
}
else
{
2025-04-02 15:41:31 +00:00
glUniform1i(glGetUniformLocation(shaderProgram, "useNormalMap"), 0);
}
glBindVertexArray(mesh.VAO);
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mesh.indices.size()), GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
2025-04-01 20:03:18 +00:00
}
}
2025-04-01 16:45:59 +00:00
2025-04-02 16:25:09 +00:00
// Draw Skybox
glDepthFunc(GL_LEQUAL); // Allow skybox fragments to pass depth test.
glUseProgram(skyboxShaderProgram);
glm::mat4 viewNoTrans = glm::mat4(glm::mat3(view));
glUniformMatrix4fv(glGetUniformLocation(skyboxShaderProgram, "view"), 1, GL_FALSE, glm::value_ptr(viewNoTrans));
glUniformMatrix4fv(glGetUniformLocation(skyboxShaderProgram, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// Bind skybox VAO and cubemap texture.
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxCubemap);
glUniform1i(glGetUniformLocation(skyboxShaderProgram, "skybox"), 0);
// Draw the cube (36 vertices)
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // Restore default depth function.
2025-04-01 16:45:59 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return (ImTextureID)(intptr_t)colorTexture;
}
2025-04-02 15:41:31 +00:00
ImTextureID Engine::GetFinalRenderingTexture()
{
2025-04-01 16:45:59 +00:00
return (ImTextureID)(intptr_t)colorTexture;
}
2025-04-02 15:41:31 +00:00
void Engine::Shutdown()
{
2025-04-01 16:45:59 +00:00
glDeleteProgram(shaderProgram);
glDeleteFramebuffers(1, &framebuffer);
glDeleteTextures(1, &colorTexture);
2025-04-01 17:22:57 +00:00
glDeleteTextures(1, &normalMapTexture);
2025-04-01 16:45:59 +00:00
glDeleteRenderbuffers(1, &depthRenderbuffer);
glfwDestroyWindow(window);
glfwTerminate();
2025-04-01 01:25:39 +00:00
}