master
Austin Morlan 3 years ago
parent 777df2cbe7
commit 9fbd7938d0
Signed by: austin
GPG Key ID: FD6B27654AF5E348
  1. 65
      CMakeLists.txt
  2. 29
      Shaders/fragment.glsl
  3. 19
      Shaders/vertex.glsl
  4. 36
      Source/Components/Camera.hpp
  5. 9
      Source/Components/Gravity.hpp
  6. 6
      Source/Components/Player.hpp
  7. 8
      Source/Components/Renderable.hpp
  8. 10
      Source/Components/RigidBody.hpp
  9. 9
      Source/Components/Thrust.hpp
  10. 11
      Source/Components/Transform.hpp
  11. 73
      Source/Core/ComponentArray.hpp
  12. 79
      Source/Core/ComponentManager.hpp
  13. 118
      Source/Core/Coordinator.hpp
  14. 58
      Source/Core/EntityManager.hpp
  15. 37
      Source/Core/Event.hpp
  16. 40
      Source/Core/EventManager.hpp
  17. 11
      Source/Core/System.hpp
  18. 68
      Source/Core/SystemManager.hpp
  19. 62
      Source/Core/Types.hpp
  20. 59
      Source/Graphics/GlLoader.cpp
  21. 30
      Source/Graphics/GlLoader.hpp
  22. 84
      Source/Graphics/Shader.cpp
  23. 33
      Source/Graphics/Shader.hpp
  24. 165
      Source/Main.cpp
  25. 53
      Source/Math/Mat44.hpp
  26. 47
      Source/Math/Vec2.hpp
  27. 85
      Source/Math/Vec3.hpp
  28. 59
      Source/Math/Vec4.hpp
  29. 61
      Source/Systems/CameraControlSystem.cpp
  30. 20
      Source/Systems/CameraControlSystem.hpp
  31. 31
      Source/Systems/PhysicsSystem.cpp
  32. 12
      Source/Systems/PhysicsSystem.hpp
  33. 61
      Source/Systems/PlayerControlSystem.cpp
  34. 20
      Source/Systems/PlayerControlSystem.hpp
  35. 224
      Source/Systems/RenderSystem.cpp
  36. 29
      Source/Systems/RenderSystem.hpp
  37. 301
      Source/WindowManager.cpp
  38. 28
      Source/WindowManager.hpp

@ -0,0 +1,65 @@
cmake_minimum_required(VERSION 3.14)
project(nexus)
find_package(X11 REQUIRED)
find_package(OpenGL REQUIRED)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(nexus)
target_compile_options(
nexus
PRIVATE
-fno-exceptions
-Wall)
target_sources(
nexus
PRIVATE
Source/Graphics/GlLoader.cpp
Source/Graphics/Shader.cpp
Source/Main.cpp
Source/Systems/CameraControlSystem.cpp
Source/Systems/PhysicsSystem.cpp
Source/Systems/PlayerControlSystem.cpp
Source/Systems/RenderSystem.cpp
Source/WindowManager.cpp)
target_sources(
nexus
PRIVATE
Source/Components/Camera.hpp
Source/Components/Gravity.hpp
Source/Components/Player.hpp
Source/Components/Renderable.hpp
Source/Components/RigidBody.hpp
Source/Components/Thrust.hpp
Source/Components/Transform.hpp
Source/Core/ComponentArray.hpp
Source/Core/ComponentManager.hpp
Source/Core/Coordinator.hpp
Source/Core/EntityManager.hpp
Source/Core/EventManager.hpp
Source/Core/System.hpp
Source/Core/SystemManager.hpp
Source/Core/Types.hpp
Source/Math/Vec2.hpp
Source/Math/Vec3.hpp
Source/Math/Vec4.hpp)
target_include_directories(
nexus
PRIVATE
Source)
target_link_libraries(
nexus
PRIVATE
OpenGL::GLX
X11::X11)

@ -0,0 +1,29 @@
#version 330 core
out vec4 FragColor;
in vec3 normal;
in vec3 fragPosWorld;
uniform vec3 uColor;
vec3 lightColor = vec3(1.0f, 1.0f, 1.0f);
vec3 lightPos = vec3(-100.0f, 50.0f, 100.0f);
void main()
{
// Ambient
float ambientStrength = 0.5;
vec3 ambient = ambientStrength * lightColor;
// Diffuse
vec3 norm = normalize(normal);
vec3 lightDir = normalize(lightPos - fragPosWorld);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
vec3 result = (ambient + diffuse) * uColor;
FragColor = vec4(result, 1.0);
}

