From a64a7480192c538cb5214d9ab79fe2e54f723aa6 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Tue, 7 Dec 2021 00:17:04 -0500 Subject: [PATCH] Obj model loading and rendering --- examples/dev_testing/src/main.cpp | 11 +- .../simpleengine/objects/2d/shapes/square.h | 2 - include/simpleengine/objects/3d/obj_model.h | 168 ++++++++++++++++++ include/simpleengine/vector.h | 4 +- include/simpleengine/vertex.h | 4 + src/camera.cpp | 4 +- src/objects/2d/square.cpp | 2 +- 7 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 include/simpleengine/objects/3d/obj_model.h diff --git a/examples/dev_testing/src/main.cpp b/examples/dev_testing/src/main.cpp index 313e618..d63cd65 100644 --- a/examples/dev_testing/src/main.cpp +++ b/examples/dev_testing/src/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,13 @@ int main(int argc, char *argv[]) { /* simpleengine::gfx::Texture wall_texture("resources/wall.jpg"); simpleengine::gfx::Texture crate_texture("resources/container.jpg", true, true); */ - std::vector vertices = { + simpleengine::gfx::Texture stall_texture("resources/stallTexture.png"); + + auto stall = std::make_shared(simpleengine::gfx::Shader(base_shader_program), "resources/stall.obj"); + stall->set_texture(stall_texture); + game.add_event(stall); + + /* std::vector vertices = { { simpleengine::Vectorf(-0.5f, -0.5f, -1.f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(0.f, 0.f) }, // bottom left { simpleengine::Vectorf(0.5f, -0.5f, -1.f), glm::vec3(0.f, 1.f, 0.f), glm::vec2(1.f, 0.f) }, // bottom right { simpleengine::Vectorf(0.f, 0.5f, -1.f), glm::vec3(0.f, 0.f, 1.f), glm::vec2(0.5f, 1.0f) }, // top @@ -53,7 +60,7 @@ int main(int argc, char *argv[]) { auto tri = std::make_shared(base_shader_program, vertices); //tri->set_texture(wall_texture); - game.add_event(tri); + game.add_event(tri); */ /* std::vector vertices = { { simpleengine::Vectorf(-0.5f,0.5f,-0.5f), glm::vec3(1.f, 0.f, 0.f), glm::vec2(1.f, 1.f) }, diff --git a/include/simpleengine/objects/2d/shapes/square.h b/include/simpleengine/objects/2d/shapes/square.h index 545192b..5bf208a 100644 --- a/include/simpleengine/objects/2d/shapes/square.h +++ b/include/simpleengine/objects/2d/shapes/square.h @@ -27,8 +27,6 @@ namespace simpleengine::objects_2d::shapes { class Square : public simpleengine::Renderable, public simpleengine::Transformable { - private: - using super = simpleengine::Renderable; private: gfx::Shader shader; nonstd::optional texture; diff --git a/include/simpleengine/objects/3d/obj_model.h b/include/simpleengine/objects/3d/obj_model.h new file mode 100644 index 0000000..a41db47 --- /dev/null +++ b/include/simpleengine/objects/3d/obj_model.h @@ -0,0 +1,168 @@ +#include +#include +#include +#include +#include +#include + +#include "../../optional.h" +#include "../../vector.h" +#include "../../vertex.h" +#include "../../renderable.h" +#include "../../transformable.h" +#include "../../gfx/vao.h" +#include "../../gfx/vbo.h" +#include "../../gfx/shader.h" +#include "../../gfx/texture.h" + +namespace simpleengine::objects_3d { + class ObjModel : public simpleengine::Renderable, public simpleengine::Transformable { + private: + std::vector split_string(std::string str, const char delim) { + std::istringstream ss(str); + + std::vector tokens; + size_t pos = 0; + std::string token; + while ((pos = str.find(delim)) != std::string::npos) { + token = str.substr(0, pos); + tokens.push_back(token); + str.erase(0, pos + 1); + } + tokens.push_back(str); + + return tokens; + } + + static void process_vertex(const std::vector& vertex_data, std::vector& indicies, const std::vector& in_textures, + const std::vector& in_normals, std::vector& out_textures, std::vector& out_normals) { + + int currentVertexIndex = stoi(vertex_data[0]) - 1; + indicies.push_back(currentVertexIndex); + + // Read texture coords + glm::vec2 current_tex = in_textures.at(stoi(vertex_data[1]) - 1); + current_tex.y = 1 - current_tex.y; + out_textures.at(currentVertexIndex) = current_tex; + + // Read normals + glm::vec3 current_norm = in_normals.at(stoi(vertex_data[2]) - 1); + out_normals.at(currentVertexIndex) = current_norm; + } + + nonstd::optional texture; + public: + std::vector model_vertices; + std::vector indicies; + gfx::VBO ebo; + gfx::VBO vbo; + gfx::VAO vao; + gfx::Shader shader; + + ObjModel(gfx::Shader shader, std::string filename) : ObjModel(shader, std::ifstream(filename, std::ios::in | std::ios::binary)) { + + } + + ObjModel(gfx::Shader shader, std::ifstream file_stream) : + shader(shader), ebo(gfx::VBO(GL_ELEMENT_ARRAY_BUFFER, false)), vbo(gfx::VBO(GL_ARRAY_BUFFER, false)), + texture(nonstd::nullopt) { + + if (!file_stream.is_open()) { + std::cerr << "File stream that was given to ObjModel::ObjModel is not open!" << std::endl; + throw std::runtime_error("Failed to open ObjModel model file"); + } + + std::vector vertices; + std::vector read_textures; + std::vector read_normals; + + std::vector textures; + std::vector normals; + + std::string line; + while (std::getline(file_stream, line)) { + std::vector line_tokens = split_string(line, ' '); + + if (line_tokens.front() == "v") { + //glm::vec3 vertex(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + vertices.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + } else if (line_tokens.front() == "vt") { + read_textures.emplace_back(stof(line_tokens[1]), stof(line_tokens[2])); + } else if (line_tokens.front() == "vn") { + read_normals.emplace_back(stof(line_tokens[1]), stof(line_tokens[2]), stof(line_tokens[3])); + } else if (line_tokens.front() == "f") { + auto size = vertices.size(); + textures.resize(size); + normals.resize(size); + + std::cout << "Textures should be size of " << size << " but is a size of " << textures.size() << std::endl; + std::cout << "Normals should be size of " << size << " but is a size of " << normals.size() << std::endl; + break; + } + } + + do { + if (!line.starts_with("f")) { + continue; + } + std::vector line_tokens = split_string(line, ' '); + std::vector vertex1 = split_string(line_tokens[1], '/'); + std::vector vertex2 = split_string(line_tokens[2], '/'); + std::vector vertex3 = split_string(line_tokens[3], '/'); + + process_vertex(vertex1, indicies, read_textures, read_normals, textures, normals); + process_vertex(vertex2, indicies, read_textures, read_normals, textures, normals); + process_vertex(vertex3, indicies, read_textures, read_normals, textures, normals); + } while (std::getline(file_stream, line)); + + file_stream.close(); + + for (int i = 0; i < vertices.size(); i++) { + model_vertices.emplace_back(simpleengine::Vectorf(vertices.at(i)), glm::vec3(1.f), textures.at(i)); + } + + vao.bind(); + vbo.buffer(model_vertices.data(), 0, sizeof(Vertex) * model_vertices.size()); + ebo.buffer(indicies.data(), 0, indicies.size() * sizeof(GLuint)); + + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, position)); + glEnableVertexAttribArray(0); + + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, color)); + glEnableVertexAttribArray(1); + + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, tex_coord)); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + this->translate(glm::vec3(0.f, -1.f, -15.f)); + } + + void set_texture(gfx::Texture texture) { + this->texture = texture; + } + + virtual void update(const float& delta_time) override { + this->rotate_y(0.5f); + } + + virtual void render(GLFWwindow* target) override { + shader.use(); + + shader.set_uniform_matrix_4f("transform_matrix", transform_matrix, false); + + // When binding to the texture, also tell the shader if the texture is set or not. + if (texture.has_value()) { + shader.set_uniform_int("texture_is_set", true, false); + texture.value().bind(); + } else { + shader.set_uniform_int("texture_is_set", false, false); + } + + vao.bind(); + glDrawElements(GL_TRIANGLES, indicies.size(), GL_UNSIGNED_INT, 0); + } + }; +} \ No newline at end of file diff --git a/include/simpleengine/vector.h b/include/simpleengine/vector.h index e359a23..73b984d 100644 --- a/include/simpleengine/vector.h +++ b/include/simpleengine/vector.h @@ -15,9 +15,9 @@ namespace simpleengine { } - Vector(glm::vec<3, VectorType, glm::defaultp> glm_vec) : inner_vec(glm_vec) { + /* Vector(glm::vec<3, VectorType, glm::defaultp> glm_vec) : inner_vec(glm_vec) { - } + } */ Vector(const glm::vec<3, VectorType, glm::defaultp>& glm_vec) : inner_vec(glm_vec) { diff --git a/include/simpleengine/vertex.h b/include/simpleengine/vertex.h index 1c115fd..665d1b7 100644 --- a/include/simpleengine/vertex.h +++ b/include/simpleengine/vertex.h @@ -19,5 +19,9 @@ namespace simpleengine { simpleengine::Vectorf position; glm::vec3 color; glm::vec2 tex_coord; + + Vertex(simpleengine::Vectorf position, glm::vec3 color, glm::vec2 tex_coord) : position(position), color(color), tex_coord(tex_coord) { + + } }; } \ No newline at end of file diff --git a/src/camera.cpp b/src/camera.cpp index 454e13d..454ba18 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -20,7 +20,7 @@ namespace simpleengine { } void Camera::update(const float& delta_time) { - /* if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) { position.z -= 0.02f; } @@ -34,7 +34,7 @@ namespace simpleengine { if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) { position.x -= 0.02f; - } */ + } view_matrix = glm::lookAt(position, position + cam_front, world_up); diff --git a/src/objects/2d/square.cpp b/src/objects/2d/square.cpp index ee4713a..9677325 100644 --- a/src/objects/2d/square.cpp +++ b/src/objects/2d/square.cpp @@ -2,7 +2,7 @@ namespace simpleengine::objects_2d::shapes { Square::Square(gfx::Shader shader, std::vector vertices, std::vector indicies) : - super(nullptr), shader(shader), vertices(vertices), indicies(indicies), + simpleengine::Renderable(nullptr), shader(shader), vertices(vertices), indicies(indicies), ebo(gfx::VBO(GL_ELEMENT_ARRAY_BUFFER, false)), vbo(gfx::VBO(GL_ARRAY_BUFFER, false)), texture(nonstd::nullopt) {