Compare commits

..

6 Commits

Author SHA1 Message Date
d69d982398 Add ability for client to override fixed and dynamic update 2021-04-30 23:11:01 +02:00
ff576182c4 Make Application create a GLFW Window 2021-04-30 22:40:42 +02:00
05a4fde2e7 Increase column width in clang-format 2021-04-30 22:40:27 +02:00
8b456f8d42 Add everything from the SPG project 2021-04-30 21:45:32 +02:00
a0e1bf8592 Add game loop to Application
Implements fixed and variable time steps.

Might be a moved to a separate class later.
2021-04-30 10:23:59 +02:00
eea3560b35 Add Time helper class 2021-04-30 10:23:37 +02:00
24 changed files with 9966 additions and 8 deletions

View File

@ -9,6 +9,6 @@ AllowShortLoopsOnASingleLine: false
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: true
IndentWidth: 4
ColumnLimit: 80
ColumnLimit: 120
...

View File

@ -6,7 +6,8 @@ def add_third_party_includes(env):
def add_strict_compile_flags(env):
env.Append(CCFLAGS=["-Wall", "-Wextra", "-Werror", "-pedantic"])
# TODO: Would be good to add "-Werror", but glad.c makes that break
env.Append(CCFLAGS=["-Wall", "-Wextra", "-pedantic", "-std=c++17"])
# Create the environment and create a Compilation Database for use in VSCodium
@ -14,12 +15,13 @@ env = Environment(tools=['default', 'compilation_db'])
env.CompilationDatabase()
env.Append(CPPPATH=['cpp/', 'include/'])
env.Append(LIBS=['glfw', 'dl'])
add_third_party_includes(env)
add_strict_compile_flags(env)
# Build the library
gedeng = env.SharedLibrary('lib/gedeng', Glob('cpp/*.cpp'))
gedeng = env.SharedLibrary('lib/gedeng', Glob('cpp/*.cpp') + ['cpp/vendor/glad.c'])
# Install the library to the test application's build directory
env.Install('test/bin/lib/', gedeng)

View File

@ -1,10 +1,36 @@
#include "Gedeng/Application.h"
#include "Gedeng/Input.h"
#include "Gedeng/Logger.h"
#include "Gedeng/RenderBackend.h"
#include "Gedeng/Time.h"
namespace Gedeng {
void Application::run() {
while (true) {
// TODO: Implement
// Setup Rendering
// FIXME: Make these parameters variable, maybe move this to a different function
RenderBackend::initialize_window(WINDOW_SIZE_X, WINDOW_SIZE_Y, WINDOW_NAME);
Input::initialize(RenderBackend::get_window());
unsigned long previous_time_ms = Time::get_time_ms();
unsigned long time_until_fixed_update_ms = 0.0;
while (!RenderBackend::does_window_want_to_close()) {
unsigned long current_time_ms = Time::get_time_ms();
unsigned long elapsed_time_ms = current_time_ms - previous_time_ms;
previous_time_ms = current_time_ms;
time_until_fixed_update_ms += elapsed_time_ms;
Input::poll_input();
// Update fixed time step
while (time_until_fixed_update_ms >= MS_PER_UPDATE) {
fixed_update(static_cast<double>(MS_PER_UPDATE) / 1000.0);
time_until_fixed_update_ms -= MS_PER_UPDATE;
}
dynamic_update(static_cast<double>(elapsed_time_ms) / 1000.0);
}
}

44
cpp/Framebuffer3D.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "Gedeng/Framebuffer3D.h"
namespace Gedeng {
Framebuffer3D::Framebuffer3D(int width, int height, int depth) {
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_3D, texture);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage3D(GL_TEXTURE_3D, 0, GL_R32F, width, height, depth, 0, GL_RED, GL_FLOAT, nullptr);
glGenFramebuffers(1, &buffer);
glBindFramebuffer(GL_FRAMEBUFFER, buffer);
GLenum c = GL_COLOR_ATTACHMENT0;
glFramebufferTexture3D(GL_FRAMEBUFFER, c, GL_TEXTURE_3D, texture, 0, 0);
glDrawBuffers(1, &c);
}
Framebuffer3D::~Framebuffer3D() {
glDeleteFramebuffers(1, &buffer);
glDeleteTextures(1, &texture);
}
void Framebuffer3D::bind_and_clear() {
glBindFramebuffer(GL_FRAMEBUFFER, buffer);
glClear(GL_COLOR_BUFFER_BIT);
}
void Framebuffer3D::bind_to(int unit) const {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_3D, texture);
}
void Framebuffer3D::bind_layer(int layer) {
glBindFramebuffer(GL_FRAMEBUFFER, buffer);
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture, 0, layer);
}
}