@ -0,0 +1,19 @@
#version 330 core
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec3 inNormal;
uniform mat4 uModel;
uniform mat4 uView;
uniform mat4 uProjection;
out vec3 normal;
out vec3 fragPosWorld;
void main()
{
fragPosWorld = vec3(uModel * vec4(inPos, 1.0));
normal = vec3(uModel * vec4(inNormal, 0.0));
gl_Position = uProjection * uView * uModel * vec4(inPos, 1.0f);
}

@ -0,0 +1,36 @@
#pragma once
#include "Math/Mat44.hpp"
#include <cmath>
struct Camera
{
Mat44 projectionTransform;
static Mat44 MakeProjectionTransform(float fov, float nearClip, float farClip, unsigned int viewWidth, unsigned int viewHeight)
{
float zClipBias0 =
(farClip + nearClip)
/ (farClip - nearClip);
float zClipBias1 =
(2.0f * farClip * nearClip)
/ (farClip - nearClip);
float zoomX = 1.0f / tanf((fov / 2.0f) * (M_PI / 180.0f));
float zoomY = (zoomX * static_cast<float>(viewWidth)) / static_cast<float>(viewHeight);
Mat44 transform;
transform.m[0][0] = zoomX;
transform.m[1][1] = zoomY;
transform.m[2][2] = -zClipBias0;
transform.m[3][2] = -1;
transform.m[2][3] = -zClipBias1;
return transform;
}
};

@ -0,0 +1,9 @@
#pragma once
#include "Math/Vec3.hpp"
struct Gravity
{
Vec3 force;
};

@ -0,0 +1,6 @@
#pragma once
struct Player
{
};

@ -0,0 +1,8 @@
#pragma once
#include "Math/Vec3.hpp"
struct Renderable
{
Vec3 color;
};

@ -0,0 +1,10 @@
#pragma once
#include "Math/Vec3.hpp"
struct RigidBody
{
Vec3 velocity;
Vec3 acceleration;
};

@ -0,0 +1,9 @@
#pragma once
#include "Math/Vec3.hpp"
struct Thrust
{
Vec3 force;
};

@ -0,0 +1,11 @@
#pragma once
#include "Math/Vec3.hpp"
struct Transform
{
Vec3 position;
Vec3 rotation;
Vec3 scale;
};

@ -0,0 +1,73 @@
#pragma once
#include "Types.hpp"
#include <array>
#include <cassert>
#include <unordered_map>
class IComponentArray
{
public:
virtual ~IComponentArray() = default;
virtual void EntityDestroyed(Entity entity) = 0;
};
template<typename T>
class ComponentArray : public IComponentArray
{
public:
void InsertData(Entity entity, T component)
{
assert(mEntityToIndexMap.find(entity) == mEntityToIndexMap.end() && "Component added to same entity more than once.");
// Put new entry at end
size_t newIndex = mSize;
mEntityToIndexMap[entity] = newIndex;
mIndexToEntityMap[newIndex] = entity;
mComponentArray[newIndex] = component;
++mSize;
}
void RemoveData(Entity entity)
{
assert(mEntityToIndexMap.find(entity) != mEntityToIndexMap.end() && "Removing non-existent component.");
// Copy element at end into deleted element's place to maintain density
size_t indexOfRemovedEntity = mEntityToIndexMap[entity];
size_t indexOfLastElement = mSize - 1;
mComponentArray[indexOfRemovedEntity] = mComponentArray[indexOfLastElement];
// Update map to point to moved spot
Entity entityOfLastElement = mIndexToEntityMap[indexOfLastElement];
mEntityToIndexMap[entityOfLastElement] = indexOfRemovedEntity;
mIndexToEntityMap[indexOfRemovedEntity] = entityOfLastElement;
mEntityToIndexMap.erase(entity);
mIndexToEntityMap.erase(indexOfLastElement);
--mSize;
}
T& GetData(Entity entity)
{
assert(mEntityToIndexMap.find(entity) != mEntityToIndexMap.end() && "Retrieving non-existent component.");
return mComponentArray[mEntityToIndexMap[entity]];
}
void EntityDestroyed(Entity entity) override
{
if (mEntityToIndexMap.find(entity) != mEntityToIndexMap.end())
{
RemoveData(entity);
}
}
private:
std::array<T, MAX_ENTITIES> mComponentArray{};
std::unordered_map<Entity, size_t> mEntityToIndexMap{};
std::unordered_map<size_t, Entity> mIndexToEntityMap{};
size_t mSize{};
};

