Draws cubes instead of triangles now

This commit is contained in:
0x01FE committed 2025-11-09 23:04:07 -06:00
1 parent 2067d5c18c
commit 45e2a5f4cc
441 files changed
+67481 -78

No files matched your search

+100
View File
@@ -0,0 +1,100 @@
#ifndef CAMERA_H
#define CAMERA_H
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
const float CAMERA_HEIGHT = 1.7f;
const float GRAVITY = 18.6f; // Should be in m/s^2 but it doesn't really work out with 9.8 so we double it
class Camera
{
public:
glm::vec3 position;
glm::vec3 target;
glm::vec3 direction;
glm::vec3 up;
// Movement
glm::vec3 horizontal_velocity;
glm::vec3 forward_velocity;
glm::vec3 vertical_velocity;
float speed;
glm::vec3 worldUp;
Camera(float speed, glm::vec3 pos)
{
this->speed = speed;
this->vertical_velocity = glm::vec3(0.0f);
this->horizontal_velocity = glm::vec3(0.0f);
this->forward_velocity = glm::vec3(0.0f);
this->position = pos;
this->target = glm::vec3(0.0f, 0.0f, -1.0f);
this->direction = glm::normalize(this->position);
this->worldUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 right = glm::normalize(glm::cross(up, this->direction));
this->up = glm::cross(this->direction, right);
}
Camera(glm::vec3 pos, glm::vec3 target, float speed)
{
this->speed = speed;
this->vertical_velocity = glm::vec3(0.0f);
this->horizontal_velocity = glm::vec3(0.0f);
this->forward_velocity = glm::vec3(0.0f);
this->position = pos;
this->target = target;
this->direction = glm::normalize(this->position - this->target);
this->worldUp = glm::vec3(0.0f, 1.0f, 0.0f);
glm::vec3 right = glm::normalize(glm::cross(up, this->direction));
this->up = glm::cross(this->direction, right);
}
glm::mat4 getView()
{
glm::mat4 v = glm::lookAt(this->position,
this->target + this->position,
this->worldUp);
v = glm::translate(v, glm::vec3(0.0f, -CAMERA_HEIGHT, 0.0f));
return v;
}
void move(float time) // time passed in seconds since last move
{
bool in_air = this->position.y > 0;
if (this->position.y > 0)
this->vertical_velocity.y -= (GRAVITY * time); // no way! physics reference?
glm::vec3 velocity = this->forward_velocity + this->horizontal_velocity + this->vertical_velocity;
glm::vec3 movement = (velocity * time);
this->position += movement;
// Don't want to clip into the ground right
if (this->position.y <= 0 && in_air)
{
this->position.y = 0.0f;
this->vertical_velocity.y = 0.0f;
}
}
};
#endif
+282
View File
@@ -0,0 +1,282 @@
#include "Object3D.h"
#include <fstream>
#include <iostream>
#include <strstream>
Object3D::Object3D() = default;
Object3D::Object3D(const std::string &file_path)
{
this->loadFromOBJ(file_path);
}
bool Object3D::loadFromOBJ(const std::string& file_path)
{
std::ifstream f(file_path);
if (!f.is_open())
return false;
std::vector<float> temp_vertices;
std::vector<unsigned int> temp_indices;
std::vector<float> temp_normals;
while (!f.eof())
{
char line[128];
f.getline(line, 128);
std::string l(line);
// std::cout << "LINE: " << l << std::endl;
if (line[0] == 'f')
{
l.erase(0, 2); // Erase the "f "
size_t pos1 = 0;
std::string token1;
// Split by space
while ((pos1 = l.find(' ')) != std::string::npos)
{
token1 = l.substr(0, pos1);
int face_vert;
if (l.find("//") != std::string::npos)
{
size_t pos2 = 0;
std::string token2;
bool face = true;
while ((pos2 = token1.find("//")) != std::string::npos)
{
token2 = token1.substr(0, pos2);
// std::cout << token1 << std::endl;
if (face)
{
face_vert = std::stoi(token2) - 1;
temp_indices.push_back(face_vert);
face = false;
}
token1.erase(0, pos2 + 2);
}
// The Normal paired with the face is here
if (!face) {
// std::cout << "thisg" << std::endl;
int face_normal = std::stoi(token1) - 1;
// std::cout << "f " << face_vert + 1 << "//" << face_normal + 1 << std::endl;
bool VBO_el_found = false;
// If Vertice AND correct normal are already in VBO buffer just refernce that
for (unsigned int i = 0; i < this->VBO_buffer.size(); i += 6)
{
bool vert_equal = true;
bool normal_equal = true;
// Since each Vertice & Normal are 3 elements we need to do a little looping
for (int a = 0; a < 3; a++)
{
if (this->VBO_buffer[i + a] != temp_vertices[(face_vert * 3) + a]) {
vert_equal = false;
break;
}
}
for (int a = 3; a < 6; a++)
{
if (this->VBO_buffer[i + a] != temp_normals[(face_normal * 3) + a - 3]) {
normal_equal = false;
break;
}
}
if (vert_equal && normal_equal) {
this->EBO_buffer.push_back(i / 6);
VBO_el_found = true;
}
}
// If not we need to add it to the VBO buffer
if (!VBO_el_found)
{
// Again we need to add all three elements for each
for (int a = 0; a < 3; a++)
this->VBO_buffer.push_back(temp_vertices[face_vert * 3 + a]);
for (int a = 0; a < 3; a++)
this->VBO_buffer.push_back(temp_normals[face_normal * 3 + a]);
this->EBO_buffer.push_back(this->VBO_buffer.size() / 6 - 1);
}
}
// std::cout << l << std::endl;
// temp_indices.push_back(std::stoi(token1) - 1);
}
l.erase(0, pos1 + 1);
}
// std::cout << "thing" << std::endl;
// std::cout << l << std::endl;
if (l.find("//") != std::string::npos)
{
size_t pos2 = 0;
std::string token2;
bool face = true;
int face_vert;
while ((pos2 = l.find("//")) != std::string::npos)
{
token2 = l.substr(0, pos2);
face_vert = std::stoi(token2) - 1;
if (face)
{
temp_indices.push_back(face_vert);
face = false;
}
// Else case if I want to add normals for the faces
l.erase(0, pos2 + 2);
}
// The Normal paired with the face is here
if (!face) {
// std::cout << "thisg" << std::endl;
int face_normal = std::stoi(l) - 1;
// std::cout << "f " << face_vert + 1 << "//" << face_normal + 1 << std::endl;
bool VBO_el_found = false;
// If Vertice AND correct normal are already in VBO buffer just refernce that
for (unsigned int i = 0; i < this->VBO_buffer.size(); i += 6)
{
bool vert_equal = true;
bool normal_equal = true;
// Since each Vertice & Normal are 3 elements we need to do a little looping
for (int a = 0; a < 3; a++)
{
if (this->VBO_buffer[i + a] != temp_vertices[(face_vert * 3) + a]) {
vert_equal = false;
break;
}
}
for (int a = 3; a < 6; a++)
{
if (this->VBO_buffer[i + a] != temp_normals[(face_normal * 3) + a - 3]) {
normal_equal = false;
break;
}
}
if (vert_equal && normal_equal) {
this->EBO_buffer.push_back(i / 6);
VBO_el_found = true;
}
}
// If not we need to add it to the VBO buffer
if (!VBO_el_found)
{
// Again we need to add all three elements for each
for (int a = 0; a < 3; a++)
this->VBO_buffer.push_back(temp_vertices[face_vert * 3 + a]);
for (int a = 0; a < 3; a++)
this->VBO_buffer.push_back(temp_normals[face_normal * 3 + a]);
this->EBO_buffer.push_back(this->VBO_buffer.size() / 6 - 1);
}
}
// std::cout << l << std::endl;
// temp_indices.push_back(std::stoi(token1) - 1);
}
}
else if (line[0] == 'v')
{
size_t pos1 = 0;
std::string token1;
bool normal = line[1] == 'n';
if (normal)
{
l.erase(0, 3); // Get rid of the "vn "
}
else
{
l.erase(0, 2); // Get rid of the "v "
}
// Split by space
while ((pos1 = l.find(' ')) != std::string::npos)
{
token1 = l.substr(0, pos1);
if (normal)
{
temp_normals.push_back(std::stof(token1));
}
else
{
temp_vertices.push_back(std::stof(token1));
}
l.erase(0, pos1 + 1);
}
// Last point is still left after the loop
if (normal)
{
temp_normals.push_back(std::stof(l));
}
else
{
temp_vertices.push_back(std::stof(l));
}
}
}
this->vertices = temp_vertices;
this->indices = temp_indices;
this->normals = temp_normals;
return true;
}
std::vector<float> Object3D::getVBOBuffer()
{
std::vector<float> temp_VBO_buffer;
for (int i = 0; i < this->vertices.size() / 3; i++)
{
for (int a = 0; a < 3; a++)
temp_VBO_buffer.push_back(this->vertices[(i * 3) + a]);
for (int a = 0; a < 3; a++)
temp_VBO_buffer.push_back(this->normals[(i * 3) + a]);
}
return temp_VBO_buffer;
}
+26
View File
@@ -0,0 +1,26 @@
#ifndef OBJECT3D_H
#define OBJECT3D_H
#include <string>
#include <vector>
class Object3D {
public:
std::vector<float> vertices;
std::vector<unsigned int> indices;
std::vector<float> normals;
std::vector<unsigned int> EBO_buffer;
std::vector<float> VBO_buffer;
Object3D();
Object3D(const std::string &file_path);
bool loadFromOBJ(const std::string& file_path);
std::vector<float> getVBOBuffer();
};
#endif //OBJECT3D_H
+178
View File
@@ -0,0 +1,178 @@
#ifndef SHADER_H
#define SHADER_H
#include <glad/glad.h>
#include <string>
#include <fstream>
#include <sstream>
#include <iostream>
#include <string.h>
class Shader
{
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const std::string &vertexPath, const std::string &fragmentPath)
{
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
// ensure ifstream objects can throw exceptions:
// vShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
// fShaderFile.exceptions (std::ifstream::failbit | std::ifstream::badbit);
try
{
// open files
vShaderFile.open(vertexPath);
if (!vShaderFile.is_open())
std::cout << "ERROR:SHADER::VERTEX::FILE_NOT_READ" << std::endl;
fShaderFile.open(fragmentPath);
if (!fShaderFile.is_open())
std::cout << "ERROR:SHADER::FRAGMENT::FILE_NOT_READ" << std::endl;
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
}
catch (std::ifstream::failure& e)
{
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
}
std::cout << fragmentCode << std::endl;
const char* vShaderCode = vertexCode.c_str();
const char * fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessary
glDeleteShader(vertex);
glDeleteShader(fragment);
}
// activate the shader
// ------------------------------------------------------------------------
void use()
{
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const
{
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const
{
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
void setVec2(const std::string &name, const glm::vec2 &value) const
{
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const std::string &name, float x, float y) const
{
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
// ------------------------------------------------------------------------
void setVec3(const std::string &name, const glm::vec3 &value) const
{
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const std::string &name, float x, float y, float z) const
{
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
// ------------------------------------------------------------------------
void setVec4(const std::string &name, const glm::vec4 &value) const
{
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const std::string &name, float x, float y, float z, float w) const
{
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
// ------------------------------------------------------------------------
void setMat2(const std::string &name, const glm::mat2 &mat) const
{
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat3(const std::string &name, const glm::mat3 &mat) const
{
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat4(const std::string &name, const glm::mat4 &mat) const
{
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(unsigned int shader, std::string type)
{
int success;
char infoLog[1024];
if (type != "PROGRAM")
{
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
else
{
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
}
}
}
};
#endif
+50 -77
View File
@@ -2,30 +2,27 @@
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include "Shader.h"
#include "Camera.h"
#include "Object3D.h"
// Window dimensions
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
// Shaders (in GLSL - OpenGL Shading Language)
// Vertex Shader: Positions the vertices
const char *vertexShaderSource = R"glsl(
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
)glsl";
const float CAMERA_SPEED = 1.0f;
const float MAX_CAMERA_SPEED = 2.0f;
const float LOOK_SENSITIVITY = 0.1f;
// Fragment Shader: Colors the pixels (fragments)
const char *fragmentShaderSource = R"glsl(
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f); // An orange color
}
)glsl";
const float Z_FAR = 1000.0f;
const float Z_NEAR = 0.1f;
bool WIREFRAME_MODE = true;
const float FOV = 90.0f;
glm::mat4 projection = glm::mat4(1.0f);
Camera camera = Camera(CAMERA_SPEED, glm::vec3(0.0f, 0.0f, 3.0f));
// Callback function for when the window is resized
void framebuffer_size_callback(GLFWwindow* window, int width, int height) {
@@ -41,9 +38,6 @@ int main() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // For macOS
#endif
// 2. --- Create a Window ---
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "HelloTriangle", NULL, NULL);
@@ -61,86 +55,66 @@ int main() {
return -1;
}
// 4. --- Compile Shaders ---
// Vertex Shader
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// Check for compilation errors
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Fragment Shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// Check for compilation errors
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
// Link shaders into a Shader Program
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// Check for linking errors
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertexShader); // Shaders are linked, we can delete them
glDeleteShader(fragmentShader);
// 4. Shader Setup
Shader shader("shaders/cube_vert.glsl", "shaders/cube_frag.glsl");
// 5. --- Set up Vertex Data and Buffers ---
// A triangle has 3 vertices, each with 3 coordinates (x, y, z)
float vertices[] = {
-0.5f, -0.5f, 0.0f, // left
0.5f, -0.5f, 0.0f, // right
0.0f, 0.5f, 0.0f // top
};
unsigned int VBO, VAO;
// Load Cube OBJ
Object3D cube = Object3D("objs/cube.obj");
unsigned int VBO, VAO, EBO;
glGenVertexArrays(1, &VAO); // 1. Create Vertex Array Object (VAO)
glGenBuffers(1, &VBO); // 2. Create Vertex Buffer Object (VBO)
glGenBuffers(1, &EBO);
glBindVertexArray(VAO); // 3. Bind the VAO
glBindBuffer(GL_ARRAY_BUFFER, VBO); // 4. Bind the VBO
// 5. Copy vertex data into VBO's memory
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER, cube.VBO_buffer.size() * sizeof(float), &cube.VBO_buffer.front(), GL_STATIC_DRAW);
// 6. Tell OpenGL how to interpret the vertex data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
// Position Attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_TRUE, 6 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0); // Enable the vertex attribute (location 0)
// Normal Attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_TRUE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
// 6.5 Setup EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, cube.EBO_buffer.size() * sizeof(unsigned int), &cube.EBO_buffer.front(), GL_STATIC_DRAW);
// Unbind VBO and VAO (optional, but good practice)
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
if (WIREFRAME_MODE)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
// Setup projection matrix
projection = glm::perspective(glm::radians(FOV), (float)SCR_WIDTH / (float)SCR_HEIGHT, Z_NEAR, Z_FAR); // This doesn't need to be recalculated every frame
glm::mat4 view = camera.getView();
// 6. --- The Render Loop ---
while (!glfwWindowShouldClose(window)) {
// Input (e.g., close window on ESC)
// processInput(window);
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
// Rendering
glClearColor(0.2f, 0.3f, 0.3f, 1.0f); // Set background color
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Z-Buffer
// Draw the triangle
glUseProgram(shaderProgram); // Use our shader program
glBindVertexArray(VAO); // Bind the VAO (our triangle's "recipe")
glDrawArrays(GL_TRIANGLES, 0, 3); // Draw it!
shader.use();
shader.setMat4("u_mvp", projection * view);
glBindVertexArray(VAO); // Bind the VAO (our triangle's "recipe")
glDrawElements(GL_TRIANGLES, cube.EBO_buffer.size(), GL_UNSIGNED_INT, nullptr); // Draw it!
// Swap buffers and poll for events
glfwSwapBuffers(window);
@@ -150,7 +124,6 @@ int main() {
// 7. --- Cleanup ---
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteProgram(shaderProgram);
glfwTerminate(); // Clean up GLFW
return 0;