44
cpp/RenderBackend.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "Gedeng/RenderBackend.h"
namespace Gedeng {
void RenderBackend::initialize_window(unsigned int width, unsigned int height, String title) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
window = glfwCreateWindow(width, height, title, NULL, NULL);
glfwMakeContextCurrent(window);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
}
bool RenderBackend::is_window_created() {
return window != nullptr;
}
void RenderBackend::set_depth_test_enabled(bool enabled) {
if (enabled) {
glEnable(GL_DEPTH_TEST);
} else {
glDisable(GL_DEPTH_TEST);
}
}
bool RenderBackend::does_window_want_to_close() {
return glfwWindowShouldClose(window);
}
GLFWwindow *RenderBackend::get_window() {
return window;
}
void RenderBackend::render() {
glfwSwapBuffers(window);
}
} // namespace Gedeng

60
cpp/Texture.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "Gedeng/Texture.h"
#include <iostream>
#define STB_IMAGE_IMPLEMENTATION
#include "vendor/stb_image.h"
namespace Gedeng {
bool Texture::is_valid() const {
return valid;
}
uint Texture::load_texture(const std::string &path, Settings settings) {
uint gl_id;
glGenTextures(1, &gl_id);
glBindTexture(GL_TEXTURE_2D, gl_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (settings.mipmaps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
unsigned char *data = stbi_load(path.c_str(), &width, &height, &nrChannels, 0);
if (data) {
// Check number of channels
unsigned int glChannels = GL_RED;
if (nrChannels == 3)
glChannels = GL_RGB;
else if (nrChannels == 4)
glChannels = GL_RGBA;
glTexImage2D(GL_TEXTURE_2D, 0, glChannels, width, height, 0, glChannels, GL_UNSIGNED_BYTE,
data);
if (settings.mipmaps) {
glGenerateMipmap(GL_TEXTURE_2D);
}
valid = true;
}
stbi_image_free(data);
return gl_id;
}
void Texture::bind_to(int unit) {
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, id);
}
}

14
cpp/Time.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "Gedeng/Time.h"
#include <chrono>
namespace Gedeng {
unsigned long Time::get_time_ms() {
auto now = std::chrono::high_resolution_clock::now();
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(now);
return now_ms.time_since_epoch().count();
}
}

41
cpp/VertexBuffer.cpp Normal file
View File

@ -0,0 +1,41 @@
#include "Gedeng/VertexBuffer.h"
namespace Gedeng {
VertexBuffer::VertexBuffer() {
glGenVertexArrays(1, &vertex_array);
glGenBuffers(1, &vertex_buffer);
}
void VertexBuffer::set_data(int size, int dimension, const void *data, int flag) {
// We can't just do size = sizeof(data) here because of array to pointer decay!
this->size = size;
bind_array();
bind_buffer();
// Create the data on the GPU
glBufferData(GL_ARRAY_BUFFER, size, data, flag);
// Specify the dimension of the vectors in the data, so that the GPU knows how much to read from
// it at a time. (Currently only one type of vector is supported)
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, dimension, GL_FLOAT, false, dimension * sizeof(float), 0);
glBindVertexArray(0);
}
void VertexBuffer::bind_buffer() {
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
}
void VertexBuffer::bind_array() {
glBindVertexArray(vertex_array);
}
void VertexBuffer::draw() {
bind_array();
glDrawArrays(GL_TRIANGLES, 0, size);
}
}