@ -0,0 +1,79 @@
#pragma once
#include "ComponentArray.hpp"
#include "Types.hpp"
#include <any>
#include <memory>
#include <unordered_map>
class ComponentManager
{
public:
template<typename T>
void RegisterComponent()
{
const char* typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) == mComponentTypes.end() && "Registering component type more than once.");
mComponentTypes.insert({typeName, mNextComponentType});
mComponentArrays.insert({typeName, std::make_shared<ComponentArray<T>>()});
++mNextComponentType;
}
template<typename T>
ComponentType GetComponentType()
{
const char* typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered before use.");
return mComponentTypes[typeName];
}
template<typename T>
void AddComponent(Entity entity, T component)
{
GetComponentArray<T>()->InsertData(entity, component);
}
template<typename T>
void RemoveComponent(Entity entity)
{
GetComponentArray<T>()->RemoveData(entity);
}
template<typename T>
T& GetComponent(Entity entity)
{
return GetComponentArray<T>()->GetData(entity);
}
void EntityDestroyed(Entity entity)
{
for (auto const& pair : mComponentArrays)
{
auto const& component = pair.second;
component->EntityDestroyed(entity);
}
}
private:
std::unordered_map<const char*, ComponentType> mComponentTypes{};
std::unordered_map<const char*, std::shared_ptr<IComponentArray>> mComponentArrays{};
ComponentType mNextComponentType{};
template<typename T>
std::shared_ptr<ComponentArray<T>> GetComponentArray()
{
const char* typeName = typeid(T).name();
assert(mComponentTypes.find(typeName) != mComponentTypes.end() && "Component not registered before use.");
return std::static_pointer_cast<ComponentArray<T>>(mComponentArrays[typeName]);
}
};

@ -0,0 +1,118 @@
#pragma once
#include "ComponentManager.hpp"
#include "EntityManager.hpp"
#include "EventManager.hpp"
#include "SystemManager.hpp"
#include "Types.hpp"
#include <memory>
class Coordinator
{
public:
void Init()
{
mComponentManager = std::make_unique<ComponentManager>();
mEntityManager = std::make_unique<EntityManager>();
mEventManager = std::make_unique<EventManager>();
mSystemManager = std::make_unique<SystemManager>();
}
// Entity methods
Entity CreateEntity()
{
return mEntityManager->CreateEntity();
}
void DestroyEntity(Entity entity)
{
mEntityManager->DestroyEntity(entity);
mComponentManager->EntityDestroyed(entity);
mSystemManager->EntityDestroyed(entity);
}
// Component methods
template<typename T>
void RegisterComponent()
{
mComponentManager->RegisterComponent<T>();
}
template<typename T>
void AddComponent(Entity entity, T component)
{
mComponentManager->AddComponent<T>(entity, component);
auto signature = mEntityManager->GetSignature(entity);
signature.set(mComponentManager->GetComponentType<T>(), true);
mEntityManager->SetSignature(entity, signature);
mSystemManager->EntitySignatureChanged(entity, signature);
}
template<typename T>
void RemoveComponent(Entity entity)
{
mComponentManager->RemoveComponent<T>(entity);
auto signature = mEntityManager->GetSignature(entity);
signature.set(mComponentManager->GetComponentType<T>(), false);
mEntityManager->SetSignature(entity, signature);
mSystemManager->EntitySignatureChanged(entity, signature);
}
template<typename T>
T& GetComponent(Entity entity)
{
return mComponentManager->GetComponent<T>(entity);
}
template<typename T>
ComponentType GetComponentType()
{
return mComponentManager->GetComponentType<T>();
}
// System methods
template<typename T>
std::shared_ptr<T> RegisterSystem()
{
return mSystemManager->RegisterSystem<T>();
}
template<typename T>
void SetSystemSignature(Signature signature)
{
mSystemManager->SetSignature<T>(signature);
}
// Event methods
void AddEventListener(EventId eventId, std::function<void(Event&)> const& listener)
{
mEventManager->AddListener(eventId, listener);
}
void SendEvent(Event& event)
{
mEventManager->SendEvent(event);
}
void SendEvent(EventId eventId)
{
mEventManager->SendEvent(eventId);
}
private:
std::unique_ptr<ComponentManager> mComponentManager;
std::unique_ptr<EntityManager> mEntityManager;
std::unique_ptr<EventManager> mEventManager;
std::unique_ptr<SystemManager> mSystemManager;
};

