restructured project to encapsulate backend into library

This commit is contained in:
Lauchmelder 2021-12-21 15:51:54 +01:00
parent 01f5a26aa6
commit 19cae22aba
12 changed files with 29 additions and 11 deletions

View file

@ -1,10 +1,8 @@
add_executable(visualizer
"main.cpp" "Application.cpp"
"backend/VertexArrayObject.cpp" "backend/Shader.cpp" "Cuboid.cpp" "backend/Drawable.cpp" "backend/Transformable.cpp")
"main.cpp" "Application.cpp" "Cuboid.cpp"
)
target_sources(visualizer PUBLIC
${VENDOR_DIR}/glad/src/glad.c
${VENDOR_DIR}/imgui/backends/imgui_impl_opengl3.cpp
${VENDOR_DIR}/imgui/backends/imgui_impl_glfw.cpp
${VENDOR_DIR}/imgui/imgui.cpp
@ -16,12 +14,11 @@ target_sources(visualizer PUBLIC
target_include_directories(visualizer PRIVATE
${GLFW3_INCLUDE_DIRS}
${GLM_INCLUDE_DIRS}
${VENDOR_DIR}/glad/include
${VENDOR_DIR}/imgui
backend
)
target_link_libraries(visualizer PRIVATE
${GLFW3_LIBRARIES}
${GLM_LIBRARIES}
backend
)

View file

@ -1,13 +0,0 @@
#include "Drawable.hpp"
void Drawable::Render()
{
shader->Use();
InitializeShader();
vao->Render(static_cast<unsigned int>(type));
}
void Drawable::SetPrimitiveType(PrimitiveType type)
{
this->type = type;
}

View file

@ -1,36 +0,0 @@
#pragma once
#include <glad/glad.h>
#include "VertexArrayObject.hpp"
#include "Shader.hpp"
enum class PrimitiveType
{
Lines = GL_LINES,
LineStrip = GL_LINE_STRIP,
LineLoop = GL_LINE_LOOP,
Triangles = GL_TRIANGLES,
TriangleStrip = GL_TRIANGLE_STRIP,
TriangleFan = GL_TRIANGLE_FAN
};
class Drawable
{
public:
Drawable(const Drawable& other) = delete;
void operator=(const Drawable& other) = delete;
virtual void InitializeShader() = 0;
void Render();
void SetPrimitiveType(PrimitiveType type);
protected:
Drawable() {}
protected:
VertexArrayObject vao;
Shader shader;
PrimitiveType type = PrimitiveType::Triangles;
};

View file

@ -1,71 +0,0 @@
#pragma once
#include <map>
#include <memory>
/**
* Some objects should only exist once but be available to multiple objects (e.g. multiple
* models sharing the same VAO and shaders. Any object can register objects here and other
* objects can then retrieve them if they have the ID.
*
* Objects are stored and returned as shared_ptr's, so even if a part of the program deletes
* an object from the manager, any part of the program that has the objects stored in them will
* not break and still work. But realistically this shouldn't happen in the first place.
* As a consequence, even if no objects are using an object stored in here it will continue to
* exist.
*/
template<typename Type>
class ObjectManager
{
public:
static ObjectManager<Type>& GetInstance()
{
static ObjectManager<Type> instance;
return instance;
}
public:
ObjectManager(const ObjectManager<Type>&) = delete;
void operator=(const ObjectManager<Type>&) = delete;
/**
* Add new (existing) object to manager
*/
inline void Register(unsigned int id, std::shared_ptr<Type> obj)
{
objects.insert(std::make_pair(id, obj));
}
/**
* Remove object from manager
*/
inline void Delete(unsigned int id)
{
objects.erase(id);
}
/**
* Retrieve object from manager
*/
inline std::shared_ptr<Type> Get(unsigned int id)
{
auto it = objects.find(id);
if (it == objects.end())
return nullptr;
return it->second;
}
private:
ObjectManager() {}
private:
std::map<unsigned int, std::shared_ptr<Type>> objects;
};
class AbstractShader;
class AbstractVertexArrayObject;
typedef ObjectManager<AbstractVertexArrayObject> VAOManager;
typedef ObjectManager<AbstractShader> ShaderManager;

View file

@ -1,88 +0,0 @@
#include "Shader.hpp"
#include <iostream>
#include <glm/gtc/type_ptr.hpp>
#include <glad/glad.h>
#define IMPLEMENT_UNIFORM_FUNCTION(type, func) \
inline
AbstractShader::AbstractShader(const std::string& vertexShader, const std::string& fragmentShader) :
id(0)
{
GLint success;
GLchar infoLog[512];
GLuint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
const char* vertexShaderSource = vertexShader.c_str();
glShaderSource(vertexShaderID, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShaderID);
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderID, 512, NULL, infoLog);
std::cerr << "Vertex shader creation failed: \n" << infoLog << std::endl;
glDeleteShader(vertexShaderID);
return;
}
GLuint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
const char* fragmentShaderSource = fragmentShader.c_str();
glShaderSource(fragmentShaderID, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShaderID);
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShaderID, 512, NULL, infoLog);
std::cerr << "Fragment shader creation failed: \n" << infoLog << std::endl;
glDeleteShader(fragmentShaderID);
glDeleteShader(vertexShaderID);
return;
}
id = glCreateProgram();
glAttachShader(id, vertexShaderID);
glAttachShader(id, fragmentShaderID);
glLinkProgram(id);
glGetProgramiv(id, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(fragmentShaderID, 512, NULL, infoLog);
std::cerr << "Shader program linking failed: \n" << infoLog << std::endl;
glDeleteShader(fragmentShaderID);
glDeleteShader(vertexShaderID);
id = 0;
return;
}
glDeleteShader(fragmentShaderID);
glDeleteShader(vertexShaderID);
}
AbstractShader::~AbstractShader()
{
glDeleteProgram(id);
}
void AbstractShader::Use()
{
glUseProgram(id);
}
void AbstractShader::SetUniform(const std::string& name, const glm::mat4& value)
{
GLint location = glGetUniformLocation(id, name.c_str());
if (location == -1)
return;
glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
}