1545
cpp/vendor/glad.c vendored Normal file

File diff suppressed because it is too large Load Diff

7559
cpp/vendor/stb_image.h vendored Normal file

File diff suppressed because it is too large Load Diff

2
cpp/vendor/stb_setup.cpp vendored Normal file
View File

@ -0,0 +1,2 @@
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

View File

@ -4,5 +4,14 @@
#include "Gedeng/Logger.h"
#include "Gedeng/String.h"
#include "Gedeng/Vector.h"
#include "Gedeng/Time.h"
#include "Gedeng/Shader.h"
#include "Gedeng/QuadMesh.h"
#include "Gedeng/Spatial.h"
#include "Gedeng/Texture.h"
#include "Gedeng/Camera.h"
#include "Gedeng/VertexBuffer.h"
#include "Gedeng/Framebuffer3D.h"
#include "Gedeng/Input.h"
#include "Gedeng/EntryPoint.h"

View File

@ -1,15 +1,39 @@
#pragma once
#include "String.h"
namespace Gedeng {
class Application {
public:
Application() = default;
Application(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y, String window_name)
: MS_PER_UPDATE(ms_per_update), WINDOW_SIZE_X(window_size_x), WINDOW_SIZE_Y(window_size_y),
WINDOW_NAME(window_name) {
}
// Virtual since this class will be inherited by user-created applications
virtual ~Application() = default;
// Game Loop
void run();
// Primarily for gameplay and physics
// To be overridden by client applications
virtual void fixed_update(double delta) = 0;
// Primarily for rendering
// To be overridden by client applications
virtual void dynamic_update(double delta) = 0;
// TODO: Write note for this: `undefined reference to vtable` can be caused by forgetting `= 0` for pure virtual
// stuff
private:
// TODO: These will probably become a separate Settings struct
const unsigned long MS_PER_UPDATE;
const unsigned int WINDOW_SIZE_X;
const unsigned int WINDOW_SIZE_Y;
const String WINDOW_NAME;
};
// To be defined in client applications

31
include/Gedeng/Camera.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/dual_quaternion.hpp>
#include "Spatial.h"
namespace Gedeng {
class Camera : public Spatial {
public:
/// Create a camera with a field of view (in degrees), width and height (in any unit) and near
/// and far distances
Camera(float fov, float width, float height, float near, float far)
: projection(glm::perspective(glm::radians(fov), width / height, near, far)) {
}
glm::mat4 get_projection() {
return projection;
}
glm::mat4 get_view() {
return glm::inverse(get_matrix());
}
private:
glm::mat4 projection;
};
}

View File

@ -0,0 +1,25 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
namespace Gedeng {
class Framebuffer3D {
public:
Framebuffer3D(int width, int height, int depth);
~Framebuffer3D();
void bind_and_clear();
void bind_to(int unit) const;
void bind_layer(int layer);
private:
GLuint texture;
GLuint buffer;
};
}

43
include/Gedeng/Input.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
#include "RenderBackend.h"
#include <map>
namespace Gedeng {
class Input {
public:
static void initialize(GLFWwindow *window) {
glfwSetKeyCallback(window, key_callback);
}
// FIXME: Ignore warnings produced by these unused variables -- they're required for the callback to work:
// https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
static void key_callback(GLFWwindow *window, int key, int scancode, int action, int mods) {
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE);
Input::set_key_down(key, action == GLFW_RELEASE ? false : true);
}
static void poll_input() {
glfwPollEvents();
}
static void set_key_down(int key, bool down) {
keys_down[key] = down;
}
static bool is_key_down(int key) {
return keys_down[key];
}
inline static std::map<int, bool> keys_down;
};
} // namespace Gedeng