@ -0,0 +1,58 @@
#pragma once
#include "Types.hpp"
#include <array>
#include <cassert>
#include <queue>
class EntityManager
{
public:
EntityManager()
{
for (Entity entity = 0; entity < MAX_ENTITIES; ++entity)
{
mAvailableEntities.push(entity);
}
}
Entity CreateEntity()
{
assert(mLivingEntityCount < MAX_ENTITIES && "Too many entities in existence.");
Entity id = mAvailableEntities.front();
mAvailableEntities.pop();
++mLivingEntityCount;
return id;
}
void DestroyEntity(Entity entity)
{
assert(entity < MAX_ENTITIES && "Entity out of range.");
mSignatures[entity].reset();
mAvailableEntities.push(entity);
--mLivingEntityCount;
}
void SetSignature(Entity entity, Signature signature)
{
assert(entity < MAX_ENTITIES && "Entity out of range.");
mSignatures[entity] = signature;
}
Signature GetSignature(Entity entity)
{
assert(entity < MAX_ENTITIES && "Entity out of range.");
return mSignatures[entity];
}
private:
std::queue<Entity> mAvailableEntities{};
std::array<Signature, MAX_ENTITIES> mSignatures{};
uint32_t mLivingEntityCount{};
};

@ -0,0 +1,37 @@
#pragma once
#include "Types.hpp"
#include <any>
#include <unordered_map>
class Event
{
public:
Event() = delete;
explicit Event(EventId type)
: mType(type)
{}
template<typename T>
void SetParam(EventId id, T value)
{
mData[id] = value;
}
template<typename T>
T GetParam(EventId id)
{
return std::any_cast<T>(mData[id]);
}
EventId GetType() const
{
return mType;
}
private:
EventId mType{};
std::unordered_map<EventId, std::any> mData{};
};

@ -0,0 +1,40 @@
#pragma once
#include "Event.hpp"
#include "Types.hpp"
#include <functional>
#include <list>
#include <unordered_map>
class EventManager
{
public:
void AddListener(EventId eventId, std::function<void(Event&)> const& listener)
{
listeners[eventId].push_back(listener);
}
void SendEvent(Event& event)
{
uint32_t type = event.GetType();
for (auto const& listener : listeners[type])
{
listener(event);
}
}
void SendEvent(EventId eventId)
{
Event event(eventId);
for (auto const& listener : listeners[eventId])
{
listener(event);
}
}
private:
std::unordered_map<EventId, std::list<std::function<void(Event&)>>> listeners;
};

@ -0,0 +1,11 @@
#pragma once
#include "Types.hpp"
#include <set>
class System
{
public:
std::set<Entity> mEntities;
};

@ -0,0 +1,68 @@
#pragma once
#include "System.hpp"
#include "Types.hpp"
#include <cassert>
#include <memory>
#include <unordered_map>
class SystemManager
{
public:
template<typename T>
std::shared_ptr<T> RegisterSystem()
{
const char* typeName = typeid(T).name();
assert(mSystems.find(typeName) == mSystems.end() && "Registering system more than once.");
auto system = std::make_shared<T>();
mSystems.insert({typeName, system});
return system;
}
template<typename T>
void SetSignature(Signature signature)
{
const char* typeName = typeid(T).name();
assert(mSystems.find(typeName) != mSystems.end() && "System used before registered.");
mSignatures.insert({typeName, signature});
}
void EntityDestroyed(Entity entity)
{
for (auto const& pair : mSystems)
{
auto const& system = pair.second;
system->mEntities.erase(entity);
}
}
void EntitySignatureChanged(Entity entity, Signature entitySignature)
{
for (auto const& pair : mSystems)
{
auto const& type = pair.first;
auto const& system = pair.second;
auto const& systemSignature = mSignatures[type];
if ((entitySignature & systemSignature) == systemSignature)
{
system->mEntities.insert(entity);
}
else
{
system->mEntities.erase(entity);
}
}
}
private:
std::unordered_map<const char*, Signature> mSignatures{};
std::unordered_map<const char*, std::shared_ptr<System>> mSystems{};
};

