Add code
This commit is contained in:
parent
777df2cbe7
commit
9fbd7938d0
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "Core/System.hpp"
|
||||
|
||||
|
||||
class PhysicsSystem : public System
|
||||
{
|
||||
public:
|
||||
void Init();
|
||||
|
||||
void Update(float dt);
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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{};
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
};
|
Loading…
Reference in New Issue