123
include/Gedeng/QuadMesh.h Normal file
View File

@ -0,0 +1,123 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include "Shader.h"
#include "Spatial.h"
#include <GLFW/glfw3.h>
namespace Gedeng {
// A simple 2x2 quad mesh consisting of two triangles. Oriented upwards by default.
class QuadMesh : public Spatial {
public:
QuadMesh() {
// Positions
glm::vec3 pos1(-1.0f, 1.0f, 0.0f);
glm::vec3 pos2(-1.0f, -1.0f, 0.0f);
glm::vec3 pos3(1.0f, -1.0f, 0.0f);
glm::vec3 pos4(1.0f, 1.0f, 0.0f);
// Texture coordinates
glm::vec2 uv1(0.0f, 1.0f);
glm::vec2 uv2(0.0f, 0.0f);
glm::vec2 uv3(1.0f, 0.0f);
glm::vec2 uv4(1.0f, 1.0f);
// Normal vector
glm::vec3 nm(0.0f, 0.0f, 1.0f);
// Calculate tangent/bitangent vectors of both triangles
glm::vec3 tangent1, bitangent1;
glm::vec3 tangent2, bitangent2;
// Triangle 1
glm::vec3 edge1 = pos2 - pos1;
glm::vec3 edge2 = pos3 - pos1;
glm::vec2 deltaUV1 = uv2 - uv1;
glm::vec2 deltaUV2 = uv3 - uv1;
float f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
tangent1.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent1.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent1.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
tangent1 = glm::normalize(tangent1);
bitangent1.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent1.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent1.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent1 = glm::normalize(bitangent1);
// Triangle 2
edge1 = pos3 - pos1;
edge2 = pos4 - pos1;
deltaUV1 = uv3 - uv1;
deltaUV2 = uv4 - uv1;
f = 1.0f / (deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y);
tangent2.x = f * (deltaUV2.y * edge1.x - deltaUV1.y * edge2.x);
tangent2.y = f * (deltaUV2.y * edge1.y - deltaUV1.y * edge2.y);
tangent2.z = f * (deltaUV2.y * edge1.z - deltaUV1.y * edge2.z);
tangent2 = glm::normalize(tangent2);
bitangent2.x = f * (-deltaUV2.x * edge1.x + deltaUV1.x * edge2.x);
bitangent2.y = f * (-deltaUV2.x * edge1.y + deltaUV1.x * edge2.y);
bitangent2.z = f * (-deltaUV2.x * edge1.z + deltaUV1.x * edge2.z);
bitangent2 = glm::normalize(bitangent2);
float quadVertices[] = {
// positions // normal // texcoords // tangent // bitangent
pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x,
uv1.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos2.x, pos2.y, pos2.z, nm.x, nm.y, nm.z, uv2.x,
uv2.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x,
uv3.y, tangent1.x, tangent1.y, tangent1.z, bitangent1.x, bitangent1.y, bitangent1.z,
pos1.x, pos1.y, pos1.z, nm.x, nm.y, nm.z, uv1.x,
uv1.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
pos3.x, pos3.y, pos3.z, nm.x, nm.y, nm.z, uv3.x,
uv3.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z,
pos4.x, pos4.y, pos4.z, nm.x, nm.y, nm.z, uv4.x,
uv4.y, tangent2.x, tangent2.y, tangent2.z, bitangent2.x, bitangent2.y, bitangent2.z};
// Configure plane VAO
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float), (void *)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(3 * sizeof(float)));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(6 * sizeof(float)));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(8 * sizeof(float)));
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, 14 * sizeof(float),
(void *)(11 * sizeof(float)));
}
void render(Shader &shader) {
shader.setMat4("model", get_matrix());
glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
private:
unsigned int quadVAO = 0;
unsigned int quadVBO;
};
}

View File