@ -0,0 +1,62 @@
#pragma once
#include <bitset>
#include <cstdint>
// Source: https://gist.github.com/Lee-R/3839813
constexpr std::uint32_t fnv1a_32(char const* s, std::size_t count)
{
return ((count ? fnv1a_32(s, count - 1) : 2166136261u) ^ s[count]) * 16777619u; // NOLINT (hicpp-signed-bitwise)
}
constexpr std::uint32_t operator "" _hash(char const* s, std::size_t count)
{
return fnv1a_32(s, count);
}
// ECS
using Entity = std::uint32_t;
const Entity MAX_ENTITIES = 5000;
using ComponentType = std::uint8_t;
const ComponentType MAX_COMPONENTS = 32;
using Signature = std::bitset<MAX_COMPONENTS>;
// Input
enum class InputButtons
{
W,
A,
S,
D,
Q,
E
};
// Events
using EventId = std::uint32_t;
using ParamId = std::uint32_t;
#define METHOD_LISTENER(EventType, Listener) EventType, std::bind(&Listener, this, std::placeholders::_1)
#define FUNCTION_LISTENER(EventType, Listener) EventType, std::bind(&Listener, std::placeholders::_1)
// TODO: Make these easier to define and use (macro?)
// TODO: Add some kind of enforcement/automation that a SetParam type and a GetParam type match
namespace Events::Window {
const EventId QUIT = "Events::Window::QUIT"_hash;
const EventId RESIZED = "Events::Window::RESIZED"_hash;
const EventId INPUT = "Events::Window::INPUT"_hash;
}
namespace Events::Window::Input {
const ParamId INPUT = "Events::Window::Input::INPUT"_hash;
}
namespace Events::Window::Resized {
const ParamId WIDTH = "Events::Window::Resized::WIDTH"_hash;
const ParamId HEIGHT = "Events::Window::Resized::HEIGHT"_hash;
}

