From 0bf4ad9e4a9e1c97e92aa23a365405dfef89bd7c Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 17 Jan 2021 19:36:30 +0000 Subject: Big reshuffle Fixes code quality warnings now picked up. --- Jamroot.jam | 6 +- application/display.cpp | 47 +++++ application/display.h | 26 +++ application/main.cpp | 59 ++++++ camera.cpp | 46 ----- camera.h | 24 --- display.cpp | 47 ----- display.h | 26 --- gfx/gl/camera.cpp | 46 +++++ gfx/gl/camera.h | 24 +++ gfx/gl/shader.cpp | 100 ++++++++++ gfx/gl/shader.h | 35 ++++ gfx/gl/shaders/basicShader.fs | 13 ++ gfx/gl/shaders/basicShader.vs | 18 ++ gfx/gl/transform.cpp | 27 +++ gfx/gl/transform.h | 58 ++++++ gfx/models/mesh.cpp | 75 ++++++++ gfx/models/mesh.h | 35 ++++ gfx/models/obj_loader.cpp | 428 ++++++++++++++++++++++++++++++++++++++++++ gfx/models/obj_loader.h | 53 ++++++ gfx/models/stb_image.c | 8 + gfx/models/texture.cpp | 35 ++++ gfx/models/texture.h | 23 +++ gfx/models/vertex.hpp | 37 ++++ main.cpp | 59 ------ mesh.cpp | 75 -------- mesh.h | 34 ---- obj_loader.cpp | 428 ------------------------------------------ obj_loader.h | 53 ------ ptr.hpp | 25 --- res/basicShader.fs | 13 -- res/basicShader.vs | 18 -- shader.cpp | 100 ---------- shader.h | 33 ---- stb_image.c | 8 - texture.cpp | 35 ---- texture.h | 23 --- transform.cpp | 27 --- transform.h | 59 ------ util.h | 34 ---- utility/ptr.hpp | 25 +++ utility/special_members.hpp | 12 ++ vertex.hpp | 36 ---- 43 files changed, 1188 insertions(+), 1205 deletions(-) create mode 100644 application/display.cpp create mode 100644 application/display.h create mode 100644 application/main.cpp delete mode 100644 camera.cpp delete mode 100644 camera.h delete mode 100644 display.cpp delete mode 100644 display.h create mode 100644 gfx/gl/camera.cpp create mode 100644 gfx/gl/camera.h create mode 100644 gfx/gl/shader.cpp create mode 100644 gfx/gl/shader.h create mode 100644 gfx/gl/shaders/basicShader.fs create mode 100644 gfx/gl/shaders/basicShader.vs create mode 100644 gfx/gl/transform.cpp create mode 100644 gfx/gl/transform.h create mode 100644 gfx/models/mesh.cpp create mode 100644 gfx/models/mesh.h create mode 100644 gfx/models/obj_loader.cpp create mode 100644 gfx/models/obj_loader.h create mode 100644 gfx/models/stb_image.c create mode 100644 gfx/models/texture.cpp create mode 100644 gfx/models/texture.h create mode 100644 gfx/models/vertex.hpp delete mode 100644 main.cpp delete mode 100644 mesh.cpp delete mode 100644 mesh.h delete mode 100644 obj_loader.cpp delete mode 100644 obj_loader.h delete mode 100644 ptr.hpp delete mode 100644 res/basicShader.fs delete mode 100644 res/basicShader.vs delete mode 100644 shader.cpp delete mode 100644 shader.h delete mode 100644 stb_image.c delete mode 100644 texture.cpp delete mode 100644 texture.h delete mode 100644 transform.cpp delete mode 100644 transform.h delete mode 100644 util.h create mode 100644 utility/ptr.hpp create mode 100644 utility/special_members.hpp delete mode 100644 vertex.hpp diff --git a/Jamroot.jam b/Jamroot.jam index 5058f6a..e67a00c 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -13,8 +13,8 @@ project : requirements debug:extra debug:on release:on - tidy:bin/res/fs-basicShader.h - tidy:bin/res/vs-basicShader.h + tidy:bin/gfx/gl/shaders/fs-basicShader.h + tidy:bin/gfx/gl/shaders/vs-basicShader.h tidy:boost-* tidy:bugprone-* tidy:clang-* @@ -45,6 +45,8 @@ IMPORT $(__name__) : xxd.i : : xxd.i ; exe test : [ glob-tree *.cpp *.c *.vs *.fs : bin ] : + . + utility sdl2 glew stb diff --git a/application/display.cpp b/application/display.cpp new file mode 100644 index 0000000..b4a42d7 --- /dev/null +++ b/application/display.cpp @@ -0,0 +1,47 @@ +#include "display.h" +#include +#include + +Display::Display(int width, int height, const std::string & title) +{ + SDL_Init(SDL_INIT_EVERYTHING); + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + m_window = m_window.create(SDL_CreateWindow, SDL_DestroyWindow, title.c_str(), SDL_WINDOWPOS_CENTERED, + SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); + m_glContext = m_glContext.create(SDL_GL_CreateContext, SDL_GL_DeleteContext, m_window); + + if (glewInit() != GLEW_OK) { + throw std::runtime_error {"Glew failed to initialize!"}; + } + + glEnable(GL_DEPTH_TEST); + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); +} + +Display::~Display() +{ + SDL_Quit(); +} + +void +Display::Clear(float r, float g, float b, float a) const +{ + glClearColor(r, g, b, a); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void +Display::SwapBuffers() const +{ + SDL_GL_SwapWindow(m_window); +} diff --git a/application/display.h b/application/display.h new file mode 100644 index 0000000..b561d77 --- /dev/null +++ b/application/display.h @@ -0,0 +1,26 @@ +#ifndef DISPLAY_INCLUDED_H +#define DISPLAY_INCLUDED_H + +#include "ptr.hpp" +#include +#include +#include +#include + +class Display { +public: + Display(int width, int height, const std::string & title); + virtual ~Display(); + + NO_COPY(Display); + NO_MOVE(Display); + + void Clear(float r, float g, float b, float a) const; + void SwapBuffers() const; + +private: + wrapped_ptr m_window; + wrapped_ptr> m_glContext; +}; + +#endif diff --git a/application/main.cpp b/application/main.cpp new file mode 100644 index 0000000..a5a09e5 --- /dev/null +++ b/application/main.cpp @@ -0,0 +1,59 @@ +#include "display.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const int DISPLAY_WIDTH = 800; +static const int DISPLAY_HEIGHT = 600; + +int +main(int, char **) +{ + Display display(DISPLAY_WIDTH, DISPLAY_HEIGHT, "OpenGL"); + + Mesh monkey("./res/monkey3.obj"); + Shader shader("./res/basicShader"); + Texture texture("./res/bricks.jpg"); + Transform transform; + Camera camera(glm::vec3(0.0F, 0.0F, -5.0F), 70.0F, (float)DISPLAY_WIDTH / (float)DISPLAY_HEIGHT, 0.1F, 100.0F); + + SDL_Event e; + bool isRunning = true; + float counter = 0.0F; + while (isRunning) { + while (SDL_PollEvent(&e)) { + if (e.type == SDL_QUIT) { + isRunning = false; + } + } + + display.Clear(0.0F, 0.0F, 0.0F, 1.0F); + + // float sinCounter = sinf(counter); + // float absSinCounter = abs(sinCounter); + + // transform.GetPos()->x = sinCounter; + transform.GetRot().y = std::numbers::pi_v + sin(counter); + transform.GetRot().z = 0.3 * cos(counter * 10); + // transform.GetScale()->x = absSinCounter; + // transform.GetScale()->y = absSinCounter; + + shader.Bind(); + texture.Bind(); + shader.Update(transform, camera); + monkey.Draw(); + + display.SwapBuffers(); + SDL_Delay(1); + counter += 0.01F; + } + + return 0; +} diff --git a/camera.cpp b/camera.cpp deleted file mode 100644 index b4a76d0..0000000 --- a/camera.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "camera.h" -#include - -Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) : - projection {glm::perspective(fov, aspect, zNear, zFar)}, pos {pos}, forward {0.0F, 0.0F, 1.0F}, up {0.0F, 1.0F, - 0.0F} -{ -} - -glm::mat4 -Camera::GetViewProjection() const -{ - return projection * glm::lookAt(pos, pos + forward, up); -} - -void -Camera::MoveForward(float amt) -{ - pos += forward * amt; -} - -void -Camera::MoveRight(float amt) -{ - pos += glm::cross(up, forward) * amt; -} - -void -Camera::Pitch(float angle) -{ - const auto right = glm::normalize(glm::cross(up, forward)); - - forward = glm::vec3(glm::normalize(glm::rotate(angle, right) * glm::vec4(forward, 0.0))); - up = glm::normalize(glm::cross(forward, right)); -} - -void -Camera::RotateY(float angle) -{ - static constexpr glm::vec3 UP {0.0F, 1.0F, 0.0F}; - - const auto rotation = glm::rotate(angle, UP); - - forward = glm::vec3(glm::normalize(rotation * glm::vec4(forward, 0.0))); - up = glm::vec3(glm::normalize(rotation * glm::vec4(up, 0.0))); -} diff --git a/camera.h b/camera.h deleted file mode 100644 index 3c1e40c..0000000 --- a/camera.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef CAMERA_INCLUDED_H -#define CAMERA_INCLUDED_H - -#include - -class Camera { -public: - Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar); - - glm::mat4 GetViewProjection() const; - - void MoveForward(float amt); - void MoveRight(float amt); - void Pitch(float angle); - void RotateY(float angle); - -private: - glm::mat4 projection; - glm::vec3 pos; - glm::vec3 forward; - glm::vec3 up; -}; - -#endif diff --git a/display.cpp b/display.cpp deleted file mode 100644 index b4a42d7..0000000 --- a/display.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "display.h" -#include -#include - -Display::Display(int width, int height, const std::string & title) -{ - SDL_Init(SDL_INIT_EVERYTHING); - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - m_window = m_window.create(SDL_CreateWindow, SDL_DestroyWindow, title.c_str(), SDL_WINDOWPOS_CENTERED, - SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL); - m_glContext = m_glContext.create(SDL_GL_CreateContext, SDL_GL_DeleteContext, m_window); - - if (glewInit() != GLEW_OK) { - throw std::runtime_error {"Glew failed to initialize!"}; - } - - glEnable(GL_DEPTH_TEST); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); -} - -Display::~Display() -{ - SDL_Quit(); -} - -void -Display::Clear(float r, float g, float b, float a) const -{ - glClearColor(r, g, b, a); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -void -Display::SwapBuffers() const -{ - SDL_GL_SwapWindow(m_window); -} diff --git a/display.h b/display.h deleted file mode 100644 index e5fcc73..0000000 --- a/display.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef DISPLAY_INCLUDED_H -#define DISPLAY_INCLUDED_H - -#include "ptr.hpp" -#include -#include -#include - -class Display { -public: - Display(int width, int height, const std::string & title); - - Display(const Display &) = delete; - void operator=(const Display &) = delete; - - virtual ~Display(); - - void Clear(float r, float g, float b, float a) const; - void SwapBuffers() const; - -private: - wrapped_ptr m_window; - wrapped_ptr> m_glContext; -}; - -#endif diff --git a/gfx/gl/camera.cpp b/gfx/gl/camera.cpp new file mode 100644 index 0000000..b4a76d0 --- /dev/null +++ b/gfx/gl/camera.cpp @@ -0,0 +1,46 @@ +#include "camera.h" +#include + +Camera::Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar) : + projection {glm::perspective(fov, aspect, zNear, zFar)}, pos {pos}, forward {0.0F, 0.0F, 1.0F}, up {0.0F, 1.0F, + 0.0F} +{ +} + +glm::mat4 +Camera::GetViewProjection() const +{ + return projection * glm::lookAt(pos, pos + forward, up); +} + +void +Camera::MoveForward(float amt) +{ + pos += forward * amt; +} + +void +Camera::MoveRight(float amt) +{ + pos += glm::cross(up, forward) * amt; +} + +void +Camera::Pitch(float angle) +{ + const auto right = glm::normalize(glm::cross(up, forward)); + + forward = glm::vec3(glm::normalize(glm::rotate(angle, right) * glm::vec4(forward, 0.0))); + up = glm::normalize(glm::cross(forward, right)); +} + +void +Camera::RotateY(float angle) +{ + static constexpr glm::vec3 UP {0.0F, 1.0F, 0.0F}; + + const auto rotation = glm::rotate(angle, UP); + + forward = glm::vec3(glm::normalize(rotation * glm::vec4(forward, 0.0))); + up = glm::vec3(glm::normalize(rotation * glm::vec4(up, 0.0))); +} diff --git a/gfx/gl/camera.h b/gfx/gl/camera.h new file mode 100644 index 0000000..fa4296d --- /dev/null +++ b/gfx/gl/camera.h @@ -0,0 +1,24 @@ +#ifndef CAMERA_INCLUDED_H +#define CAMERA_INCLUDED_H + +#include + +class Camera { +public: + Camera(glm::vec3 pos, float fov, float aspect, float zNear, float zFar); + + [[nodiscard]] glm::mat4 GetViewProjection() const; + + void MoveForward(float amt); + void MoveRight(float amt); + void Pitch(float angle); + void RotateY(float angle); + +private: + glm::mat4 projection; + glm::vec3 pos; + glm::vec3 forward; + glm::vec3 up; +}; + +#endif diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp new file mode 100644 index 0000000..33fdf61 --- /dev/null +++ b/gfx/gl/shader.cpp @@ -0,0 +1,100 @@ +#include "shader.h" +#include "transform.h" +#include +#include +#include +#include + +Shader::Shader(const std::string &) : + m_program {glCreateProgram()}, m_shaders {CreateShader( + (GLchar *)(basicShader_vs), basicShader_vs_len, GL_VERTEX_SHADER), + CreateShader( + (GLchar *)basicShader_fs, basicShader_fs_len, GL_FRAGMENT_SHADER)}, + m_uniforms {} +{ + for (auto m_shader : m_shaders) { + glAttachShader(m_program, m_shader); + } + + glBindAttribLocation(m_program, 0, "position"); + glBindAttribLocation(m_program, 1, "texCoord"); + glBindAttribLocation(m_program, 2, "normal"); + + glLinkProgram(m_program); + CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program"); + + glValidateProgram(m_program); + CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program"); + + m_uniforms = {glGetUniformLocation(m_program, "MVP"), glGetUniformLocation(m_program, "Normal"), + glGetUniformLocation(m_program, "lightDirection")}; +} + +Shader::~Shader() +{ + for (auto m_shader : m_shaders) { + glDetachShader(m_program, m_shader); + glDeleteShader(m_shader); + } + + glDeleteProgram(m_program); +} + +void +Shader::Bind() const +{ + glUseProgram(m_program); +} + +void +Shader::Update(const Transform & transform, const Camera & camera) const +{ + glm::mat4 MVP = transform.GetMVP(camera); + glm::mat4 Normal = transform.GetModel(); + + glUniformMatrix4fv(m_uniforms[0], 1, GL_FALSE, &MVP[0][0]); + glUniformMatrix4fv(m_uniforms[1], 1, GL_FALSE, &Normal[0][0]); + glUniform3f(m_uniforms[2], 0.0F, 0.0F, 1.0F); +} + +void +Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage) +{ + GLint success = 0; + std::array error {}; + + if (isProgram) { + glGetProgramiv(shader, flag, &success); + } + else { + glGetShaderiv(shader, flag, &success); + } + + if (success == GL_FALSE) { + if (isProgram) { + glGetProgramInfoLog(shader, error.size(), nullptr, error.data()); + } + else { + glGetShaderInfoLog(shader, error.size(), nullptr, error.data()); + } + + throw std::runtime_error {errorMessage + ": '" + std::string {error.data(), error.size()} + "'"}; + } +} + +GLuint +Shader::CreateShader(const GLchar * text, GLint len, unsigned int type) +{ + GLuint shader = glCreateShader(type); + + if (shader == 0) { + throw std::runtime_error {"Error compiling shader type " + std::to_string(type)}; + } + + glShaderSource(shader, 1, &text, &len); + glCompileShader(shader); + + CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!"); + + return shader; +} diff --git a/gfx/gl/shader.h b/gfx/gl/shader.h new file mode 100644 index 0000000..2072199 --- /dev/null +++ b/gfx/gl/shader.h @@ -0,0 +1,35 @@ +#ifndef SHADER_INCLUDED_H +#define SHADER_INCLUDED_H + +#include +#include +#include +#include + +class Camera; +class Transform; + +class Shader { +public: + explicit Shader(const std::string & fileName); + virtual ~Shader(); + + NO_COPY(Shader); + NO_MOVE(Shader); + + void Bind() const; + void Update(const Transform & transform, const Camera & camera) const; + +private: + static constexpr unsigned int NUM_SHADERS = 2; + static constexpr unsigned int NUM_UNIFORMS = 3; + + static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage); + static GLuint CreateShader(const GLchar * text, GLint len, unsigned int type); + + GLuint m_program; + std::array m_shaders; + std::array m_uniforms; +}; + +#endif diff --git a/gfx/gl/shaders/basicShader.fs b/gfx/gl/shaders/basicShader.fs new file mode 100644 index 0000000..3aa974f --- /dev/null +++ b/gfx/gl/shaders/basicShader.fs @@ -0,0 +1,13 @@ +#version 120 + +varying vec2 texCoord0; +varying vec3 normal0; + +uniform sampler2D sampler; +uniform vec3 lightDirection; + +void main() +{ + gl_FragColor = texture2D(sampler, texCoord0) * + clamp(dot(-lightDirection, normal0), 0.0, 1.0); +} diff --git a/gfx/gl/shaders/basicShader.vs b/gfx/gl/shaders/basicShader.vs new file mode 100644 index 0000000..e673548 --- /dev/null +++ b/gfx/gl/shaders/basicShader.vs @@ -0,0 +1,18 @@ +#version 120 + +attribute vec3 position; +attribute vec2 texCoord; +attribute vec3 normal; + +varying vec2 texCoord0; +varying vec3 normal0; + +uniform mat4 MVP; +uniform mat4 Normal; + +void main() +{ + gl_Position = MVP * vec4(position, 1.0); + texCoord0 = texCoord; + normal0 = (Normal * vec4(normal, 0.0)).xyz; +} diff --git a/gfx/gl/transform.cpp b/gfx/gl/transform.cpp new file mode 100644 index 0000000..7b256af --- /dev/null +++ b/gfx/gl/transform.cpp @@ -0,0 +1,27 @@ +#include "transform.h" +#include "camera.h" +#include + +Transform::Transform(glm::vec3 pos, glm::vec3 rot, glm::vec3 scale) : pos {pos}, rot {rot}, scale {scale} { } + +glm::mat4 +Transform::GetModel() const +{ + const auto posMat = glm::translate(pos); + const auto scaleMat = glm::scale(scale); + const auto rotX = glm::rotate(rot.x, glm::vec3(1.0, 0.0, 0.0)); + const auto rotY = glm::rotate(rot.y, glm::vec3(0.0, 1.0, 0.0)); + const auto rotZ = glm::rotate(rot.z, glm::vec3(0.0, 0.0, 1.0)); + const auto rotMat = rotX * rotY * rotZ; + + return posMat * rotMat * scaleMat; +} + +glm::mat4 +Transform::GetMVP(const Camera & camera) const +{ + const auto VP = camera.GetViewProjection(); + const auto M = GetModel(); + + return VP * M; +} diff --git a/gfx/gl/transform.h b/gfx/gl/transform.h new file mode 100644 index 0000000..07040ae --- /dev/null +++ b/gfx/gl/transform.h @@ -0,0 +1,58 @@ +#ifndef TRANSFORM_INCLUDED_H +#define TRANSFORM_INCLUDED_H + +#include + +class Camera; + +class Transform { +public: + explicit Transform(glm::vec3 pos = {}, glm::vec3 rot = {}, glm::vec3 scale = {1.0F, 1.0F, 1.0F}); + + [[nodiscard]] glm::mat4 GetModel() const; + + [[nodiscard]] glm::mat4 GetMVP(const Camera & camera) const; + + [[nodiscard]] inline glm::vec3 & + GetPos() + { + return pos; + } + + [[nodiscard]] inline glm::vec3 & + GetRot() + { + return rot; + } + + [[nodiscard]] inline glm::vec3 & + GetScale() + { + return scale; + } + + inline void + SetPos(glm::vec3 && pos) + { + this->pos = pos; + } + + inline void + SetRot(glm::vec3 && rot) + { + this->rot = rot; + } + + inline void + SetScale(glm::vec3 && scale) + { + this->scale = scale; + } + +private: + glm::vec3 pos; + glm::vec3 rot; + glm::vec3 scale; +}; + +#endif diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp new file mode 100644 index 0000000..8c304b3 --- /dev/null +++ b/gfx/models/mesh.cpp @@ -0,0 +1,75 @@ +#include "mesh.h" +#include "obj_loader.h" +#include "vertex.hpp" +#include +#include +#include + +Mesh::Mesh(const std::string & fileName) : Mesh(OBJModel(fileName).ToIndexedModel()) { } + +Mesh::Mesh(const IndexedModel & model) : + m_vertexArrayObject {}, m_vertexArrayBuffers {}, m_numIndices {model.indices.size()} +{ + glGenVertexArrays(1, &m_vertexArrayObject); + glBindVertexArray(m_vertexArrayObject); + + glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers.data()); + + glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]); + glBufferData( + GL_ARRAY_BUFFER, sizeof(model.positions[0]) * model.positions.size(), &model.positions[0], GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[TEXCOORD_VB]); + glBufferData( + GL_ARRAY_BUFFER, sizeof(model.texCoords[0]) * model.texCoords.size(), &model.texCoords[0], GL_STATIC_DRAW); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[NORMAL_VB]); + glBufferData(GL_ARRAY_BUFFER, sizeof(model.normals[0]) * model.normals.size(), &model.normals[0], GL_STATIC_DRAW); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vertexArrayBuffers[INDEX_VB]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(model.indices[0]) * model.indices.size(), &model.indices[0], + GL_STATIC_DRAW); + + glBindVertexArray(0); +} + +Mesh::Mesh(Vertex * vertices, unsigned int numVertices, unsigned int * indices, unsigned int numIndices) : + Mesh {[vertices, numVertices, indices, numIndices]() { + IndexedModel model; + + for (unsigned int i = 0; i < numVertices; i++) { + model.positions.push_back(vertices[i].GetPos()); + model.texCoords.push_back(vertices[i].GetTexCoord()); + model.normals.push_back(vertices[i].GetNormal()); + } + + for (unsigned int i = 0; i < numIndices; i++) { + model.indices.push_back(indices[i]); + } + + return model; + }()} +{ +} + +Mesh::~Mesh() +{ + glDeleteBuffers(NUM_BUFFERS, m_vertexArrayBuffers.data()); + glDeleteVertexArrays(1, &m_vertexArrayObject); +} + +void +Mesh::Draw() +{ + glBindVertexArray(m_vertexArrayObject); + + glDrawElementsBaseVertex(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, nullptr, 0); + + glBindVertexArray(0); +} diff --git a/gfx/models/mesh.h b/gfx/models/mesh.h new file mode 100644 index 0000000..453e54a --- /dev/null +++ b/gfx/models/mesh.h @@ -0,0 +1,35 @@ +#ifndef MESH_INCLUDED_H +#define MESH_INCLUDED_H + +#include +#include +#include +#include +#include + +class IndexedModel; +class Vertex; + +enum MeshBufferPositions { POSITION_VB, TEXCOORD_VB, NORMAL_VB, INDEX_VB }; + +class Mesh { +public: + explicit Mesh(const std::string & fileName); + explicit Mesh(const IndexedModel & model); + Mesh(Vertex * vertices, unsigned int numVertices, unsigned int * indices, unsigned int numIndices); + virtual ~Mesh(); + + NO_COPY(Mesh); + NO_MOVE(Mesh); + + void Draw(); + +private: + static constexpr unsigned int NUM_BUFFERS {4}; + + GLuint m_vertexArrayObject; + std::array m_vertexArrayBuffers; + size_t m_numIndices; +}; + +#endif diff --git a/gfx/models/obj_loader.cpp b/gfx/models/obj_loader.cpp new file mode 100644 index 0000000..7611a2c --- /dev/null +++ b/gfx/models/obj_loader.cpp @@ -0,0 +1,428 @@ +#include "obj_loader.h" +#include +#include +#include +#include +#include +#include + +static bool CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b); +static inline unsigned int FindNextChar(unsigned int start, const char * str, unsigned int length, char token); +static inline unsigned int ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end); +static inline float ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end); +static inline std::vector SplitString(const std::string & s, char delim); + +OBJModel::OBJModel(const std::string & fileName) +{ + hasUVs = false; + hasNormals = false; + std::ifstream file; + file.open(fileName.c_str()); + + std::string line; + if (file.is_open()) { + while (file.good()) { + getline(file, line); + + unsigned int lineLength = line.length(); + + if (lineLength < 2) { + continue; + } + + const char * lineCStr = line.c_str(); + + switch (lineCStr[0]) { + case 'v': + switch (lineCStr[1]) { + case 't': + this->uvs.push_back(ParseOBJVec2(line)); + break; + case 'n': + this->normals.push_back(ParseOBJVec3(line)); + break; + case ' ': + case '\t': + this->vertices.push_back(ParseOBJVec3(line)); + } + break; + case 'f': + CreateOBJFace(line); + break; + default: + break; + }; + } + } + else { + throw std::runtime_error {"Unable to load mesh: " + fileName}; + } +} + +void +IndexedModel::CalcNormals() +{ + for (unsigned int i = 0; i < indices.size(); i += 3) { + int i0 = indices[i]; + int i1 = indices[i + 1]; + int i2 = indices[i + 2]; + + glm::vec3 v1 = positions[i1] - positions[i0]; + glm::vec3 v2 = positions[i2] - positions[i0]; + + glm::vec3 normal = glm::normalize(glm::cross(v1, v2)); + + normals[i0] += normal; + normals[i1] += normal; + normals[i2] += normal; + } + + for (unsigned int i = 0; i < positions.size(); i++) { + normals[i] = glm::normalize(normals[i]); + } +} + +IndexedModel +OBJModel::ToIndexedModel() +{ + IndexedModel result; + IndexedModel normalModel; + + unsigned int numIndices = OBJIndices.size(); + + std::vector indexLookup; + + for (unsigned int i = 0; i < numIndices; i++) { + indexLookup.push_back(&OBJIndices[i]); + } + + std::sort(indexLookup.begin(), indexLookup.end(), CompareOBJIndexPtr); + + std::map normalModelIndexMap; + std::map indexMap; + + for (unsigned int i = 0; i < numIndices; i++) { + OBJIndex * currentIndex = &OBJIndices[i]; + + glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; + glm::vec2 currentTexCoord; + glm::vec3 currentNormal; + + if (hasUVs) { + currentTexCoord = uvs[currentIndex->uvIndex]; + } + else { + currentTexCoord = glm::vec2(0, 0); + } + + if (hasNormals) { + currentNormal = normals[currentIndex->normalIndex]; + } + else { + currentNormal = glm::vec3(0, 0, 0); + } + + unsigned int normalModelIndex; + unsigned int resultModelIndex; + + // Create model to properly generate normals on + const auto it = normalModelIndexMap.find(*currentIndex); + if (it == normalModelIndexMap.end()) { + normalModelIndex = normalModel.positions.size(); + + normalModelIndexMap.insert(std::pair(*currentIndex, normalModelIndex)); + normalModel.positions.push_back(currentPosition); + normalModel.texCoords.push_back(currentTexCoord); + normalModel.normals.push_back(currentNormal); + } + else { + normalModelIndex = it->second; + } + + // Create model which properly separates texture coordinates + unsigned int previousVertexLocation = FindLastVertexIndex(indexLookup, currentIndex, result); + + if (previousVertexLocation == (unsigned int)-1) { + resultModelIndex = result.positions.size(); + + result.positions.push_back(currentPosition); + result.texCoords.push_back(currentTexCoord); + result.normals.push_back(currentNormal); + } + else { + resultModelIndex = previousVertexLocation; + } + + normalModel.indices.push_back(normalModelIndex); + result.indices.push_back(resultModelIndex); + indexMap.insert(std::pair(resultModelIndex, normalModelIndex)); + } + + if (!hasNormals) { + normalModel.CalcNormals(); + + for (unsigned int i = 0; i < result.positions.size(); i++) { + result.normals[i] = normalModel.normals[indexMap[i]]; + } + } + + return result; +}; + +unsigned int +OBJModel::FindLastVertexIndex( + const std::vector & indexLookup, const OBJIndex * currentIndex, const IndexedModel & result) +{ + unsigned int start = 0; + unsigned int end = indexLookup.size(); + unsigned int current = (end - start) / 2 + start; + unsigned int previous = start; + + while (current != previous) { + OBJIndex * testIndex = indexLookup[current]; + + if (testIndex->vertexIndex == currentIndex->vertexIndex) { + unsigned int countStart = current; + + for (unsigned int i = 0; i < current; i++) { + OBJIndex * possibleIndex = indexLookup[current - i]; + + if (possibleIndex == currentIndex) { + continue; + } + + if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { + break; + } + + countStart--; + } + + for (unsigned int i = countStart; i < indexLookup.size() - countStart; i++) { + OBJIndex * possibleIndex = indexLookup[current + i]; + + if (possibleIndex == currentIndex) { + continue; + } + + if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { + break; + } + else if ((!hasUVs || possibleIndex->uvIndex == currentIndex->uvIndex) + && (!hasNormals || possibleIndex->normalIndex == currentIndex->normalIndex)) { + glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; + glm::vec2 currentTexCoord; + glm::vec3 currentNormal; + + if (hasUVs) { + currentTexCoord = uvs[currentIndex->uvIndex]; + } + else { + currentTexCoord = glm::vec2(0, 0); + } + + if (hasNormals) { + currentNormal = normals[currentIndex->normalIndex]; + } + else { + currentNormal = glm::vec3(0, 0, 0); + } + + for (unsigned int j = 0; j < result.positions.size(); j++) { + if (currentPosition == result.positions[j] + && ((!hasUVs || currentTexCoord == result.texCoords[j]) + && (!hasNormals || currentNormal == result.normals[j]))) { + return j; + } + } + } + } + + return -1; + } + else { + if (testIndex->vertexIndex < currentIndex->vertexIndex) { + start = current; + } + else { + end = current; + } + } + + previous = current; + current = (end - start) / 2 + start; + } + + return -1; +} + +void +OBJModel::CreateOBJFace(const std::string & line) +{ + std::vector tokens = SplitString(line, ' '); + + this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); + this->OBJIndices.push_back(ParseOBJIndex(tokens[2], &this->hasUVs, &this->hasNormals)); + this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); + + if ((int)tokens.size() > 4) { + this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); + this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); + this->OBJIndices.push_back(ParseOBJIndex(tokens[4], &this->hasUVs, &this->hasNormals)); + } +} + +OBJIndex +OBJModel::ParseOBJIndex(const std::string & token, bool * hasUVs, bool * hasNormals) +{ + unsigned int tokenLength = token.length(); + const char * tokenString = token.c_str(); + + unsigned int vertIndexStart = 0; + unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); + + OBJIndex result { + .vertexIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd), + .uvIndex = 0, + .normalIndex = 0, + }; + + if (vertIndexEnd >= tokenLength) { + return result; + } + + vertIndexStart = vertIndexEnd + 1; + vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); + + result.uvIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); + *hasUVs = true; + + if (vertIndexEnd >= tokenLength) { + return result; + } + + vertIndexStart = vertIndexEnd + 1; + vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); + + result.normalIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); + *hasNormals = true; + + return result; +} + +glm::vec3 +OBJModel::ParseOBJVec3(const std::string & line) +{ + unsigned int tokenLength = line.length(); + const char * tokenString = line.c_str(); + + unsigned int vertIndexStart = 2; + + while (vertIndexStart < tokenLength) { + if (tokenString[vertIndexStart] != ' ') { + break; + } + vertIndexStart++; + } + + unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); + + float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); + + vertIndexStart = vertIndexEnd + 1; + vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); + + float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); + + vertIndexStart = vertIndexEnd + 1; + vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); + + float z = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); + + return glm::vec3(x, y, z); +} + +glm::vec2 +OBJModel::ParseOBJVec2(const std::string & line) +{ + unsigned int tokenLength = line.length(); + const char * tokenString = line.c_str(); + + unsigned int vertIndexStart = 3; + + while (vertIndexStart < tokenLength) { + if (tokenString[vertIndexStart] != ' ') { + break; + } + vertIndexStart++; + } + + unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); + + float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); + + vertIndexStart = vertIndexEnd + 1; + vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); + + float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); + + return glm::vec2(x, y); +} + +static bool +CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b) +{ + return a->vertexIndex < b->vertexIndex; +} + +static inline unsigned int +FindNextChar(unsigned int start, const char * str, unsigned int length, char token) +{ + unsigned int result = start; + while (result < length) { + result++; + if (str[result] == token) { + break; + } + } + + return result; +} + +static inline unsigned int +ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end) +{ + return std::stoul(token.substr(start, end - start)) - 1; +} + +static inline float +ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end) +{ + return std::stof(token.substr(start, end - start)); +} + +static inline std::vector +SplitString(const std::string & s, char delim) +{ + std::vector elems; + + const char * cstr = s.c_str(); + unsigned int strLength = s.length(); + unsigned int start = 0; + unsigned int end = 0; + + while (end <= strLength) { + while (end <= strLength) { + if (cstr[end] == delim) { + break; + } + end++; + } + + elems.push_back(s.substr(start, end - start)); + start = end + 1; + end = start; + } + + return elems; +} diff --git a/gfx/models/obj_loader.h b/gfx/models/obj_loader.h new file mode 100644 index 0000000..11c6b38 --- /dev/null +++ b/gfx/models/obj_loader.h @@ -0,0 +1,53 @@ +#ifndef OBJ_LOADER_H_INCLUDED +#define OBJ_LOADER_H_INCLUDED + +#include +#include +#include + +struct OBJIndex { + unsigned int vertexIndex; + unsigned int uvIndex; + unsigned int normalIndex; + + bool + operator<(const OBJIndex & r) const + { + return vertexIndex < r.vertexIndex; + } +}; + +class IndexedModel { +public: + std::vector positions; + std::vector texCoords; + std::vector normals; + std::vector indices; + + void CalcNormals(); +}; + +class OBJModel { +public: + std::vector OBJIndices; + std::vector vertices; + std::vector uvs; + std::vector normals; + bool hasUVs; + bool hasNormals; + + explicit OBJModel(const std::string & fileName); + + IndexedModel ToIndexedModel(); + +private: + unsigned int FindLastVertexIndex( + const std::vector & indexLookup, const OBJIndex * currentIndex, const IndexedModel & result); + void CreateOBJFace(const std::string & line); + + glm::vec2 ParseOBJVec2(const std::string & line); + glm::vec3 ParseOBJVec3(const std::string & line); + OBJIndex ParseOBJIndex(const std::string & token, bool * hasUVs, bool * hasNormals); +}; + +#endif // OBJ_LOADER_H_INCLUDED diff --git a/gfx/models/stb_image.c b/gfx/models/stb_image.c new file mode 100644 index 0000000..a839b61 --- /dev/null +++ b/gfx/models/stb_image.c @@ -0,0 +1,8 @@ +#ifndef TIDY +# define STB_IMAGE_IMPLEMENTATION +# pragma GCC diagnostic ignored "-Wsign-compare" +# ifndef __clang__ +# pragma GCC diagnostic ignored "-Wunused-but-set-variable" +# endif +# include "stb_image.h" +#endif diff --git a/gfx/models/texture.cpp b/gfx/models/texture.cpp new file mode 100644 index 0000000..a388b32 --- /dev/null +++ b/gfx/models/texture.cpp @@ -0,0 +1,35 @@ +#include "texture.h" +#include "stb_image.h" +#include + +Texture::Texture(const std::string & fileName) : m_texture {} +{ + int width, height, numComponents; + unsigned char * data = stbi_load((fileName).c_str(), &width, &height, &numComponents, 4); + + if (!data) { + throw std::runtime_error {"Unable to load texture: " + fileName}; + } + + glGenTextures(1, &m_texture); + glBindTexture(GL_TEXTURE_2D, m_texture); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + stbi_image_free(data); +} + +Texture::~Texture() +{ + glDeleteTextures(1, &m_texture); +} + +void +Texture::Bind() const +{ + glBindTexture(GL_TEXTURE_2D, m_texture); +} diff --git a/gfx/models/texture.h b/gfx/models/texture.h new file mode 100644 index 0000000..6ebf88d --- /dev/null +++ b/gfx/models/texture.h @@ -0,0 +1,23 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include +#include +#include + +class Texture { +public: + explicit Texture(const std::string & fileName); + + virtual ~Texture(); + + NO_COPY(Texture); + NO_MOVE(Texture); + + void Bind() const; + +private: + GLuint m_texture; +}; + +#endif diff --git a/gfx/models/vertex.hpp b/gfx/models/vertex.hpp new file mode 100644 index 0000000..4ab6024 --- /dev/null +++ b/gfx/models/vertex.hpp @@ -0,0 +1,37 @@ +#ifndef VERTEX_H +#define VERTEX_H + +#include + +class Vertex { +public: + Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal) : + pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)} + { + } + + glm::vec3 & + GetPos() + { + return pos; + } + + glm::vec2 & + GetTexCoord() + { + return texCoord; + } + + glm::vec3 & + GetNormal() + { + return normal; + } + +private: + glm::vec3 pos; + glm::vec2 texCoord; + glm::vec3 normal; +}; + +#endif diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 7f67ad4..0000000 --- a/main.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "camera.h" -#include "display.h" -#include "mesh.h" -#include "shader.h" -#include "texture.h" -#include "transform.h" -#include -#include -#include -#include -#include - -static const int DISPLAY_WIDTH = 800; -static const int DISPLAY_HEIGHT = 600; - -int -main(int, char **) -{ - Display display(DISPLAY_WIDTH, DISPLAY_HEIGHT, "OpenGL"); - - Mesh monkey("./res/monkey3.obj"); - Shader shader("./res/basicShader"); - Texture texture("./res/bricks.jpg"); - Transform transform; - Camera camera(glm::vec3(0.0F, 0.0F, -5.0F), 70.0F, (float)DISPLAY_WIDTH / (float)DISPLAY_HEIGHT, 0.1F, 100.0F); - - SDL_Event e; - bool isRunning = true; - float counter = 0.0F; - while (isRunning) { - while (SDL_PollEvent(&e)) { - if (e.type == SDL_QUIT) { - isRunning = false; - } - } - - display.Clear(0.0F, 0.0F, 0.0F, 1.0F); - - // float sinCounter = sinf(counter); - // float absSinCounter = abs(sinCounter); - - // transform.GetPos()->x = sinCounter; - transform.GetRot().y = std::numbers::pi_v + sin(counter); - transform.GetRot().z = 0.3 * cos(counter * 10); - // transform.GetScale()->x = absSinCounter; - // transform.GetScale()->y = absSinCounter; - - shader.Bind(); - texture.Bind(); - shader.Update(transform, camera); - monkey.Draw(); - - display.SwapBuffers(); - SDL_Delay(1); - counter += 0.01F; - } - - return 0; -} diff --git a/mesh.cpp b/mesh.cpp deleted file mode 100644 index 8c304b3..0000000 --- a/mesh.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "mesh.h" -#include "obj_loader.h" -#include "vertex.hpp" -#include -#include -#include - -Mesh::Mesh(const std::string & fileName) : Mesh(OBJModel(fileName).ToIndexedModel()) { } - -Mesh::Mesh(const IndexedModel & model) : - m_vertexArrayObject {}, m_vertexArrayBuffers {}, m_numIndices {model.indices.size()} -{ - glGenVertexArrays(1, &m_vertexArrayObject); - glBindVertexArray(m_vertexArrayObject); - - glGenBuffers(NUM_BUFFERS, m_vertexArrayBuffers.data()); - - glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[POSITION_VB]); - glBufferData( - GL_ARRAY_BUFFER, sizeof(model.positions[0]) * model.positions.size(), &model.positions[0], GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[TEXCOORD_VB]); - glBufferData( - GL_ARRAY_BUFFER, sizeof(model.texCoords[0]) * model.texCoords.size(), &model.texCoords[0], GL_STATIC_DRAW); - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, m_vertexArrayBuffers[NORMAL_VB]); - glBufferData(GL_ARRAY_BUFFER, sizeof(model.normals[0]) * model.normals.size(), &model.normals[0], GL_STATIC_DRAW); - glEnableVertexAttribArray(2); - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, nullptr); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_vertexArrayBuffers[INDEX_VB]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(model.indices[0]) * model.indices.size(), &model.indices[0], - GL_STATIC_DRAW); - - glBindVertexArray(0); -} - -Mesh::Mesh(Vertex * vertices, unsigned int numVertices, unsigned int * indices, unsigned int numIndices) : - Mesh {[vertices, numVertices, indices, numIndices]() { - IndexedModel model; - - for (unsigned int i = 0; i < numVertices; i++) { - model.positions.push_back(vertices[i].GetPos()); - model.texCoords.push_back(vertices[i].GetTexCoord()); - model.normals.push_back(vertices[i].GetNormal()); - } - - for (unsigned int i = 0; i < numIndices; i++) { - model.indices.push_back(indices[i]); - } - - return model; - }()} -{ -} - -Mesh::~Mesh() -{ - glDeleteBuffers(NUM_BUFFERS, m_vertexArrayBuffers.data()); - glDeleteVertexArrays(1, &m_vertexArrayObject); -} - -void -Mesh::Draw() -{ - glBindVertexArray(m_vertexArrayObject); - - glDrawElementsBaseVertex(GL_TRIANGLES, m_numIndices, GL_UNSIGNED_INT, nullptr, 0); - - glBindVertexArray(0); -} diff --git a/mesh.h b/mesh.h deleted file mode 100644 index 69f41b9..0000000 --- a/mesh.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef MESH_INCLUDED_H -#define MESH_INCLUDED_H - -#include -#include -#include -#include - -class IndexedModel; -class Vertex; - -enum MeshBufferPositions { POSITION_VB, TEXCOORD_VB, NORMAL_VB, INDEX_VB }; - -class Mesh { -public: - explicit Mesh(const std::string & fileName); - explicit Mesh(const IndexedModel & model); - Mesh(Vertex * vertices, unsigned int numVertices, unsigned int * indices, unsigned int numIndices); - Mesh(const Mesh &) = delete; - void operator=(const Mesh &) = delete; - - virtual ~Mesh(); - - void Draw(); - -private: - static constexpr unsigned int NUM_BUFFERS {4}; - - GLuint m_vertexArrayObject; - std::array m_vertexArrayBuffers; - size_t m_numIndices; -}; - -#endif diff --git a/obj_loader.cpp b/obj_loader.cpp deleted file mode 100644 index 7611a2c..0000000 --- a/obj_loader.cpp +++ /dev/null @@ -1,428 +0,0 @@ -#include "obj_loader.h" -#include -#include -#include -#include -#include -#include - -static bool CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b); -static inline unsigned int FindNextChar(unsigned int start, const char * str, unsigned int length, char token); -static inline unsigned int ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end); -static inline float ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end); -static inline std::vector SplitString(const std::string & s, char delim); - -OBJModel::OBJModel(const std::string & fileName) -{ - hasUVs = false; - hasNormals = false; - std::ifstream file; - file.open(fileName.c_str()); - - std::string line; - if (file.is_open()) { - while (file.good()) { - getline(file, line); - - unsigned int lineLength = line.length(); - - if (lineLength < 2) { - continue; - } - - const char * lineCStr = line.c_str(); - - switch (lineCStr[0]) { - case 'v': - switch (lineCStr[1]) { - case 't': - this->uvs.push_back(ParseOBJVec2(line)); - break; - case 'n': - this->normals.push_back(ParseOBJVec3(line)); - break; - case ' ': - case '\t': - this->vertices.push_back(ParseOBJVec3(line)); - } - break; - case 'f': - CreateOBJFace(line); - break; - default: - break; - }; - } - } - else { - throw std::runtime_error {"Unable to load mesh: " + fileName}; - } -} - -void -IndexedModel::CalcNormals() -{ - for (unsigned int i = 0; i < indices.size(); i += 3) { - int i0 = indices[i]; - int i1 = indices[i + 1]; - int i2 = indices[i + 2]; - - glm::vec3 v1 = positions[i1] - positions[i0]; - glm::vec3 v2 = positions[i2] - positions[i0]; - - glm::vec3 normal = glm::normalize(glm::cross(v1, v2)); - - normals[i0] += normal; - normals[i1] += normal; - normals[i2] += normal; - } - - for (unsigned int i = 0; i < positions.size(); i++) { - normals[i] = glm::normalize(normals[i]); - } -} - -IndexedModel -OBJModel::ToIndexedModel() -{ - IndexedModel result; - IndexedModel normalModel; - - unsigned int numIndices = OBJIndices.size(); - - std::vector indexLookup; - - for (unsigned int i = 0; i < numIndices; i++) { - indexLookup.push_back(&OBJIndices[i]); - } - - std::sort(indexLookup.begin(), indexLookup.end(), CompareOBJIndexPtr); - - std::map normalModelIndexMap; - std::map indexMap; - - for (unsigned int i = 0; i < numIndices; i++) { - OBJIndex * currentIndex = &OBJIndices[i]; - - glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; - glm::vec2 currentTexCoord; - glm::vec3 currentNormal; - - if (hasUVs) { - currentTexCoord = uvs[currentIndex->uvIndex]; - } - else { - currentTexCoord = glm::vec2(0, 0); - } - - if (hasNormals) { - currentNormal = normals[currentIndex->normalIndex]; - } - else { - currentNormal = glm::vec3(0, 0, 0); - } - - unsigned int normalModelIndex; - unsigned int resultModelIndex; - - // Create model to properly generate normals on - const auto it = normalModelIndexMap.find(*currentIndex); - if (it == normalModelIndexMap.end()) { - normalModelIndex = normalModel.positions.size(); - - normalModelIndexMap.insert(std::pair(*currentIndex, normalModelIndex)); - normalModel.positions.push_back(currentPosition); - normalModel.texCoords.push_back(currentTexCoord); - normalModel.normals.push_back(currentNormal); - } - else { - normalModelIndex = it->second; - } - - // Create model which properly separates texture coordinates - unsigned int previousVertexLocation = FindLastVertexIndex(indexLookup, currentIndex, result); - - if (previousVertexLocation == (unsigned int)-1) { - resultModelIndex = result.positions.size(); - - result.positions.push_back(currentPosition); - result.texCoords.push_back(currentTexCoord); - result.normals.push_back(currentNormal); - } - else { - resultModelIndex = previousVertexLocation; - } - - normalModel.indices.push_back(normalModelIndex); - result.indices.push_back(resultModelIndex); - indexMap.insert(std::pair(resultModelIndex, normalModelIndex)); - } - - if (!hasNormals) { - normalModel.CalcNormals(); - - for (unsigned int i = 0; i < result.positions.size(); i++) { - result.normals[i] = normalModel.normals[indexMap[i]]; - } - } - - return result; -}; - -unsigned int -OBJModel::FindLastVertexIndex( - const std::vector & indexLookup, const OBJIndex * currentIndex, const IndexedModel & result) -{ - unsigned int start = 0; - unsigned int end = indexLookup.size(); - unsigned int current = (end - start) / 2 + start; - unsigned int previous = start; - - while (current != previous) { - OBJIndex * testIndex = indexLookup[current]; - - if (testIndex->vertexIndex == currentIndex->vertexIndex) { - unsigned int countStart = current; - - for (unsigned int i = 0; i < current; i++) { - OBJIndex * possibleIndex = indexLookup[current - i]; - - if (possibleIndex == currentIndex) { - continue; - } - - if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { - break; - } - - countStart--; - } - - for (unsigned int i = countStart; i < indexLookup.size() - countStart; i++) { - OBJIndex * possibleIndex = indexLookup[current + i]; - - if (possibleIndex == currentIndex) { - continue; - } - - if (possibleIndex->vertexIndex != currentIndex->vertexIndex) { - break; - } - else if ((!hasUVs || possibleIndex->uvIndex == currentIndex->uvIndex) - && (!hasNormals || possibleIndex->normalIndex == currentIndex->normalIndex)) { - glm::vec3 currentPosition = vertices[currentIndex->vertexIndex]; - glm::vec2 currentTexCoord; - glm::vec3 currentNormal; - - if (hasUVs) { - currentTexCoord = uvs[currentIndex->uvIndex]; - } - else { - currentTexCoord = glm::vec2(0, 0); - } - - if (hasNormals) { - currentNormal = normals[currentIndex->normalIndex]; - } - else { - currentNormal = glm::vec3(0, 0, 0); - } - - for (unsigned int j = 0; j < result.positions.size(); j++) { - if (currentPosition == result.positions[j] - && ((!hasUVs || currentTexCoord == result.texCoords[j]) - && (!hasNormals || currentNormal == result.normals[j]))) { - return j; - } - } - } - } - - return -1; - } - else { - if (testIndex->vertexIndex < currentIndex->vertexIndex) { - start = current; - } - else { - end = current; - } - } - - previous = current; - current = (end - start) / 2 + start; - } - - return -1; -} - -void -OBJModel::CreateOBJFace(const std::string & line) -{ - std::vector tokens = SplitString(line, ' '); - - this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[2], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); - - if ((int)tokens.size() > 4) { - this->OBJIndices.push_back(ParseOBJIndex(tokens[1], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[3], &this->hasUVs, &this->hasNormals)); - this->OBJIndices.push_back(ParseOBJIndex(tokens[4], &this->hasUVs, &this->hasNormals)); - } -} - -OBJIndex -OBJModel::ParseOBJIndex(const std::string & token, bool * hasUVs, bool * hasNormals) -{ - unsigned int tokenLength = token.length(); - const char * tokenString = token.c_str(); - - unsigned int vertIndexStart = 0; - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - OBJIndex result { - .vertexIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd), - .uvIndex = 0, - .normalIndex = 0, - }; - - if (vertIndexEnd >= tokenLength) { - return result; - } - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - result.uvIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); - *hasUVs = true; - - if (vertIndexEnd >= tokenLength) { - return result; - } - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, '/'); - - result.normalIndex = ParseOBJIndexValue(token, vertIndexStart, vertIndexEnd); - *hasNormals = true; - - return result; -} - -glm::vec3 -OBJModel::ParseOBJVec3(const std::string & line) -{ - unsigned int tokenLength = line.length(); - const char * tokenString = line.c_str(); - - unsigned int vertIndexStart = 2; - - while (vertIndexStart < tokenLength) { - if (tokenString[vertIndexStart] != ' ') { - break; - } - vertIndexStart++; - } - - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float z = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - return glm::vec3(x, y, z); -} - -glm::vec2 -OBJModel::ParseOBJVec2(const std::string & line) -{ - unsigned int tokenLength = line.length(); - const char * tokenString = line.c_str(); - - unsigned int vertIndexStart = 3; - - while (vertIndexStart < tokenLength) { - if (tokenString[vertIndexStart] != ' ') { - break; - } - vertIndexStart++; - } - - unsigned int vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float x = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - vertIndexStart = vertIndexEnd + 1; - vertIndexEnd = FindNextChar(vertIndexStart, tokenString, tokenLength, ' '); - - float y = ParseOBJFloatValue(line, vertIndexStart, vertIndexEnd); - - return glm::vec2(x, y); -} - -static bool -CompareOBJIndexPtr(const OBJIndex * a, const OBJIndex * b) -{ - return a->vertexIndex < b->vertexIndex; -} - -static inline unsigned int -FindNextChar(unsigned int start, const char * str, unsigned int length, char token) -{ - unsigned int result = start; - while (result < length) { - result++; - if (str[result] == token) { - break; - } - } - - return result; -} - -static inline unsigned int -ParseOBJIndexValue(const std::string & token, unsigned int start, unsigned int end) -{ - return std::stoul(token.substr(start, end - start)) - 1; -} - -static inline float -ParseOBJFloatValue(const std::string & token, unsigned int start, unsigned int end) -{ - return std::stof(token.substr(start, end - start)); -} - -static inline std::vector -SplitString(const std::string & s, char delim) -{ - std::vector elems; - - const char * cstr = s.c_str(); - unsigned int strLength = s.length(); - unsigned int start = 0; - unsigned int end = 0; - - while (end <= strLength) { - while (end <= strLength) { - if (cstr[end] == delim) { - break; - } - end++; - } - - elems.push_back(s.substr(start, end - start)); - start = end + 1; - end = start; - } - - return elems; -} diff --git a/obj_loader.h b/obj_loader.h deleted file mode 100644 index 11c6b38..0000000 --- a/obj_loader.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef OBJ_LOADER_H_INCLUDED -#define OBJ_LOADER_H_INCLUDED - -#include -#include -#include - -struct OBJIndex { - unsigned int vertexIndex; - unsigned int uvIndex; - unsigned int normalIndex; - - bool - operator<(const OBJIndex & r) const - { - return vertexIndex < r.vertexIndex; - } -}; - -class IndexedModel { -public: - std::vector positions; - std::vector texCoords; - std::vector normals; - std::vector indices; - - void CalcNormals(); -}; - -class OBJModel { -public: - std::vector OBJIndices; - std::vector vertices; - std::vector uvs; - std::vector normals; - bool hasUVs; - bool hasNormals; - - explicit OBJModel(const std::string & fileName); - - IndexedModel ToIndexedModel(); - -private: - unsigned int FindLastVertexIndex( - const std::vector & indexLookup, const OBJIndex * currentIndex, const IndexedModel & result); - void CreateOBJFace(const std::string & line); - - glm::vec2 ParseOBJVec2(const std::string & line); - glm::vec3 ParseOBJVec3(const std::string & line); - OBJIndex ParseOBJIndex(const std::string & token, bool * hasUVs, bool * hasNormals); -}; - -#endif // OBJ_LOADER_H_INCLUDED diff --git a/ptr.hpp b/ptr.hpp deleted file mode 100644 index b92b63e..0000000 --- a/ptr.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef PTR_H -#define PTR_H - -#include - -template class wrapped_ptr : public std::unique_ptr { -public: - using std::unique_ptr::unique_ptr; - wrapped_ptr() : std::unique_ptr {{}, {}} { } - - inline - operator Obj *() const - { - return this->get(); - } - - template - static auto - create(Obj * (*factory)(Args...), void (*deleter)(Obj *), Params &&... params) - { - return wrapped_ptr {factory(std::forward(params)...), deleter}; - } -}; - -#endif diff --git a/res/basicShader.fs b/res/basicShader.fs deleted file mode 100644 index 3aa974f..0000000 --- a/res/basicShader.fs +++ /dev/null @@ -1,13 +0,0 @@ -#version 120 - -varying vec2 texCoord0; -varying vec3 normal0; - -uniform sampler2D sampler; -uniform vec3 lightDirection; - -void main() -{ - gl_FragColor = texture2D(sampler, texCoord0) * - clamp(dot(-lightDirection, normal0), 0.0, 1.0); -} diff --git a/res/basicShader.vs b/res/basicShader.vs deleted file mode 100644 index e673548..0000000 --- a/res/basicShader.vs +++ /dev/null @@ -1,18 +0,0 @@ -#version 120 - -attribute vec3 position; -attribute vec2 texCoord; -attribute vec3 normal; - -varying vec2 texCoord0; -varying vec3 normal0; - -uniform mat4 MVP; -uniform mat4 Normal; - -void main() -{ - gl_Position = MVP * vec4(position, 1.0); - texCoord0 = texCoord; - normal0 = (Normal * vec4(normal, 0.0)).xyz; -} diff --git a/shader.cpp b/shader.cpp deleted file mode 100644 index 4d9f43b..0000000 --- a/shader.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#include "shader.h" -#include "transform.h" -#include -#include -#include -#include - -Shader::Shader(const std::string &) : - m_program {glCreateProgram()}, m_shaders {CreateShader( - (GLchar *)(basicShader_vs), basicShader_vs_len, GL_VERTEX_SHADER), - CreateShader( - (GLchar *)basicShader_fs, basicShader_fs_len, GL_FRAGMENT_SHADER)}, - m_uniforms {} -{ - for (auto m_shader : m_shaders) { - glAttachShader(m_program, m_shader); - } - - glBindAttribLocation(m_program, 0, "position"); - glBindAttribLocation(m_program, 1, "texCoord"); - glBindAttribLocation(m_program, 2, "normal"); - - glLinkProgram(m_program); - CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program"); - - glValidateProgram(m_program); - CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program"); - - m_uniforms = {glGetUniformLocation(m_program, "MVP"), glGetUniformLocation(m_program, "Normal"), - glGetUniformLocation(m_program, "lightDirection")}; -} - -Shader::~Shader() -{ - for (auto m_shader : m_shaders) { - glDetachShader(m_program, m_shader); - glDeleteShader(m_shader); - } - - glDeleteProgram(m_program); -} - -void -Shader::Bind() const -{ - glUseProgram(m_program); -} - -void -Shader::Update(const Transform & transform, const Camera & camera) const -{ - glm::mat4 MVP = transform.GetMVP(camera); - glm::mat4 Normal = transform.GetModel(); - - glUniformMatrix4fv(m_uniforms[0], 1, GL_FALSE, &MVP[0][0]); - glUniformMatrix4fv(m_uniforms[1], 1, GL_FALSE, &Normal[0][0]); - glUniform3f(m_uniforms[2], 0.0F, 0.0F, 1.0F); -} - -void -Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage) -{ - GLint success = 0; - std::array error {}; - - if (isProgram) { - glGetProgramiv(shader, flag, &success); - } - else { - glGetShaderiv(shader, flag, &success); - } - - if (success == GL_FALSE) { - if (isProgram) { - glGetProgramInfoLog(shader, error.size(), nullptr, error.data()); - } - else { - glGetShaderInfoLog(shader, error.size(), nullptr, error.data()); - } - - throw std::runtime_error {errorMessage + ": '" + std::string {error.data(), error.size()} + "'"}; - } -} - -GLuint -Shader::CreateShader(const GLchar * text, GLint len, unsigned int type) -{ - GLuint shader = glCreateShader(type); - - if (shader == 0) { - throw std::runtime_error {"Error compiling shader type " + std::to_string(type)}; - } - - glShaderSource(shader, 1, &text, &len); - glCompileShader(shader); - - CheckShaderError(shader, GL_COMPILE_STATUS, false, "Error compiling shader!"); - - return shader; -} diff --git a/shader.h b/shader.h deleted file mode 100644 index 85a7d58..0000000 --- a/shader.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef SHADER_INCLUDED_H -#define SHADER_INCLUDED_H - -#include -#include -#include - -class Camera; -class Transform; - -class Shader { -public: - explicit Shader(const std::string & fileName); - virtual ~Shader(); - void operator=(const Shader &) = delete; - Shader(const Shader &) = delete; - - void Bind() const; - void Update(const Transform & transform, const Camera & camera) const; - -private: - static constexpr unsigned int NUM_SHADERS = 2; - static constexpr unsigned int NUM_UNIFORMS = 3; - - static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, const std::string & errorMessage); - static GLuint CreateShader(const GLchar * text, GLint len, unsigned int type); - - GLuint m_program; - std::array m_shaders; - std::array m_uniforms; -}; - -#endif diff --git a/stb_image.c b/stb_image.c deleted file mode 100644 index a839b61..0000000 --- a/stb_image.c +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef TIDY -# define STB_IMAGE_IMPLEMENTATION -# pragma GCC diagnostic ignored "-Wsign-compare" -# ifndef __clang__ -# pragma GCC diagnostic ignored "-Wunused-but-set-variable" -# endif -# include "stb_image.h" -#endif diff --git a/texture.cpp b/texture.cpp deleted file mode 100644 index a388b32..0000000 --- a/texture.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "texture.h" -#include "stb_image.h" -#include - -Texture::Texture(const std::string & fileName) : m_texture {} -{ - int width, height, numComponents; - unsigned char * data = stbi_load((fileName).c_str(), &width, &height, &numComponents, 4); - - if (!data) { - throw std::runtime_error {"Unable to load texture: " + fileName}; - } - - glGenTextures(1, &m_texture); - glBindTexture(GL_TEXTURE_2D, m_texture); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - stbi_image_free(data); -} - -Texture::~Texture() -{ - glDeleteTextures(1, &m_texture); -} - -void -Texture::Bind() const -{ - glBindTexture(GL_TEXTURE_2D, m_texture); -} diff --git a/texture.h b/texture.h deleted file mode 100644 index 9955f01..0000000 --- a/texture.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef TEXTURE_H -#define TEXTURE_H - -#include -#include - -class Texture { -public: - explicit Texture(const std::string & fileName); - - Texture(const Texture &) = delete; - void operator=(const Texture &) = delete; - - virtual ~Texture(); - - void Bind() const; - -protected: -private: - GLuint m_texture; -}; - -#endif diff --git a/transform.cpp b/transform.cpp deleted file mode 100644 index 7b256af..0000000 --- a/transform.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "transform.h" -#include "camera.h" -#include - -Transform::Transform(glm::vec3 pos, glm::vec3 rot, glm::vec3 scale) : pos {pos}, rot {rot}, scale {scale} { } - -glm::mat4 -Transform::GetModel() const -{ - const auto posMat = glm::translate(pos); - const auto scaleMat = glm::scale(scale); - const auto rotX = glm::rotate(rot.x, glm::vec3(1.0, 0.0, 0.0)); - const auto rotY = glm::rotate(rot.y, glm::vec3(0.0, 1.0, 0.0)); - const auto rotZ = glm::rotate(rot.z, glm::vec3(0.0, 0.0, 1.0)); - const auto rotMat = rotX * rotY * rotZ; - - return posMat * rotMat * scaleMat; -} - -glm::mat4 -Transform::GetMVP(const Camera & camera) const -{ - const auto VP = camera.GetViewProjection(); - const auto M = GetModel(); - - return VP * M; -} diff --git a/transform.h b/transform.h deleted file mode 100644 index 783ef31..0000000 --- a/transform.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef TRANSFORM_INCLUDED_H -#define TRANSFORM_INCLUDED_H - -#include -#include - -class Camera; - -class Transform { -public: - Transform(glm::vec3 pos = {}, glm::vec3 rot = {}, glm::vec3 scale = {1.0f, 1.0f, 1.0f}); - - glm::mat4 GetModel() const; - - glm::mat4 GetMVP(const Camera & camera) const; - - inline glm::vec3 & - GetPos() - { - return pos; - } - - inline glm::vec3 & - GetRot() - { - return rot; - } - - inline glm::vec3 & - GetScale() - { - return scale; - } - - inline void - SetPos(glm::vec3 && pos) - { - this->pos = std::move(pos); - } - - inline void - SetRot(glm::vec3 && rot) - { - this->rot = std::move(rot); - } - - inline void - SetScale(glm::vec3 && scale) - { - this->scale = std::move(scale); - } - -private: - glm::vec3 pos; - glm::vec3 rot; - glm::vec3 scale; -}; - -#endif diff --git a/util.h b/util.h deleted file mode 100644 index 83de626..0000000 --- a/util.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef UTIL_H_INCLUDED -#define UTIL_H_INCLUDED - -#include -#include - -namespace Util { - std::vector - Split(const std::string & s, char delim) - { - std::vector elems; - - const char * cstr = s.c_str(); - unsigned int strLength = s.length(); - unsigned int start = 0; - unsigned int end = 0; - - while (end <= strLength) { - while (end <= strLength) { - if (cstr[end] == delim) - break; - end++; - } - - elems.push_back(s.substr(start, end - start)); - start = end + 1; - end = start; - } - - return elems; - } -}; - -#endif // UTIL_H_INCLUDED diff --git a/utility/ptr.hpp b/utility/ptr.hpp new file mode 100644 index 0000000..b92b63e --- /dev/null +++ b/utility/ptr.hpp @@ -0,0 +1,25 @@ +#ifndef PTR_H +#define PTR_H + +#include + +template class wrapped_ptr : public std::unique_ptr { +public: + using std::unique_ptr::unique_ptr; + wrapped_ptr() : std::unique_ptr {{}, {}} { } + + inline + operator Obj *() const + { + return this->get(); + } + + template + static auto + create(Obj * (*factory)(Args...), void (*deleter)(Obj *), Params &&... params) + { + return wrapped_ptr {factory(std::forward(params)...), deleter}; + } +}; + +#endif diff --git a/utility/special_members.hpp b/utility/special_members.hpp new file mode 100644 index 0000000..f396813 --- /dev/null +++ b/utility/special_members.hpp @@ -0,0 +1,12 @@ +#ifndef SPECIAL_MEMBERS_H +#define SPECIAL_MEMBERS_H + +#define NO_COPY(TYPE) \ + TYPE(const TYPE &) = delete; \ + void operator=(const TYPE &) = delete + +#define NO_MOVE(TYPE) \ + TYPE(TYPE &&) = delete; \ + void operator=(TYPE &&) = delete + +#endif diff --git a/vertex.hpp b/vertex.hpp deleted file mode 100644 index 3f6514b..0000000 --- a/vertex.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef VERTEX_H -#define VERTEX_H - -#include - -class Vertex { -public: - Vertex(glm::vec3 pos, glm::vec2 texCoord, glm::vec3 normal) : - pos {std::move(pos)}, texCoord {std::move(texCoord)}, normal {std::move(normal)} - { - } - - glm::vec3 & - GetPos() - { - return pos; - } - - glm::vec2 & - GetTexCoord() - { - return texCoord; - } - - glm::vec3 & - GetNormal() - { - return normal; - } - -private: - glm::vec3 pos; - glm::vec2 texCoord; - glm::vec3 normal; -}; -#endif -- cgit v1.2.3