diff --git a/inc/engine/obj_loader.hpp b/inc/engine/obj_loader.hpp new file mode 100644 index 0000000..1880ba1 --- /dev/null +++ b/inc/engine/obj_loader.hpp @@ -0,0 +1,36 @@ +#ifndef OBJ_LOADER_HPP +#define OBJ_LOADER_HPP + +// Includes +#include +#include +#include + +// OBJLoader class definition +class OBJLoader { +public: + // Vertex structure + typedef struct { + glm::vec3 position; + glm::vec3 normal; + glm::vec2 texCoord; + } Vertex; + + // Constructor + OBJLoader(std::string filepath); + + // convert loaded data to arrays + float *getVertexData(); + unsigned int *getIndexData(); + size_t getVertexCount(); + size_t getIndexCount(); + bool isLoaded() const { return loaded; } + +private: + std::string filepath; + std::vector vertices; + std::vector indices; + bool loaded = false; +}; + +#endif \ No newline at end of file diff --git a/shaders/triangle.vert b/shaders/triangle.vert index 5bd8af9..ab301da 100644 --- a/shaders/triangle.vert +++ b/shaders/triangle.vert @@ -1,7 +1,8 @@ #version 330 core layout(location = 0) in vec3 position; // Vertex position -layout(location = 1) in vec3 inColor; // Vertex color +layout(location = 1) in vec3 normal; // Vertex normal +layout(location = 2) in vec2 texCoord; // Vertex texture coordinate out vec3 color; // Output color to the fragment shader uniform mat4 model; @@ -10,5 +11,5 @@ uniform mat4 projection; void main() { gl_Position = projection * view * model * vec4(position, 1.0); // Apply transformation matrices - color = inColor; // Set the color output + color = vec3(1.0, 0.5, 0.2); // Set output color (orange) } \ No newline at end of file diff --git a/src/engine/obj_loader.cpp b/src/engine/obj_loader.cpp new file mode 100644 index 0000000..daa8218 --- /dev/null +++ b/src/engine/obj_loader.cpp @@ -0,0 +1,84 @@ +#include "engine/obj_loader.hpp" +#include +#include + +OBJLoader::OBJLoader(std::string filepath) : filepath(filepath), loaded(true) { + std::ifstream file(filepath); + if (!file.is_open()) { + loaded = false; + return; + } + + std::vector temp_positions; + std::vector temp_normals; + std::vector temp_texCoords; + + std::string line; + while (std::getline(file, line)) { + std::istringstream ss(line); + std::string prefix; + ss >> prefix; + + if (prefix == "v") { + glm::vec3 position; + ss >> position.x >> position.y >> position.z; + temp_positions.push_back(position); + } else if (prefix == "vn") { + glm::vec3 normal; + ss >> normal.x >> normal.y >> normal.z; + temp_normals.push_back(normal); + } else if (prefix == "vt") { + glm::vec2 texCoord; + ss >> texCoord.x >> texCoord.y; + temp_texCoords.push_back(texCoord); + } else if (prefix == "f") { + unsigned int posIdx[3], texIdx[3], normIdx[3]; + char slash; // to consume the '/' characters + + for (int i = 0; i < 3; ++i) { + ss >> posIdx[i] >> slash >> texIdx[i] >> slash >> normIdx[i]; + Vertex vertex; + vertex.position = temp_positions[posIdx[i] - 1]; + vertex.texCoord = temp_texCoords[texIdx[i] - 1]; + vertex.normal = temp_normals[normIdx[i] - 1]; + vertices.push_back(vertex); + indices.push_back(static_cast(vertices.size() - 1)); + } + } + } +} + +// Convert loaded vertex data to a contiguous float array +float* OBJLoader::getVertexData() { + size_t vertexCount = vertices.size(); + float* vertexData = new float[vertexCount * 8]; // 3 pos + 3 normal + 2 texCoord + for (size_t i = 0; i < vertexCount; ++i) { + vertexData[i * 8 + 0] = vertices[i].position.x; + vertexData[i * 8 + 1] = vertices[i].position.y; + vertexData[i * 8 + 2] = vertices[i].position.z; + vertexData[i * 8 + 3] = vertices[i].normal.x; + vertexData[i * 8 + 4] = vertices[i].normal.y; + vertexData[i * 8 + 5] = vertices[i].normal.z; + vertexData[i * 8 + 6] = vertices[i].texCoord.x; + vertexData[i * 8 + 7] = vertices[i].texCoord.y; + } + return vertexData; +} + +// Convert loaded index data to a contiguous unsigned int array +unsigned int* OBJLoader::getIndexData() { + size_t indexCount = indices.size(); + unsigned int* indexData = new unsigned int[indexCount]; + for (size_t i = 0; i < indexCount; ++i) { + indexData[i] = indices[i]; + } + return indexData; +} + +size_t OBJLoader::getVertexCount() { + return vertices.size(); +} + +size_t OBJLoader::getIndexCount() { + return indices.size(); +} \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 108ac28..597810a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,10 +1,6 @@ -#define GL_GLEXT_PROTOTYPES #include "engine/sdl.hpp" #include "engine/opengl.hpp" - -#include -#include -#include +#include "engine/obj_loader.hpp" int main(int argc, char* argv[]) { SDLWindow window("My SDL Application", 800, 600); @@ -12,9 +8,8 @@ int main(int argc, char* argv[]) { OpenGLContext glContext(window); if (!glContext.isInitialized()) { return -1; } - Camera camera( - glm::vec3(0.0f, 0.0f, 3.0f), // Position + glm::vec3(2.0f, 1.0f, 3.0f), // Position glm::vec3(0.0f, 0.0f, 0.0f), // Target glm::vec3(0.0f, 1.0f, 0.0f) // Up vector ); @@ -28,29 +23,25 @@ int main(int argc, char* argv[]) { Shader shader_program("shaders/triangle.vert", "shaders/triangle.frag"); - // vertex, color - float vertexData[] = { - 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, // top right - 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, // bottom right - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, // top left - -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f // bottom left - }; - - unsigned int indexData[] = { - 0, 1, 2, // first triangle - 1, 3, 2 // second triangle - }; - - // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + OBJLoader objLoader("assets/models/suzanne.obj"); + if (!objLoader.isLoaded()) { + SDL_Log("Failed to load OBJ model."); + return -1; + } VertexArrayObject VAO; - VAO.bufferVertexData(vertexData, sizeof(vertexData)); - VAO.bufferElementData(indexData, sizeof(indexData)); - VAO.setAttributePointer(0, 3, GL_FLOAT, false, 6 * sizeof(float), 0); // position - VAO.setAttributePointer(1, 3, GL_FLOAT, false, 6 * sizeof(float), 3 * sizeof(float)); // color + VAO.bufferVertexData(objLoader.getVertexData(), objLoader.getVertexCount() * sizeof(float) * 8); + VAO.bufferElementData(objLoader.getIndexData(), objLoader.getIndexCount() * sizeof(unsigned int)); + VAO.setAttributePointer(0, 3, GL_FLOAT, false, 8 * sizeof(float), 0); // position + VAO.setAttributePointer(1, 3, GL_FLOAT, false, 8 * sizeof(float), 3 * sizeof(float)); // normal + VAO.setAttributePointer(2, 2, GL_FLOAT, false, 8 * sizeof(float), 6 * sizeof(float)); // texCoord + + // Wireframe mode + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); window.setPosition(SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); window.showWindow(); + while (window.isRunning()) { window.pollEvents();