@ -0,0 +1,59 @@
#include "GlLoader.hpp"
#include <cassert>
PFNGLCREATESHADERPROC glCreateShader = nullptr;
PFNGLSHADERSOURCEPROC glShaderSource = nullptr;
PFNGLCOMPILESHADERPROC glCompileShader = nullptr;
PFNGLGETSHADERIVPROC glGetShaderiv = nullptr;
PFNGLGETSHADERSOURCEPROC glGetShaderInfo = nullptr;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr;
PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr;
PFNGLATTACHSHADERPROC glAttachShader = nullptr;
PFNGLLINKPROGRAMPROC glLinkProgram = nullptr;
PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr;
PFNGLDELETESHADERPROC glDeleteShader = nullptr;
PFNGLGENBUFFERSPROC glGenBuffers = nullptr;
PFNGLBINDBUFFERPROC glBindBuffer = nullptr;
PFNGLBUFFERDATAPROC glBufferData = nullptr;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr;
PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr;
PFNGLUSEPROGRAMPROC glUseProgram = nullptr;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv = nullptr;
PFNGLUNIFORM3FVPROC glUniform3fv = nullptr;
#define LOAD_GL_FUNCTION(type, name) \
(name) = (PFN##type##PROC) glXGetProcAddress((unsigned char *) #name); \
assert(name && "GL function not found");
void LoadGlFunctions()
{
LOAD_GL_FUNCTION(GLCREATESHADER, glCreateShader)
LOAD_GL_FUNCTION(GLSHADERSOURCE, glShaderSource)
LOAD_GL_FUNCTION(GLCOMPILESHADER, glCompileShader)
LOAD_GL_FUNCTION(GLGETSHADERIV, glGetShaderiv)
LOAD_GL_FUNCTION(GLGETSHADERSOURCE, glGetShaderInfo)
LOAD_GL_FUNCTION(GLGETSHADERINFOLOG, glGetShaderInfoLog)
LOAD_GL_FUNCTION(GLCREATEPROGRAM, glCreateProgram)
LOAD_GL_FUNCTION(GLATTACHSHADER, glAttachShader)
LOAD_GL_FUNCTION(GLLINKPROGRAM, glLinkProgram)
LOAD_GL_FUNCTION(GLGETPROGRAMIV, glGetProgramiv)
LOAD_GL_FUNCTION(GLGETPROGRAMINFOLOG, glGetProgramInfoLog)
LOAD_GL_FUNCTION(GLDELETESHADER, glDeleteShader)
LOAD_GL_FUNCTION(GLGENBUFFERS, glGenBuffers)
LOAD_GL_FUNCTION(GLBINDBUFFER, glBindBuffer)
LOAD_GL_FUNCTION(GLBUFFERDATA, glBufferData)
LOAD_GL_FUNCTION(GLGENVERTEXARRAYS, glGenVertexArrays)
LOAD_GL_FUNCTION(GLBINDVERTEXARRAY, glBindVertexArray)
LOAD_GL_FUNCTION(GLVERTEXATTRIBPOINTER, glVertexAttribPointer)
LOAD_GL_FUNCTION(GLENABLEVERTEXATTRIBARRAY, glEnableVertexAttribArray)
LOAD_GL_FUNCTION(GLUSEPROGRAM, glUseProgram)
LOAD_GL_FUNCTION(GLGETUNIFORMLOCATION, glGetUniformLocation)
LOAD_GL_FUNCTION(GLUNIFORMMATRIX4FV, glUniformMatrix4fv)
LOAD_GL_FUNCTION(GLUNIFORM3FV, glUniform3fv)
}

@ -0,0 +1,30 @@
#pragma once
#include <GL/glx.h>
extern PFNGLCREATESHADERPROC glCreateShader;
extern PFNGLSHADERSOURCEPROC glShaderSource;
extern PFNGLCOMPILESHADERPROC glCompileShader;
extern PFNGLGETSHADERIVPROC glGetShaderiv;
extern PFNGLGETSHADERSOURCEPROC glGetShaderInfo;
extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
extern PFNGLCREATEPROGRAMPROC glCreateProgram;
extern PFNGLATTACHSHADERPROC glAttachShader;
extern PFNGLLINKPROGRAMPROC glLinkProgram;
extern PFNGLGETPROGRAMIVPROC glGetProgramiv;
extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
extern PFNGLDELETESHADERPROC glDeleteShader;
extern PFNGLGENBUFFERSPROC glGenBuffers;
extern PFNGLBINDBUFFERPROC glBindBuffer;
extern PFNGLBUFFERDATAPROC glBufferData;
extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
extern PFNGLUSEPROGRAMPROC glUseProgram;
extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
extern PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
extern PFNGLUNIFORM3FVPROC glUniform3fv;
void LoadGlFunctions();

@ -0,0 +1,84 @@
#include "Shader.hpp"
#include <fstream>
#include <iostream>
#include <sstream>
Shader::Shader(std::string const& vertexPath, std::string const& fragmentPath)
{
std::string fragmentFileContents;
std::string vertexFileContents;
// Read in the vertex shader
std::ifstream vertex_file;
vertex_file.open(vertexPath);
std::stringstream vertex_file_stream;
vertex_file_stream << vertex_file.rdbuf();
vertex_file.close();
vertexFileContents = vertex_file_stream.str();
// Read in the fragment shader
std::ifstream fragment_file;
fragment_file.open(fragmentPath);
std::stringstream fragment_file_stream;
fragment_file_stream << fragment_file.rdbuf();
fragment_file.close();
fragmentFileContents = fragment_file_stream.str();
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
const GLchar* vertex_shader_source = vertexFileContents.c_str();
glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr);
glCompileShader(vertex_shader);
int success;
char infoLog[512];
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertex_shader, 512, nullptr, infoLog);
std::cerr << "Error compiling vertex shader: " << infoLog << "\n";
}
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
const GLchar* fragment_shader_source = fragmentFileContents.c_str();
glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragment_shader, 512, nullptr, infoLog);
std::cerr << "Error compiling fragment shader: " << infoLog << "\n";
}
mId = glCreateProgram();
glAttachShader(mId, vertex_shader);
glAttachShader(mId, fragment_shader);
glLinkProgram(mId);
glGetProgramiv(mId, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(mId, 512, nullptr, infoLog);
std::cerr << "Error linking shaders: " << infoLog << "\n";
}
glDeleteShader(vertex_shader);
glDeleteShader(fragment_shader);
}
void Shader::Activate()
{
glUseProgram(mId);
}

@ -0,0 +1,33 @@
#pragma once
#include "GlLoader.hpp"
#include <string>
class Mat44;
class Vec3;
class Shader
{
public:
Shader(std::string const& vertexPath, std::string const& fragmentPath);
void Activate();
template<typename T>
void SetUniform(const std::string& name, const T& value)
{
if constexpr (std::is_same_v<T, Mat44>)
{
glUniformMatrix4fv(glGetUniformLocation(mId, name.c_str()), 1, GL_TRUE, (GLfloat*)value.m);
}
else if constexpr (std::is_same_v<T, Vec3>)
{
glUniform3fv(glGetUniformLocation(mId, name.c_str()), 1, (GLfloat*)&value);
}
}
private:
GLuint mId;
};