View file

@ -1,38 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <string>
#include <memory>
#include <functional>
class AbstractShader
{
friend class ShaderFactory;
public:
AbstractShader(const std::string& vertexShader, const std::string& fragmentShader);
AbstractShader(const AbstractShader& other) = delete;
~AbstractShader();
inline bool Good() { return id != 0; }
void Use();
void SetUniform(const std::string& name, const glm::mat4& value);
private:
unsigned int id;
bool recording = false;
};
typedef std::shared_ptr<AbstractShader> Shader;
class ShaderFactory
{
public:
inline static Shader Produce(const std::string& vertexShader, const std::string& fragmentShader)
{
return std::make_shared<AbstractShader>(vertexShader, fragmentShader);
}
};

View file

@ -1,72 +0,0 @@
#include "Transformable.hpp"
Transformable::Transformable() :
position(0.0f), scale(1.0f), orientation(0.0, 0.0, 0.0, 1.0)
{
CalculateTransformationMatrix();
}
const glm::vec3& Transformable::GetPosition()
{
return position;
}
void Transformable::SetPosition(const glm::vec3& pos)
{
position = pos;
CalculateTransformationMatrix();
}
void Transformable::Move(const glm::vec3& direction)
{
position += direction;
CalculateTransformationMatrix();
}
const glm::vec3 Transformable::GetRotation()
{
return glm::eulerAngles(orientation);
}
void Transformable::SetRotation(const glm::vec3& axis, float angle)
{
orientation = glm::quat(glm::radians(angle), axis);
CalculateTransformationMatrix();
}
void Transformable::SetRotation(const glm::vec3& eulerAngles)
{
orientation = glm::quat(eulerAngles);
CalculateTransformationMatrix();
}
void Transformable::Rotate(const glm::vec3& axis, float angle)
{
orientation = glm::rotate(orientation, glm::radians(angle), axis);
CalculateTransformationMatrix();
}
const glm::vec3& Transformable::GetScale()
{
return scale;
}
void Transformable::SetScale(const glm::vec3& scale)
{
this->scale = scale;
CalculateTransformationMatrix();
}
void Transformable::Scale(const glm::vec3& factor)
{
this->scale *= scale; // I pray this is component-wise multiplication
CalculateTransformationMatrix();
}
void Transformable::CalculateTransformationMatrix()
{
transformation = glm::mat4(1.0f);
transformation = glm::translate(transformation, position);
transformation *= glm::toMat4(orientation);
transformation = glm::scale(transformation, scale);
}

