tried to add assimp (spoilers, it did not go well, so hey! now we have separate fiels now.)
This commit is contained in:
587
src/Rendering.cpp
Normal file
587
src/Rendering.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
#include "Rendering.h"
|
||||
#include "Camera.h"
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "../include/ThirdParty/tiny_obj_loader.h"
|
||||
|
||||
// Global OBJ loader instance
|
||||
OBJLoader g_objLoader;
|
||||
|
||||
// Cube vertex data
|
||||
float vertices[] = {
|
||||
// Back face (z = -0.5f)
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
|
||||
|
||||
// Front face (z = 0.5f)
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
|
||||
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
|
||||
|
||||
// Left face (x = -0.5f)
|
||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
|
||||
// Right face (x = 0.5f)
|
||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
|
||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
|
||||
|
||||
// Bottom face (y = -0.5f)
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
|
||||
|
||||
// Top face (y = 0.5f)
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
|
||||
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
std::vector<float> generateSphere(int segments, int rings) {
|
||||
std::vector<float> vertices;
|
||||
|
||||
for (int ring = 0; ring <= rings; ring++) {
|
||||
float theta = ring * PI / rings;
|
||||
float sinTheta = sin(theta);
|
||||
float cosTheta = cos(theta);
|
||||
|
||||
for (int seg = 0; seg <= segments; seg++) {
|
||||
float phi = seg * 2.0f * PI / segments;
|
||||
float sinPhi = sin(phi);
|
||||
float cosPhi = cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta;
|
||||
float y = cosTheta;
|
||||
float z = sinPhi * sinTheta;
|
||||
|
||||
// Position
|
||||
vertices.push_back(x * 0.5f);
|
||||
vertices.push_back(y * 0.5f);
|
||||
vertices.push_back(z * 0.5f);
|
||||
|
||||
// Normal (same as position for unit sphere)
|
||||
vertices.push_back(x);
|
||||
vertices.push_back(y);
|
||||
vertices.push_back(z);
|
||||
|
||||
// Texcoord
|
||||
vertices.push_back((float)seg / segments);
|
||||
vertices.push_back((float)ring / rings);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> triangulated;
|
||||
int stride = segments + 1;
|
||||
for (int ring = 0; ring < rings; ring++) {
|
||||
for (int seg = 0; seg < segments; seg++) {
|
||||
int current = ring * stride + seg;
|
||||
int next = current + stride;
|
||||
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[current * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[next * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(current + 1) * 8 + i]);
|
||||
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(current + 1) * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[next * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(next + 1) * 8 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
return triangulated;
|
||||
}
|
||||
|
||||
std::vector<float> generateCapsule(int segments, int rings) {
|
||||
std::vector<float> vertices;
|
||||
float cylinderHeight = 0.5f;
|
||||
float radius = 0.25f;
|
||||
|
||||
// Top hemisphere
|
||||
for (int ring = 0; ring <= rings / 2; ring++) {
|
||||
float theta = ring * PI / rings;
|
||||
float sinTheta = sin(theta);
|
||||
float cosTheta = cos(theta);
|
||||
|
||||
for (int seg = 0; seg <= segments; seg++) {
|
||||
float phi = seg * 2.0f * PI / segments;
|
||||
float sinPhi = sin(phi);
|
||||
float cosPhi = cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta * radius;
|
||||
float y = cosTheta * radius + cylinderHeight;
|
||||
float z = sinPhi * sinTheta * radius;
|
||||
|
||||
vertices.push_back(x);
|
||||
vertices.push_back(y);
|
||||
vertices.push_back(z);
|
||||
|
||||
glm::vec3 normal = glm::normalize(glm::vec3(x, y - cylinderHeight, z));
|
||||
vertices.push_back(normal.x);
|
||||
vertices.push_back(normal.y);
|
||||
vertices.push_back(normal.z);
|
||||
|
||||
vertices.push_back((float)seg / segments);
|
||||
vertices.push_back((float)ring / (rings / 2));
|
||||
}
|
||||
}
|
||||
|
||||
// Cylinder body
|
||||
for (int i = 0; i <= 1; i++) {
|
||||
float y = i == 0 ? cylinderHeight : -cylinderHeight;
|
||||
for (int seg = 0; seg <= segments; seg++) {
|
||||
float phi = seg * 2.0f * PI / segments;
|
||||
float x = cos(phi) * radius;
|
||||
float z = sin(phi) * radius;
|
||||
|
||||
vertices.push_back(x);
|
||||
vertices.push_back(y);
|
||||
vertices.push_back(z);
|
||||
|
||||
glm::vec3 normal = glm::normalize(glm::vec3(x, 0.0f, z));
|
||||
vertices.push_back(normal.x);
|
||||
vertices.push_back(normal.y);
|
||||
vertices.push_back(normal.z);
|
||||
|
||||
vertices.push_back((float)seg / segments);
|
||||
vertices.push_back(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom hemisphere
|
||||
for (int ring = rings / 2; ring <= rings; ring++) {
|
||||
float theta = ring * PI / rings;
|
||||
float sinTheta = sin(theta);
|
||||
float cosTheta = cos(theta);
|
||||
|
||||
for (int seg = 0; seg <= segments; seg++) {
|
||||
float phi = seg * 2.0f * PI / segments;
|
||||
float sinPhi = sin(phi);
|
||||
float cosPhi = cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta * radius;
|
||||
float y = cosTheta * radius - cylinderHeight;
|
||||
float z = sinPhi * sinTheta * radius;
|
||||
|
||||
vertices.push_back(x);
|
||||
vertices.push_back(y);
|
||||
vertices.push_back(z);
|
||||
|
||||
glm::vec3 normal = glm::normalize(glm::vec3(x, y + cylinderHeight, z));
|
||||
vertices.push_back(normal.x);
|
||||
vertices.push_back(normal.y);
|
||||
vertices.push_back(normal.z);
|
||||
|
||||
vertices.push_back((float)seg / segments);
|
||||
vertices.push_back((float)ring / rings);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> triangulated;
|
||||
int stride = segments + 1;
|
||||
int totalRings = rings + 3;
|
||||
|
||||
for (int ring = 0; ring < totalRings - 1; ring++) {
|
||||
for (int seg = 0; seg < segments; seg++) {
|
||||
int current = ring * stride + seg;
|
||||
int next = current + stride;
|
||||
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[current * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[next * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(current + 1) * 8 + i]);
|
||||
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(current + 1) * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[next * 8 + i]);
|
||||
for (int i = 0; i < 8; i++) triangulated.push_back(vertices[(next + 1) * 8 + i]);
|
||||
}
|
||||
}
|
||||
|
||||
return triangulated;
|
||||
}
|
||||
|
||||
// Mesh implementation
|
||||
Mesh::Mesh(const float* vertexData, size_t dataSizeBytes) {
|
||||
vertexCount = dataSizeBytes / (8 * sizeof(float));
|
||||
|
||||
glGenVertexArrays(1, &VAO);
|
||||
glGenBuffers(1, &VBO);
|
||||
|
||||
glBindVertexArray(VAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, dataSizeBytes, vertexData, GL_STATIC_DRAW);
|
||||
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
Mesh::~Mesh() {
|
||||
glDeleteVertexArrays(1, &VAO);
|
||||
glDeleteBuffers(1, &VBO);
|
||||
}
|
||||
|
||||
void Mesh::draw() const {
|
||||
glBindVertexArray(VAO);
|
||||
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
// OBJLoader implementation
|
||||
int OBJLoader::loadOBJ(const std::string& filepath, std::string& errorMsg) {
|
||||
// Check if already loaded
|
||||
for (size_t i = 0; i < loadedMeshes.size(); i++) {
|
||||
if (loadedMeshes[i].path == filepath) {
|
||||
return static_cast<int>(i);
|
||||
}
|
||||
}
|
||||
|
||||
tinyobj::attrib_t attrib;
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string warn, err;
|
||||
|
||||
std::string baseDir = fs::path(filepath).parent_path().string();
|
||||
if (!baseDir.empty()) baseDir += "/";
|
||||
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err,
|
||||
filepath.c_str(), baseDir.c_str());
|
||||
|
||||
if (!warn.empty()) {
|
||||
errorMsg += "Warning: " + warn + "\n";
|
||||
}
|
||||
|
||||
if (!err.empty()) {
|
||||
errorMsg += "Error: " + err + "\n";
|
||||
}
|
||||
|
||||
if (!ret || shapes.empty()) {
|
||||
errorMsg += "Failed to load OBJ file: " + filepath;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::vector<float> vertices;
|
||||
bool hasNormalsInFile = !attrib.normals.empty();
|
||||
|
||||
int faceCount = 0;
|
||||
for (const auto& shape : shapes) {
|
||||
faceCount += static_cast<int>(shape.mesh.num_face_vertices.size());
|
||||
}
|
||||
|
||||
for (const auto& shape : shapes) {
|
||||
size_t indexOffset = 0;
|
||||
for (size_t f = 0; f < shape.mesh.num_face_vertices.size(); f++) {
|
||||
int fv = shape.mesh.num_face_vertices[f];
|
||||
|
||||
struct TempVertex {
|
||||
glm::vec3 pos;
|
||||
glm::vec2 uv;
|
||||
glm::vec3 normal;
|
||||
bool hasNormal = false;
|
||||
};
|
||||
std::vector<TempVertex> faceVerts;
|
||||
|
||||
for (int v = 0; v < fv; v++) {
|
||||
tinyobj::index_t idx = shape.mesh.indices[indexOffset + v];
|
||||
|
||||
TempVertex tv;
|
||||
tv.pos.x = attrib.vertices[3 * size_t(idx.vertex_index) + 0];
|
||||
tv.pos.y = attrib.vertices[3 * size_t(idx.vertex_index) + 1];
|
||||
tv.pos.z = attrib.vertices[3 * size_t(idx.vertex_index) + 2];
|
||||
|
||||
if (idx.texcoord_index >= 0 && !attrib.texcoords.empty()) {
|
||||
tv.uv.x = attrib.texcoords[2 * size_t(idx.texcoord_index) + 0];
|
||||
tv.uv.y = attrib.texcoords[2 * size_t(idx.texcoord_index) + 1];
|
||||
} else {
|
||||
tv.uv = glm::vec2(0.0f);
|
||||
}
|
||||
|
||||
if (idx.normal_index >= 0 && hasNormalsInFile) {
|
||||
tv.normal.x = attrib.normals[3 * size_t(idx.normal_index) + 0];
|
||||
tv.normal.y = attrib.normals[3 * size_t(idx.normal_index) + 1];
|
||||
tv.normal.z = attrib.normals[3 * size_t(idx.normal_index) + 2];
|
||||
tv.hasNormal = true;
|
||||
}
|
||||
|
||||
faceVerts.push_back(tv);
|
||||
}
|
||||
|
||||
if (!hasNormalsInFile && fv >= 3) {
|
||||
glm::vec3 v0 = faceVerts[0].pos;
|
||||
glm::vec3 v1 = faceVerts[1].pos;
|
||||
glm::vec3 v2 = faceVerts[2].pos;
|
||||
glm::vec3 faceNormal = glm::normalize(glm::cross(v1 - v0, v2 - v0));
|
||||
|
||||
for (auto& tv : faceVerts) {
|
||||
tv.normal = faceNormal;
|
||||
tv.hasNormal = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int v = 1; v < fv - 1; v++) {
|
||||
const TempVertex* tri[3] = { &faceVerts[0], &faceVerts[v], &faceVerts[v+1] };
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
vertices.push_back(tri[i]->pos.x);
|
||||
vertices.push_back(tri[i]->pos.y);
|
||||
vertices.push_back(tri[i]->pos.z);
|
||||
vertices.push_back(tri[i]->normal.x);
|
||||
vertices.push_back(tri[i]->normal.y);
|
||||
vertices.push_back(tri[i]->normal.z);
|
||||
vertices.push_back(tri[i]->uv.x);
|
||||
vertices.push_back(tri[i]->uv.y);
|
||||
}
|
||||
}
|
||||
|
||||
indexOffset += fv;
|
||||
}
|
||||
}
|
||||
|
||||
if (vertices.empty()) {
|
||||
errorMsg += "No vertices found in OBJ file";
|
||||
return -1;
|
||||
}
|
||||
|
||||
LoadedMesh loaded;
|
||||
loaded.path = filepath;
|
||||
loaded.name = fs::path(filepath).stem().string();
|
||||
loaded.mesh = std::make_unique<Mesh>(vertices.data(), vertices.size() * sizeof(float));
|
||||
loaded.vertexCount = static_cast<int>(vertices.size() / 8);
|
||||
loaded.faceCount = faceCount;
|
||||
loaded.hasNormals = hasNormalsInFile;
|
||||
loaded.hasTexCoords = !attrib.texcoords.empty();
|
||||
|
||||
loadedMeshes.push_back(std::move(loaded));
|
||||
return static_cast<int>(loadedMeshes.size() - 1);
|
||||
}
|
||||
|
||||
Mesh* OBJLoader::getMesh(int index) {
|
||||
if (index < 0 || index >= static_cast<int>(loadedMeshes.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
return loadedMeshes[index].mesh.get();
|
||||
}
|
||||
|
||||
const OBJLoader::LoadedMesh* OBJLoader::getMeshInfo(int index) const {
|
||||
if (index < 0 || index >= static_cast<int>(loadedMeshes.size())) {
|
||||
return nullptr;
|
||||
}
|
||||
return &loadedMeshes[index];
|
||||
}
|
||||
|
||||
// Renderer implementation
|
||||
Renderer::~Renderer() {
|
||||
delete shader;
|
||||
delete texture1;
|
||||
delete texture2;
|
||||
delete cubeMesh;
|
||||
delete sphereMesh;
|
||||
delete capsuleMesh;
|
||||
delete skybox;
|
||||
if (framebuffer) glDeleteFramebuffers(1, &framebuffer);
|
||||
if (viewportTexture) glDeleteTextures(1, &viewportTexture);
|
||||
if (rbo) glDeleteRenderbuffers(1, &rbo);
|
||||
}
|
||||
|
||||
void Renderer::initialize() {
|
||||
shader = new Shader("Resources/Shaders/vert.glsl", "Resources/Shaders/frag.glsl");
|
||||
if (shader->ID == 0) {
|
||||
std::cerr << "Shader compilation failed!\n";
|
||||
delete shader;
|
||||
shader = nullptr;
|
||||
throw std::runtime_error("Shader error");
|
||||
}
|
||||
|
||||
texture1 = new Texture("Resources/Textures/container.jpg");
|
||||
texture2 = new Texture("Resources/Textures/awesomeface.png");
|
||||
|
||||
cubeMesh = new Mesh(vertices, sizeof(vertices));
|
||||
|
||||
auto sphereVerts = generateSphere();
|
||||
sphereMesh = new Mesh(sphereVerts.data(), sphereVerts.size() * sizeof(float));
|
||||
|
||||
auto capsuleVerts = generateCapsule();
|
||||
capsuleMesh = new Mesh(capsuleVerts.data(), capsuleVerts.size() * sizeof(float));
|
||||
|
||||
skybox = new Skybox();
|
||||
|
||||
setupFBO();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
|
||||
void Renderer::setupFBO() {
|
||||
glGenFramebuffers(1, &framebuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
glGenTextures(1, &viewportTexture);
|
||||
glBindTexture(GL_TEXTURE_2D, viewportTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, currentWidth, currentHeight, 0, GL_RGB, 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, viewportTexture, 0);
|
||||
|
||||
glGenRenderbuffers(1, &rbo);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, currentWidth, currentHeight);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
std::cerr << "Framebuffer setup failed!\n";
|
||||
}
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void Renderer::resize(int w, int h) {
|
||||
if (w <= 0 || h <= 0 || (w == currentWidth && h == currentHeight)) return;
|
||||
|
||||
currentWidth = w;
|
||||
currentHeight = h;
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, viewportTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, currentWidth, currentHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, currentWidth, currentHeight);
|
||||
|
||||
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
|
||||
std::cerr << "Framebuffer incomplete after resize!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::beginRender(const glm::mat4& view, const glm::mat4& proj) {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
|
||||
glViewport(0, 0, currentWidth, currentHeight);
|
||||
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
shader->use();
|
||||
shader->setMat4("view", view);
|
||||
shader->setMat4("projection", proj);
|
||||
texture1->Bind(GL_TEXTURE0);
|
||||
texture2->Bind(GL_TEXTURE1);
|
||||
shader->setInt("texture1", 0);
|
||||
shader->setInt("texture2", 1);
|
||||
}
|
||||
|
||||
void Renderer::renderSkybox(const glm::mat4& view, const glm::mat4& proj) {
|
||||
if (skybox) {
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
skybox->draw(glm::value_ptr(view), glm::value_ptr(proj));
|
||||
glDepthFunc(GL_LESS);
|
||||
|
||||
shader->use();
|
||||
shader->setMat4("view", view);
|
||||
shader->setMat4("projection", proj);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderObject(const SceneObject& obj) {
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
model = glm::translate(model, obj.position);
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.x), glm::vec3(1, 0, 0));
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.y), glm::vec3(0, 1, 0));
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.z), glm::vec3(0, 0, 1));
|
||||
model = glm::scale(model, obj.scale);
|
||||
|
||||
shader->setMat4("model", model);
|
||||
|
||||
switch (obj.type) {
|
||||
case ObjectType::Cube:
|
||||
cubeMesh->draw();
|
||||
break;
|
||||
case ObjectType::Sphere:
|
||||
sphereMesh->draw();
|
||||
break;
|
||||
case ObjectType::Capsule:
|
||||
capsuleMesh->draw();
|
||||
break;
|
||||
case ObjectType::OBJMesh:
|
||||
if (obj.meshId >= 0) {
|
||||
Mesh* objMesh = g_objLoader.getMesh(obj.meshId);
|
||||
if (objMesh) {
|
||||
objMesh->draw();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderScene(const Camera& camera, const std::vector<SceneObject>& sceneObjects) {
|
||||
shader->use();
|
||||
shader->setMat4("view", camera.getViewMatrix());
|
||||
shader->setMat4("projection", glm::perspective(glm::radians(FOV), (float)currentWidth / (float)currentHeight, NEAR_PLANE, FAR_PLANE));
|
||||
shader->setVec3("lightPos", glm::vec3(4.0f, 6.0f, 4.0f));
|
||||
shader->setVec3("lightColor", glm::vec3(1.0f, 1.0f, 1.0f));
|
||||
shader->setFloat("ambientStrength", 0.25f);
|
||||
shader->setFloat("specularStrength", 0.8f);
|
||||
shader->setFloat("shininess", 64.0f);
|
||||
shader->setFloat("mixAmount", 0.3f);
|
||||
|
||||
texture1->Bind(0);
|
||||
texture2->Bind(1);
|
||||
|
||||
for (const auto& obj : sceneObjects) {
|
||||
glm::mat4 model = glm::mat4(1.0f);
|
||||
model = glm::translate(model, obj.position);
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||
model = glm::rotate(model, glm::radians(obj.rotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
model = glm::scale(model, obj.scale);
|
||||
|
||||
shader->setMat4("model", model);
|
||||
|
||||
Mesh* meshToDraw = nullptr;
|
||||
if (obj.type == ObjectType::Cube) meshToDraw = cubeMesh;
|
||||
else if (obj.type == ObjectType::Sphere) meshToDraw = sphereMesh;
|
||||
else if (obj.type == ObjectType::Capsule) meshToDraw = capsuleMesh;
|
||||
else if (obj.type == ObjectType::OBJMesh && obj.meshId != -1) {
|
||||
meshToDraw = g_objLoader.getMesh(obj.meshId);
|
||||
}
|
||||
|
||||
if (meshToDraw) {
|
||||
meshToDraw->draw();
|
||||
}
|
||||
}
|
||||
|
||||
if (skybox) {
|
||||
glm::mat4 view = camera.getViewMatrix();
|
||||
glm::mat4 proj = glm::perspective(glm::radians(FOV),
|
||||
(float)currentWidth / currentHeight,
|
||||
NEAR_PLANE, FAR_PLANE);
|
||||
|
||||
skybox->draw(glm::value_ptr(view), glm::value_ptr(proj));
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
void Renderer::endRender() {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
Reference in New Issue
Block a user