@ -0,0 +1,165 @@
#include "Components/Camera.hpp"
#include "Components/Gravity.hpp"
#include "Components/Player.hpp"
#include "Components/Renderable.hpp"
#include "Components/RigidBody.hpp"
#include "Components/Thrust.hpp"
#include "Components/Transform.hpp"
#include "Core/Coordinator.hpp"
#include "Systems/CameraControlSystem.hpp"
#include "Systems/PhysicsSystem.hpp"
#include "Systems/PlayerControlSystem.hpp"
#include "Systems/RenderSystem.hpp"
#include "WindowManager.hpp"
#include <chrono>
#include <random>
Coordinator gCoordinator;
static bool quit = false;
void QuitHandler(Event& event)
{
quit = true;
}
int main()
{
gCoordinator.Init();
WindowManager windowManager;
windowManager.Init("Nexus", 1920, 1080, 0, 0);
LoadGlFunctions();
gCoordinator.AddEventListener(FUNCTION_LISTENER(Events::Window::QUIT, QuitHandler));
gCoordinator.RegisterComponent<Camera>();
gCoordinator.RegisterComponent<Gravity>();
gCoordinator.RegisterComponent<Player>();
gCoordinator.RegisterComponent<Renderable>();
gCoordinator.RegisterComponent<RigidBody>();
gCoordinator.RegisterComponent<Thrust>();
gCoordinator.RegisterComponent<Transform>();
auto physicsSystem = gCoordinator.RegisterSystem<PhysicsSystem>();
{
Signature signature;
signature.set(gCoordinator.GetComponentType<Gravity>());
signature.set(gCoordinator.GetComponentType<RigidBody>());
signature.set(gCoordinator.GetComponentType<Transform>());
gCoordinator.SetSystemSignature<PhysicsSystem>(signature);
}
physicsSystem->Init();
auto cameraControlSystem = gCoordinator.RegisterSystem<CameraControlSystem>();
{
Signature signature;
signature.set(gCoordinator.GetComponentType<Camera>());
signature.set(gCoordinator.GetComponentType<Transform>());
gCoordinator.SetSystemSignature<CameraControlSystem>(signature);
}
cameraControlSystem->Init();
auto playerControlSystem = gCoordinator.RegisterSystem<PlayerControlSystem>();
{
Signature signature;
signature.set(gCoordinator.GetComponentType<Player>());
signature.set(gCoordinator.GetComponentType<Transform>());
gCoordinator.SetSystemSignature<PlayerControlSystem>(signature);
}
playerControlSystem->Init();
auto renderSystem = gCoordinator.RegisterSystem<RenderSystem>();
{
Signature signature;
signature.set(gCoordinator.GetComponentType<Renderable>());
signature.set(gCoordinator.GetComponentType<Transform>());
gCoordinator.SetSystemSignature<RenderSystem>(signature);
}
renderSystem->Init();
std::vector<Entity> entities(MAX_ENTITIES - 1);
std::default_random_engine generator;
std::uniform_real_distribution<float> randPosition(-100.0f, 100.0f);
std::uniform_real_distribution<float> randRotation(0.0f, 3.0f);
std::uniform_real_distribution<float> randScale(3.0f, 5.0f);
std::uniform_real_distribution<float> randColor(0.0f, 1.0f);
std::uniform_real_distribution<float> randGravity(-10.0f, -1.0f);
float scale = randScale(generator);
for (auto& entity : entities)
{
entity = gCoordinator.CreateEntity();
gCoordinator.AddComponent(entity, Player{});
gCoordinator.AddComponent<Gravity>(
entity,
{Vec3(0.0f, randGravity(generator), 0.0f)});
gCoordinator.AddComponent(
entity,
RigidBody{
.velocity = Vec3(0.0f, 0.0f, 0.0f),
.acceleration = Vec3(0.0f, 0.0f, 0.0f)
});
gCoordinator.AddComponent(
entity,
Transform{
.position = Vec3(randPosition(generator), randPosition(generator), randPosition(generator)),
.rotation = Vec3(randRotation(generator), randRotation(generator), randRotation(generator)),
.scale = Vec3(scale, scale, scale)
});
gCoordinator.AddComponent(
entity,
Renderable{
.color = Vec3(randColor(generator), randColor(generator), randColor(generator))
});
}
float dt = 0.0f;
while (!quit)
{
auto startTime = std::chrono::high_resolution_clock::now();
windowManager.ProcessEvents();
playerControlSystem->Update(dt);
cameraControlSystem->Update(dt);
physicsSystem->Update(dt);
renderSystem->Update(dt);
windowManager.Update();
auto stopTime = std::chrono::high_resolution_clock::now();
dt = std::chrono::duration<float, std::chrono::seconds::period>(stopTime - startTime).count();
}
windowManager.Shutdown();
return 0;
}

