1
0
Fork 0
This commit is contained in:
Austin Morlan 2019-08-03 12:29:42 -07:00
parent 777df2cbe7
commit 9fbd7938d0
Signed by: austin
GPG Key ID: FD6B27654AF5E348
38 changed files with 2150 additions and 0 deletions

65
CMakeLists.txt Normal file
View File

@ -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)

29
Shaders/fragment.glsl Normal file
View File

@ -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);
}

19
Shaders/vertex.glsl Normal file
View File

@ -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);
}

View File

@ -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;
}
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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{};
};

View File

@ -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]);
}
};

118
Source/Core/Coordinator.hpp Normal file
View File

@ -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;
};

View File

@ -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{};
};

37
Source/Core/Event.hpp Normal file
View File

@ -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{};
};

View File

@ -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;
};

11
Source/Core/System.hpp Normal file
View File

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

View File

@ -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{};
};

62
Source/Core/Types.hpp Normal file
View File

@ -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;
}

View File

@ -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)
}

View File

@ -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();

View File

@ -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);
}

View File

@ -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;
};

165
Source/Main.cpp Normal file
View File

@ -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;
}

53
Source/Math/Mat44.hpp Normal file
View File

@ -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];
};

47
Source/Math/Vec2.hpp Normal file
View File

@ -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;
};

85
Source/Math/Vec3.hpp Normal file
View File

@ -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;
};

59
Source/Math/Vec4.hpp Normal file
View File

@ -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;
};

View File