@ -0,0 +1,31 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
#include "Gedeng/String.h"
namespace Gedeng {
class RenderBackend {
private:
static inline GLFWwindow *window;
public:
static void initialize_window(unsigned int width, unsigned int height, String title);
static bool is_window_created();
static void set_depth_test_enabled(bool enabled);
static bool does_window_want_to_close();
static GLFWwindow *get_window();
static void render();
};
} // namespace Gedeng

172
include/Gedeng/Shader.h Normal file
View File

@ -0,0 +1,172 @@
#pragma once
// Adapted from LearnOpenGL
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
namespace Gedeng {
class Shader {
public:
unsigned int ID;
// constructor generates the shader on the fly
// ------------------------------------------------------------------------
Shader(const char *vertexPath, const char *fragmentPath, const char *geometryPath = nullptr) {
// 1. retrieve the vertex/fragment source code from filePath
std::string vertexCode;
std::string fragmentCode;
std::string geometryCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
std::ifstream gShaderFile;
// ensure ifstream objects can throw exceptions:
vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// open files
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
// read file's buffer contents into streams
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
// close file handlers
vShaderFile.close();
fShaderFile.close();
// convert stream into string
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
// if geometry shader path is present, also load a geometry shader
if (geometryPath != nullptr) {
gShaderFile.open(geometryPath);
std::stringstream gShaderStream;
gShaderStream << gShaderFile.rdbuf();
gShaderFile.close();
geometryCode = gShaderStream.str();
}
} catch (std::ifstream::failure &e) {
std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const char *vShaderCode = vertexCode.c_str();
const char *fShaderCode = fragmentCode.c_str();
// 2. compile shaders
unsigned int vertex, fragment;
// vertex shader
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
// fragment Shader
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
checkCompileErrors(fragment, "FRAGMENT");
// if geometry shader is given, compile geometry shader
unsigned int geometry;
if (geometryPath != nullptr) {
const char *gShaderCode = geometryCode.c_str();
geometry = glCreateShader(GL_GEOMETRY_SHADER);
glShaderSource(geometry, 1, &gShaderCode, NULL);
glCompileShader(geometry);
checkCompileErrors(geometry, "GEOMETRY");
}
// shader Program
ID = glCreateProgram();
glAttachShader(ID, vertex);
glAttachShader(ID, fragment);
if (geometryPath != nullptr) glAttachShader(ID, geometry);
glLinkProgram(ID);
checkCompileErrors(ID, "PROGRAM");
// delete the shaders as they're linked into our program now and no longer necessery
glDeleteShader(vertex);
glDeleteShader(fragment);
if (geometryPath != nullptr) glDeleteShader(geometry);
}
// activate the shader
// ------------------------------------------------------------------------
void use() {
glUseProgram(ID);
}
// utility uniform functions
// ------------------------------------------------------------------------
void setBool(const std::string &name, bool value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value);
}
// ------------------------------------------------------------------------
void setInt(const std::string &name, int value) const {
glUniform1i(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setFloat(const std::string &name, float value) const {
glUniform1f(glGetUniformLocation(ID, name.c_str()), value);
}
// ------------------------------------------------------------------------
void setVec2(const std::string &name, const glm::vec2 &value) const {
glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec2(const std::string &name, float x, float y) const {
glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y);
}
// ------------------------------------------------------------------------
void setVec3(const std::string &name, const glm::vec3 &value) const {
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec3(const std::string &name, float x, float y, float z) const {
glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z);
}
// ------------------------------------------------------------------------
void setVec4(const std::string &name, const glm::vec4 &value) const {
glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]);
}
void setVec4(const std::string &name, float x, float y, float z, float w) {
glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w);
}
// ------------------------------------------------------------------------
void setMat2(const std::string &name, const glm::mat2 &mat) const {
glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat3(const std::string &name, const glm::mat3 &mat) const {
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
// ------------------------------------------------------------------------
void setMat4(const std::string &name, const glm::mat4 &mat) const {
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]);
}
private:
// utility function for checking shader compilation/linking errors.
// ------------------------------------------------------------------------
void checkCompileErrors(GLuint shader, std::string type) {
GLint success;
GLchar infoLog[1024];
if (type != "PROGRAM") {
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n"
<< infoLog
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
}
} else {
glGetProgramiv(shader, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shader, 1024, NULL, infoLog);
std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n"
<< infoLog
<< "\n -- --------------------------------------------------- -- "
<< std::endl;
}
}
}
};
}