@ -0,0 +1,53 @@
#pragma once
#include "Vec4.hpp"
class Mat44
{
public:
Mat44()
{
//@formatter:off
m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f;
m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f;
m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f;
m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f;
//@formatter:on
}
Mat44 operator*(Mat44 const& rhs)
{
Mat44 result;
for (int row = 0; row < 4; ++row)
{
for (int col = 0; col < 4; ++col)
{
float sum = 0.0f;
for (int i = 0; i < 4; ++i)
{
sum += m[row][i] * rhs.m[i][col];
}
result.m[row][col] = sum;
}
}
return result;
}
Vec4 operator*(Vec4 const& rhs)
{
return Vec4(
(rhs.x * m[0][0]) + (rhs.y * m[0][1]) + (rhs.z * m[0][2]) + (rhs.w * m[0][3]),
(rhs.x * m[1][0]) + (rhs.y * m[1][1]) + (rhs.z * m[1][2]) + (rhs.w * m[1][3]),
(rhs.x * m[2][0]) + (rhs.y * m[2][1]) + (rhs.z * m[2][2]) + (rhs.w * m[2][3]),
(rhs.x * m[3][0]) + (rhs.y * m[3][1]) + (rhs.z * m[3][2]) + (rhs.w * m[3][3]));
}
float m[4][4];
};

@ -0,0 +1,47 @@
#pragma once
class Vec2
{
public:
Vec2()
: x(0.0f), y(0.0f)
{}
Vec2(float x, float y)
: x(x), y(y)
{}
Vec2 operator+(Vec2 const& v)
{
return Vec2(
x + v.x,
y + v.y);
}
Vec2 operator+=(Vec2 const& v)
{
x += v.x;
y += v.y;
return *this;
}
Vec2 operator-(Vec2 const& v)
{
return Vec2(
x - v.x,
y - v.y);
}
Vec2 operator-=(Vec2 const& v)
{
x -= v.x;
y -= v.y;
return *this;
}
float x, y;
};

@ -0,0 +1,85 @@
#pragma once
class Vec3
{
public:
Vec3()
: x(0.0f), y(0.0f), z(0.0f)
{}
Vec3(float x, float y, float z)
: x(x), y(y), z(z)
{}
Vec3 operator+(Vec3 const& rhs) const
{
return Vec3(
x + rhs.x,
y + rhs.y,
z + rhs.z);
}
Vec3 operator+=(Vec3 const& rhs)
{
x += rhs.x;
y += rhs.y;
z += rhs.z;
return *this;
}
Vec3 operator-(Vec3 const& rhs) const
{
return Vec3(
x - rhs.x,
y - rhs.y,
z - rhs.z);
}
Vec3 operator-=(Vec3 const& rhs)
{
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
return *this;
}
Vec3 operator*(Vec3 const& rhs) const
{
return Vec3(
x * rhs.x,
y * rhs.y,
z * rhs.z);
}
Vec3 operator*=(Vec3 const& rhs)
{
x *= rhs.x;
y *= rhs.y;
z *= rhs.z;
return *this;
}
Vec3 operator*(float rhs) const
{
return Vec3(
x * rhs,
y * rhs,
z * rhs);
}
Vec3 operator*=(float rhs)
{
x *= rhs;
y *= rhs;
z *= rhs;
return *this;
}
float x, y, z;
};

@ -0,0 +1,59 @@
#pragma once
class Vec4
{
public:
Vec4()
: x(0.0f), y(0.0f), z(0.0f), w(0.0f)
{}
Vec4(float x, float y, float z)
: x(x), y(y), z(z), w(0.0f)
{}
Vec4(float x, float y, float z, float w)
: x(x), y(y), z(z), w(w)
{}
Vec4 operator+(Vec4 const& v) const
{
return Vec4(
x + v.x,
y + v.y,
z + v.z,
w + v.w);
}
Vec4 operator+=(Vec4 const& v)
{
x += v.x;
y += v.y;
z += v.z;
w += v.w;
return *this;
}
Vec4 operator-(Vec4 const& v) const
{
return Vec4(
x - v.x,
y - v.y,
z - v.z,
w - v.w);
}
Vec4 operator-=(Vec4 const& v)
{
x -= v.x;
y -= v.y;
z -= v.z;
w -= v.w;
return *this;
}
float x, y, z, w;
};

61