View file

@ -1,32 +0,0 @@
#pragma once
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
class Transformable
{
public:
Transformable();
const glm::vec3& GetPosition();
void SetPosition(const glm::vec3& pos);
void Move(const glm::vec3& direction);
const glm::vec3 GetRotation();
void SetRotation(const glm::vec3& axis, float angle);
void SetRotation(const glm::vec3& eulerAngles);
void Rotate(const glm::vec3& axis, float angle);
const glm::vec3& GetScale();
void SetScale(const glm::vec3& scale);
void Scale(const glm::vec3& factor);
private:
void CalculateTransformationMatrix();
protected:
glm::mat4 transformation;
glm::vec3 position, scale;
glm::quat orientation;
};

View file

@ -1,60 +0,0 @@
#include "VertexArrayObject.hpp"
#include <assert.h>
#include <glad/glad.h>
AbstractVertexArrayObject::~AbstractVertexArrayObject()
{
glDeleteBuffers(1, &ebo);
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
}
void AbstractVertexArrayObject::Render(GLenum mode)
{
assert(vao != 0);
glBindVertexArray(vao);
// GLenum result = glGetError();
glDrawElements(mode, indexCount, GL_UNSIGNED_INT, 0);
}
AbstractVertexArrayObject::AbstractVertexArrayObject(const VertexArray& vertices, const IndexArray& indices, const Layout& layout, Usage usage) :
vao(0), vbo(0), ebo(0), indexCount(indices.size())
{
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);
// Determing native OpenGL GLenum depending on specified usage
GLenum bufferUsage;
switch (usage)
{
case Usage::Static: bufferUsage = GL_STATIC_DRAW; break;
case Usage::Dynamic: bufferUsage = GL_DYNAMIC_DRAW; break;
case Usage::Stream: bufferUsage = GL_STREAM_DRAW; break;
default: // Forgot to add a usage case to this switch
assert("Unknown buffer usage" == "");
break;
}
// Create VBO
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), (const void*)(vertices.data()), bufferUsage);
// Create EBO
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), (const void*)(indices.data()), bufferUsage);
// Set up pipeline layout
unsigned int index = 0;
for (const VertexAttribute& attribute : layout)
{
glVertexAttribPointer(index, attribute.size, attribute.type, attribute.normalized, attribute.stride, attribute.pointer);
glEnableVertexAttribArray(index);
index++;
}
}

View file

@ -1,58 +0,0 @@
#pragma once
#include <vector>
#include <memory>
// struct representing an OpenGL attribute pointer
struct VertexAttribute
{
int size;
unsigned int type;
bool normalized;
unsigned int stride;
const void* pointer;
};
// Useful abbreviations
typedef std::vector<float> VertexArray;
typedef std::vector<unsigned int> IndexArray;
typedef std::vector<VertexAttribute> Layout;
// OpenGL Buffer usages (I turned them into an enum so it's easier to know what options exist)
enum class Usage
{
Static, Stream, Dynamic
};
// VAO structure that sets up the buffers and deletes them at the end of the lifecycle
class AbstractVertexArrayObject
{
friend class VAOFactory;
public:
AbstractVertexArrayObject() = delete;
AbstractVertexArrayObject(const VertexArray& vertices, const IndexArray& indices, const Layout& layout, Usage usage);
~AbstractVertexArrayObject();
void Render(unsigned int mode = 4);
private:
unsigned int vao, vbo, ebo;
size_t indexCount;
};
// You cannot actually create this VAO, you are forced to use a shared pointer
// so the buffers dont get accidentally deleted while another obejct is potentially still using it.
// I find this to be very important since VAOs are supposed to be shared between copies of objects
// if they have the same model.
typedef std::shared_ptr<AbstractVertexArrayObject> VertexArrayObject;
// Factory for creating said shared pointers.
class VAOFactory
{
public:
static VertexArrayObject Produce(const VertexArray& vertices, const IndexArray& indices, const Layout& layout, Usage usage = Usage::Static)
{
return std::make_shared<AbstractVertexArrayObject>(vertices, indices, layout, usage);
}
};