@ -0,0 +1,61 @@
#include "CameraControlSystem.hpp"
#include "Components/Transform.hpp"
#include "Core/Coordinator.hpp"
extern Coordinator gCoordinator;
void CameraControlSystem::Init()
{
gCoordinator.AddEventListener(METHOD_LISTENER(Events::Window::INPUT, CameraControlSystem::InputListener));
}
void CameraControlSystem::Update(float dt)
{
for (auto& entity : mEntities)
{
auto& transform = gCoordinator.GetComponent<Transform>(entity);
float speed = 20.0f;
if (mButtons.test(static_cast<std::size_t>(InputButtons::W)))
{
transform.position.z -= (dt * speed);
}
else if (mButtons.test(static_cast<std::size_t>(InputButtons::S)))
{
transform.position.z += (dt * speed);
}
if (mButtons.test(static_cast<std::size_t>(InputButtons::Q)))
{
transform.position.y += (dt * speed);
}
else if (mButtons.test(static_cast<std::size_t>(InputButtons::E)))
{
transform.position.y -= (dt * speed);
}
if (mButtons.test(static_cast<std::size_t>(InputButtons::A)))
{
transform.position.x -= (dt * speed);
}
else if (mButtons.test(static_cast<std::size_t>(InputButtons::D)))
{
transform.position.x += (dt * speed);
}
}
}
void CameraControlSystem::InputListener(Event& event)
{
mButtons = event.GetParam<std::bitset<8>>(Events::Window::Input::INPUT);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "Core/System.hpp"
class Event;
class CameraControlSystem : public System
{
public:
void Init();
void Update(float dt);
private:
std::bitset<8> mButtons;
void InputListener(Event& event);
};

View File

@ -0,0 +1,31 @@
#include "PhysicsSystem.hpp"
#include "Components/Gravity.hpp"
#include "Components/RigidBody.hpp"
#include "Components/Thrust.hpp"
#include "Components/Transform.hpp"
#include "Core/Coordinator.hpp"
extern Coordinator gCoordinator;
void PhysicsSystem::Init()
{
}
void PhysicsSystem::Update(float dt)
{
for (auto const& entity : mEntities)
{
auto& rigidBody = gCoordinator.GetComponent<RigidBody>(entity);
auto& transform = gCoordinator.GetComponent<Transform>(entity);
// Forces
auto const& gravity = gCoordinator.GetComponent<Gravity>(entity);
transform.position += rigidBody.velocity * dt;
rigidBody.velocity += gravity.force * dt;
}
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "Core/System.hpp"
class PhysicsSystem : public System
{
public:
void Init();
void Update(float dt);
};

View File

@ -0,0 +1,61 @@
#include "PlayerControlSystem.hpp"
#include "Components/Player.hpp"
#include "Components/Thrust.hpp"
#include "Components/Transform.hpp"
#include "Core/Coordinator.hpp"
extern Coordinator gCoordinator;
void PlayerControlSystem::Init()
{
gCoordinator.AddEventListener(METHOD_LISTENER(Events::Window::INPUT, PlayerControlSystem::InputListener));
}
void PlayerControlSystem::Update(float dt)
{
//for (auto& entity : mEntities)
//{
// auto& transform = gCoordinator.Get<Transform>(entity);
// if (mButtons.test(static_cast<std::size_t>(InputButtons::W)))
// {
// transform.position.z += (dt * 10.0f);
// }
// else if (mButtons.test(static_cast<std::size_t>(InputButtons::S)))
// {
// transform.position.z -= (dt * 10.0f);
// }
// if (mButtons.test(static_cast<std::size_t>(InputButtons::Q)))
// {
// transform.position.y += (dt * 10.0f);
// }
// else if (mButtons.test(static_cast<std::size_t>(InputButtons::E)))
// {
// transform.position.y -= (dt * 10.0f);
// }
// if (mButtons.test(static_cast<std::size_t>(InputButtons::A)))
// {
// transform.position.x += (dt * 10.0f);
// }
// else if (mButtons.test(static_cast<std::size_t>(InputButtons::D)))
// {
// transform.position.x -= (dt * 10.0f);
// }
//}
}
void PlayerControlSystem::InputListener(Event& event)
{
mButtons = event.GetParam<std::bitset<8>>(Events::Window::Input::INPUT);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "Core/System.hpp"
class Event;
class PlayerControlSystem : public System
{
public:
void Init();
void Update(float dt);
private:
std::bitset<8> mButtons;
void InputListener(Event& event);
};

View File

@ -0,0 +1,224 @@
#include "RenderSystem.hpp"
#include "Components/Camera.hpp"
#include "Components/Renderable.hpp"
#include "Components/Transform.hpp"
#include "Core/Coordinator.hpp"
#include "Graphics/Shader.hpp"
#include <cmath>
extern Coordinator gCoordinator;
void RenderSystem::Init()
{
gCoordinator.AddEventListener(METHOD_LISTENER(Events::Window::RESIZED, RenderSystem::WindowSizeListener));
shader = std::make_unique<Shader>("../Shaders/vertex.glsl", "../Shaders/fragment.glsl");
mCamera = gCoordinator.CreateEntity();
gCoordinator.AddComponent(
mCamera,
Transform{
.position = Vec3(0.0f, 0.0f, 500.0f)
});
gCoordinator.AddComponent(
mCamera,
Camera{
.projectionTransform = Camera::MakeProjectionTransform(45.0f, 0.1f, 1000.0f, 1920, 1080)
});
std::vector<Vec3> vertices =
{
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(0.5f, -0.5f, -0.5f),
Vec3(0.5f, 0.5f, -0.5f),
Vec3(0.5f, 0.5f, -0.5f),
Vec3(-0.5f, 0.5f, -0.5f),
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(-0.5f, -0.5f, 0.5),
Vec3(0.5f, -0.5f, 0.5),
Vec3(0.5f, 0.5f, 0.5),
Vec3(0.5f, 0.5f, 0.5),
Vec3(-0.5f, 0.5f, 0.5),
Vec3(-0.5f, -0.5f, 0.5),
Vec3(-0.5f, 0.5f, 0.5f),
Vec3(-0.5f, 0.5f, -0.5f),
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(-0.5f, -0.5f, 0.5f),
Vec3(-0.5f, 0.5f, 0.5f),
Vec3(0.5f, 0.5f, 0.5),
Vec3(0.5f, 0.5f, -0.5),
Vec3(0.5f, -0.5f, -0.5),
Vec3(0.5f, -0.5f, -0.5),
Vec3(0.5f, -0.5f, 0.5),
Vec3(0.5f, 0.5f, 0.5),
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(0.5f, -0.5f, -0.5f),
Vec3(0.5f, -0.5f, 0.5f),
Vec3(0.5f, -0.5f, 0.5f),
Vec3(-0.5f, -0.5f, 0.5f),
Vec3(-0.5f, -0.5f, -0.5f),
Vec3(-0.5f, 0.5f, -0.5),
Vec3(0.5f, 0.5f, -0.5),
Vec3(0.5f, 0.5f, 0.5),
Vec3(0.5f, 0.5f, 0.5),
Vec3(-0.5f, 0.5f, 0.5),
Vec3(-0.5f, 0.5f, -0.5)
};
std::vector<Vec3> normals =
{
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, -1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(0.0f, 0.0f, 1.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(-1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(1.0f, 0.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, -1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0f),
Vec3(0.0f, 1.0f, 0.0)
};
glGenVertexArrays(1, &mVao);
glBindVertexArray(mVao);
// Vertices
glGenBuffers(1, &mVboVertices);
glBindBuffer(GL_ARRAY_BUFFER, mVboVertices);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vec3) * vertices.size(), vertices.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), (void*)nullptr);
glEnableVertexAttribArray(0);
// Surface normal
glGenBuffers(1, &mVboNormals);
glBindBuffer(GL_ARRAY_BUFFER, mVboNormals);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vec3) * normals.size(), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), (void*)nullptr);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}
void RenderSystem::Update(float dt)
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // NOLINT (hicpp-signed-bitwise)
shader->Activate();
glBindVertexArray(mVao);
auto& cameraTransform = gCoordinator.GetComponent<Transform>(mCamera);
auto& camera = gCoordinator.GetComponent<Camera>(mCamera);
for (auto const& entity : mEntities)
{
auto const& transform = gCoordinator.GetComponent<Transform>(entity);
auto const& renderable = gCoordinator.GetComponent<Renderable>(entity);
Mat44 view;
view.m[0][3] = -cameraTransform.position.x;
view.m[1][3] = -cameraTransform.position.y;
view.m[2][3] = -cameraTransform.position.z;
Mat44 rotY;
float cos_theta_y = cosf(transform.rotation.y);
float sin_theta_y = sinf(transform.rotation.y);
rotY.m[0][0] = cos_theta_y;
rotY.m[2][0] = -sin_theta_y;
rotY.m[0][2] = sin_theta_y;
rotY.m[2][2] = cos_theta_y;
Mat44 rotX;
float cosThetaX = cosf(transform.rotation.x);
float sinThetaX = sinf(transform.rotation.x);
rotX.m[1][1] = cosThetaX;
rotX.m[2][1] = sinThetaX;
rotX.m[1][2] = -sinThetaX;
rotX.m[2][2] = cosThetaX;
Mat44 rotZ;
float cosThetaZ = cosf(transform.rotation.z);
float sinThetaZ = sinf(transform.rotation.z);
rotZ.m[0][0] = cosThetaZ;
rotZ.m[1][0] = sinThetaZ;
rotZ.m[0][1] = -sinThetaZ;
rotZ.m[1][1] = cosThetaZ;
Mat44 translate;
translate.m[0][3] = transform.position.x;
translate.m[1][3] = transform.position.y;
translate.m[2][3] = transform.position.z;
Mat44 scaleMat;
scaleMat.m[0][0] = transform.scale.x;
scaleMat.m[1][1] = transform.scale.y;
scaleMat.m[2][2] = transform.scale.z;
Mat44 model = translate * scaleMat * rotY;
Mat44 projection = camera.projectionTransform;
shader->SetUniform<Mat44>("uModel", model);
shader->SetUniform<Mat44>("uView", view);
shader->SetUniform<Mat44>("uProjection", projection);
shader->SetUniform<Vec3>("uColor", renderable.color);
glDrawArrays(GL_TRIANGLES, 0, 36);
}
glBindVertexArray(0);
}
void RenderSystem::WindowSizeListener(Event& event)
{
auto windowWidth = event.GetParam<unsigned int>(Events::Window::Resized::WIDTH);
auto windowHeight = event.GetParam<unsigned int>(Events::Window::Resized::HEIGHT);
auto& camera = gCoordinator.GetComponent<Camera>(mCamera);
camera.projectionTransform = Camera::MakeProjectionTransform(45.0f, 0.1f, 1000.0f, windowWidth, windowHeight);
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "Core/System.hpp"
#include "Graphics/GlLoader.hpp"
#include "Graphics/Shader.hpp"
#include <memory>
class Event;
class RenderSystem : public System
{
public:
void Init();
void Update(float dt);
private:
void WindowSizeListener(Event& event);
std::unique_ptr<Shader> shader;
Entity mCamera;
GLuint mVao{};
GLuint mVboVertices{};
GLuint mVboNormals{};
};

301
Source/WindowManager.cpp Normal file
View File

@ -0,0 +1,301 @@
#include "WindowManager.hpp"
#include "Core/Coordinator.hpp"
#include <bitset>
#include <iostream>
#include <X11/XKBlib.h>
extern Coordinator gCoordinator;
// TODO: Return error to caller
void WindowManager::Init(
std::string const& windowTitle, unsigned int windowWidth, unsigned int windowHeight, unsigned int windowPositionX,
unsigned int windowPositionY)
{
// Open the mDisplay
{
mDisplay = XOpenDisplay(nullptr);
if (!mDisplay)
{
std::cerr << "Error: XOpenDisplay()\n";
return;
}
}
// Get the proper frame buffer config
GLXFBConfig frameBufferConfig{};
{
// Frame buffer configs were added in GLX version 1.3.
if (int glxMajor, glxMinor;
!glXQueryVersion(mDisplay, &glxMajor, &glxMinor)
|| ((glxMajor == 1) && (glxMinor < 3)) || (glxMajor < 1))
{
std::cerr << "Invalid GLX version.\n";
return;
}
static int visualAttributes[] =
{
GLX_X_RENDERABLE, True,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_STENCIL_SIZE, 8,
GLX_DOUBLEBUFFER, True,
None
};
int frameBufferCount;
GLXFBConfig* frameBufferConfigList = glXChooseFBConfig(
mDisplay, DefaultScreen(mDisplay), visualAttributes, &frameBufferCount);
if (!frameBufferConfigList)
{
std::cerr << "Error: glXChooseFBConfig()\n";
return;
}
frameBufferConfig = frameBufferConfigList[0];
XFree(frameBufferConfigList);
}
// Create the window
{
XVisualInfo* visualInfo = glXGetVisualFromFBConfig(mDisplay, frameBufferConfig);
XSetWindowAttributes swa;
swa.colormap = XCreateColormap(
mDisplay,
RootWindow(mDisplay, visualInfo->screen),
visualInfo->visual, AllocNone);
swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask; // NOLINT(hicpp-signed-bitwise)
mWindow = XCreateWindow(
mDisplay, RootWindow(mDisplay, visualInfo->screen),
windowPositionX, windowPositionY,
windowWidth, windowHeight,
0, visualInfo->depth, InputOutput,
visualInfo->visual,
CWColormap | CWEventMask, &swa); // NOLINT (hicpp-signed-bitwise)
if (!mWindow)
{
std::cerr << "Error: XCreateWindow()\n";
return;
}
XFree(visualInfo);
XStoreName(mDisplay, mWindow, windowTitle.c_str());
XMapWindow(mDisplay, mWindow);
}
// Create the context
{
typedef GLXContext (* glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
auto glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddress(
(const GLubyte*)"glXCreateContextAttribsARB");
if (!glXCreateContextAttribsARB)
{
std::cerr << "glXCreateContextAttribsARB() not found\n";
return;
}
int contextAttributes[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 0,
None
};
mGlxContext = glXCreateContextAttribsARB(
mDisplay, frameBufferConfig, nullptr,
True, contextAttributes);
if (!mGlxContext)
{
std::cerr << "Failed to create an OpenGL context\n";
return;
}
}
// Generate KeyRelease event only when physical key is actually released
{
bool detectableSet = XkbSetDetectableAutoRepeat(mDisplay, true, nullptr);
if (!detectableSet)
{
std::cerr << "Detectable auto repeat not set - holding a key down will cause event spamming and delays.\n";
}
}
glXMakeCurrent(mDisplay, mWindow, mGlxContext);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glXSwapBuffers(mDisplay, mWindow);
glEnable(GL_DEPTH_TEST);
}
void WindowManager::Update()
{
glXSwapBuffers(mDisplay, mWindow);
}
void WindowManager::Shutdown()
{
glXMakeCurrent(mDisplay, 0, nullptr);
glXDestroyContext(mDisplay, mGlxContext);
XDestroyWindow(mDisplay, mWindow);
XCloseDisplay(mDisplay);
}
void WindowManager::ProcessEvents()
{
XEvent xEvent;
if (XCheckWindowEvent(mDisplay, mWindow, ExposureMask | KeyPressMask | KeyReleaseMask, &xEvent)) // NOLINT (hicpp-signed-bitwise)
{
if (xEvent.type == Expose)
{
XWindowAttributes gwa;
XGetWindowAttributes(mDisplay, mWindow, &gwa);
glViewport(0, 0, gwa.width, gwa.height);
Event event(Events::Window::RESIZED);
event.SetParam<unsigned int>(Events::Window::Resized::WIDTH, gwa.width);
event.SetParam<unsigned int>(Events::Window::Resized::HEIGHT, gwa.height);
gCoordinator.SendEvent(event);
}
else if (xEvent.type == KeyPress)
{
KeySym key = XkbKeycodeToKeysym(
mDisplay,
static_cast<KeyCode>(xEvent.xkey.keycode),
0, 0);
bool buttonStateChanged = true;
if (key == XK_Escape)
{
gCoordinator.SendEvent(Events::Window::QUIT);
}
else if (key == XK_w)
{
mButtons.set(static_cast<std::size_t>(InputButtons::W));
}
else if (key == XK_a)
{
mButtons.set(static_cast<std::size_t>(InputButtons::A));
}
else if (key == XK_s)
{
mButtons.set(static_cast<std::size_t>(InputButtons::S));
}
else if (key == XK_d)
{
mButtons.set(static_cast<std::size_t>(InputButtons::D));
}
else if (key == XK_q)
{
mButtons.set(static_cast<std::size_t>(InputButtons::Q));
}
else if (key == XK_e)
{
mButtons.set(static_cast<std::size_t>(InputButtons::E));
}
else
{
buttonStateChanged = false;
XFlush(mDisplay);
}
if (buttonStateChanged)
{
Event event(Events::Window::INPUT);
event.SetParam(Events::Window::Input::INPUT, mButtons);
gCoordinator.SendEvent(event);
}
}
else if (xEvent.type == KeyRelease)
{
KeySym key = XkbKeycodeToKeysym(
mDisplay,
static_cast<KeyCode>(xEvent.xkey.keycode),
0, 0);
bool buttonStateChanged = true;
if (key == XK_Escape)
{
gCoordinator.SendEvent(Events::Window::QUIT);
}
else if (key == XK_w)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::W));
}
else if (key == XK_a)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::A));
}
else if (key == XK_s)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::S));
}
else if (key == XK_d)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::D));
}
else if (key == XK_q)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::Q));
}
else if (key == XK_e)
{
mButtons.reset(static_cast<std::size_t>(InputButtons::E));
}
else
{
buttonStateChanged = false;
XFlush(mDisplay);
}
if (buttonStateChanged)
{
Event event(Events::Window::INPUT);
event.SetParam(Events::Window::Input::INPUT, mButtons);
gCoordinator.SendEvent(event);
}
}
else
{
XFlush(mDisplay);
}
}
}

28
Source/WindowManager.hpp Normal file
View File

@ -0,0 +1,28 @@
#pragma once
#include <bitset>
#include <GL/glx.h>
#include <string>
#include <X11/Xlib.h>
class WindowManager
{
public:
void Init(
std::string const& windowTitle, unsigned int windowWidth, unsigned int windowHeight,
unsigned int windowPositionX, unsigned int windowPositionY);
void Update();
void ProcessEvents();
void Shutdown();
private:
Display* mDisplay;
Window mWindow;
GLXContext mGlxContext;
std::bitset<8> mButtons;
};