76
include/Gedeng/Spatial.h Normal file
View File

@ -0,0 +1,76 @@
#pragma once
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "glm/gtx/string_cast.hpp"
namespace Gedeng {
class Spatial {
public:
Spatial() = default;
void translate(glm::vec3 offset) {
matrix = glm::translate(matrix, offset);
}
glm::vec3 get_translation() {
return glm::vec3(matrix[3]);
}
void uniform_scale(float factor) {
scale(glm::vec3(factor, factor, factor));
}
void scale(glm::vec3 factors) {
matrix = glm::scale(matrix, factors);
}
void rotate(float degrees, glm::vec3 axis) {
matrix = glm::rotate(matrix, glm::radians(degrees), axis);
}
void set_origin(glm::vec3 position) {
origin = position;
}
void add_to_origin(glm::vec3 addition) {
origin += addition;
}
void set_rotation_from_quat(glm::quat quaternion) {
// Remember translation
glm::vec4 save = matrix[3];
matrix = glm::mat4_cast(quaternion);
matrix[3] = save;
}
glm::vec3 get_origin() const {
return origin;
}
glm::mat4 get_matrix() {
return matrix;
}
glm::vec3 forward() const {
return matrix * glm::vec4(0.0, 0.0, -1.0, 0.0);
}
glm::vec3 up() const {
return matrix * glm::vec4(0.0, 1.0, 0.0, 0.0);
}
glm::vec3 right() const {
return matrix * glm::vec4(1.0, 0.0, 0.0, 0.0);
}
private:
glm::mat4 matrix = glm::mat4(1.0f); // Initialize as identity
glm::vec3 origin = glm::vec3(0.0f, 0.0f, 0.0f);
};
}

38
include/Gedeng/Texture.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
#include <iostream>
#include <string>
namespace Gedeng {
class Texture {
public:
struct Settings {
Settings() : mipmaps(true), transparent(false){};
bool mipmaps;
bool transparent;
};
explicit Texture(const std::string &path, Settings settings)
: id(load_texture(path, settings)), valid(false) {
}
bool is_valid() const;
// Bind a texture from the given path and return its ID
uint load_texture(const std::string &path, Settings settings);
void bind_to(int unit);
private:
const uint id;
bool valid;
};
}

10
include/Gedeng/Time.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
namespace Gedeng {
class Time {
public:
static unsigned long get_time_ms();
};
} // namespace Gedeng

View File

@ -0,0 +1,28 @@
#pragma once
// Must be the first include
#include <glad/glad.h>
// Other includes
#include <GLFW/glfw3.h>
namespace Gedeng {
class VertexBuffer {
public:
VertexBuffer();
void set_data(int size, int dimension, const void *data, int flag);
void bind_array();
void bind_buffer();
void draw();
private:
GLuint vertex_array;
GLuint vertex_buffer;
int size;
};
}

View File

@ -4,12 +4,23 @@
class TestApp : public Gedeng::Application {
public:
TestApp() = default;
TestApp(unsigned long ms_per_update, unsigned int window_size_x, unsigned int window_size_y,
Gedeng::String window_name)
: Application(ms_per_update, window_size_x, window_size_y, window_name) {
}
~TestApp() = default;
void fixed_update(double delta) override {
GG_CLIENT_INFO("Fixed update");
}
void dynamic_update(double delta) override {
GG_CLIENT_INFO("Dynamic update");
}
};
Gedeng::Application *Gedeng::create_application() {
GG_CLIENT_INFO("Creating Application");
return new TestApp();
return new TestApp(20, 900, 600, String("Test App"));
}