Merge branch 'master' of https://github.com/teamfisk/TacticalZ into Importer

# Conflicts:
#	include/Engine/Collision/Collision.h
#	src/Engine/Rendering/Model.cpp
#	src/Engine/Rendering/RawModelAssimp.cpp
This commit is contained in:
antc13
2016-01-15 18:00:30 +01:00
109 changed files with 3705 additions and 1382 deletions
+3 -3
View File
@@ -7,10 +7,10 @@
#include <vector>
#include "Core/Ray.h"
#include "Core/AABB.h"
#include "../Core/Ray.h"
#include "../Core/AABB.h"
#include "Engine/Rendering/RawModelAssimp.h"
#include "Core/Entity.h"
#include "../Core/Entity.h"
class World;
struct ComponentWrapper;
+4 -4
View File
@@ -4,10 +4,10 @@
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "Common.h"
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "Core/EKeyUp.h"
#include "../Common.h"
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "../Core/EKeyUp.h"
class CollisionSystem : public PureSystem
{
+2 -2
View File
@@ -4,8 +4,8 @@
#include <glm/common.hpp>
#include <unordered_set>
#include "Core/System.h"
#include "Core/EventBroker.h"
#include "../Core/System.h"
#include "../Core/EventBroker.h"
#include "ETrigger.h"
class AABB;
+2 -1
View File
@@ -14,6 +14,7 @@ struct ComponentInfo
struct Field_t
{
std::string Name;
std::string Type;
unsigned int Offset;
unsigned int Stride;
@@ -21,7 +22,7 @@ struct ComponentInfo
std::string Name;
std::unordered_map<std::string, Field_t> Fields;
std::vector<const Field_t*> FieldsInOrder;
std::vector<std::string> FieldsInOrder;
Meta_t Meta;
std::shared_ptr<char> Defaults = nullptr;
};
+1 -1
View File
@@ -2,7 +2,7 @@
#define Ray_h__
#include "../GLM.h"
#include "Common.h"
#include "../Common.h"
class Ray
{
+132 -39
View File
@@ -12,7 +12,6 @@
/** Base Resource class.
Implement this class for every resource to be handled by the resource manager.
Implement Create() to return a new object of that type.
*/
class Resource
{
@@ -22,6 +21,23 @@ protected:
Resource() { }
public:
//Should be thrown in a Resource's constructor if it cannot complete because another resource is still loading.
//Not actually an error, just a message to the ResourceManager.
struct StillLoadingException : public std::exception
{
virtual const char* what() const throw()
{
return "Resource is still loading.";
}
};
struct FailedLoadingException : public std::exception
{
virtual const char* what() const throw()
{
return "Resource is failed to load.";
}
};
// Pretend that this is a pure virtual function that you have to implement
// FIXME: Why did we do this again instead of just using the constructor?
// static Resource* Create(std::string resourceName);
@@ -33,6 +49,15 @@ public:
unsigned int ResourceID;
};
//Any class inheriting from this class will always be loaded on the master thread, not on a parallel worker thread.
//This is important in case some instructions must be executed on the main thread, e.g. OpenGL commands, like glBindBuffer.
//This resource can still be loaded asyncronously, but it will not be loaded in a thread, instead it's constructor will
//be called once on every ResourceManager::Load, just throw StillLoadingException in the constructor if it is not done yet.
class ThreadUnsafeResource : public Resource
{
friend class ResourceManager;
};
/** Singleton resource manager to keep track of and cache any external engine assets */
class ResourceManager
{
@@ -40,6 +65,7 @@ private:
ResourceManager();
public:
static bool UseThreading;
/*static ResourceManager& Instance()
{
static ResourceManager s;
@@ -49,15 +75,6 @@ public:
template <typename T>
static void RegisterType(std::string typeName);
/** Preloads a resource and caches it for future use
@tparam T Resource type.
@param resourceName Fully qualified name of the resource to preload.
*/
template <typename T>
static void Preload(std::string resourceName);
static void Preload(std::string resourceType, std::string resourceName);
/** Checks if a resource is in cache
@param resourceType Resource type as string.
@@ -65,15 +82,20 @@ public:
*/
// TODO: Templateify
static bool IsResourceLoaded(std::string resourceType, std::string resourceName);
/** Return value should always be a valid pointer, will throw an exception on error.
If the resource has been loaded already, returns a pointer to it.
/** Hot-loads a resource and caches it for future use
If Async is false: Hot-loads a resource, caches it for future use, and returns a pointer to it.
If Async is true: If the resource is not loaded yet, starts loading the resource
in the background and throws Resource::StillLoadingException immediately.
@tparam T Resource type.
@tparam async Set this to true if the resource should be loaded asyncronously.
@param resourceName Fully qualified name of the resource to load.
*/
template <typename T>
static T* Load(std::string resourceName, Resource* parent = nullptr);
static Resource* Load(std::string resourceType, std::string resourceName, Resource* parent = nullptr);
template <typename T, bool async = false>
static T* Load(const std::string& resourceName, Resource* parent = nullptr);
/** Reloads an already loaded resource, keeping its resource ID intact.
@@ -87,19 +109,31 @@ public:
static void Update();
private:
//This is a haxy way to make sure that IsMainThread is run when the program starts, so the master thread id is set.
struct MasterThreadChecker
{
MasterThreadChecker()
{
ResourceManager::IsMainThread();
}
};
const static MasterThreadChecker m_Checker;
static std::unordered_map<std::string, std::string> m_CompilerTypenameToResourceType;
static std::unordered_map<std::string, std::function<Resource*(std::string)>> m_FactoryFunctions; // type -> factory function
static std::unordered_map<std::pair<std::string, std::string>, Resource*> m_ResourceCache; // (type, name) -> resource
static std::unordered_map<std::string, Resource*> m_ResourceFromName; // name -> resource
static std::unordered_map<Resource*, Resource*> m_ResourceParents; // resource -> parent resource
static std::unordered_map<std::pair<std::string, std::string>, boost::thread> m_LoadingThreads; // (type, name) -> loading thread
static std::unordered_map<std::pair<std::string, std::string>, std::exception_ptr> m_LoadingThreadExceptions; // (type, name) -> exceptions
static boost::recursive_mutex m_Mutex;
// TODO: Getters for IDs
static unsigned int m_CurrentResourceTypeID;
static std::unordered_map<std::string, unsigned int> m_ResourceTypeIDs;
// Number of resources of a type. Doubles as local ID.
static std::unordered_map<unsigned int, unsigned int> m_ResourceCount;
// Flag to suppress hot-load warnings when a preloading resource chain loads another resource
static bool m_Preloading;
static FileWatcher m_FileWatcher;
static void fileWatcherCallback(std::string path, FileWatcher::FileEventFlags flags);
@@ -108,22 +142,13 @@ private:
static unsigned int GetNewResourceID(unsigned int typeID);
// Internal: Create a resource and cache it
static Resource* CreateResource(std::string resourceType, std::string resourceName, Resource* parent);
static Resource* createResourceThrowing(const std::string& resourceType, const std::string& resourceName, Resource* parent);
static Resource* createResource(const std::string& resourceType, const std::string& resourceName, Resource* parent, std::exception_ptr& exception);
static Resource* cacheResource(Resource* resource, const std::string& resourceType, const std::string& resourceName, Resource* parent);
static bool IsMainThread();
};
template <typename T>
T* ResourceManager::Load(std::string resourceName, Resource* parent /* = nullptr */)
{
auto resourceTypename = typeid(T).name();
auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
return nullptr;
}
return static_cast<T*>(Load(it->second, resourceName, parent));
}
template <typename T>
void ResourceManager::RegisterType(std::string typeName)
{
@@ -131,17 +156,85 @@ void ResourceManager::RegisterType(std::string typeName)
m_FactoryFunctions[typeName] = [](std::string resourceName) { return new T(resourceName); };
}
template <typename T>
void ResourceManager::Preload(std::string resourceName)
template <typename T, bool async>
static T* ResourceManager::Load(const std::string& resourceName, Resource* parent /* = nullptr */)
{
auto resourceTypename = typeid(T).name();
auto it = m_CompilerTypenameToResourceType.find(resourceTypename);
if (it == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
return;
}
auto resourceTypename = typeid(T).name();
auto iter = m_CompilerTypenameToResourceType.find(resourceTypename);
if (iter == m_CompilerTypenameToResourceType.end()) {
LOG_ERROR("Failed to load resource \"%s\" of type \"%s\": type not registered", resourceName.c_str(), resourceTypename);
throw Resource::FailedLoadingException();
}
Preload(it->second, resourceName);
std::string resourceType = iter->second;
constexpr bool mustNotLoadInThread = std::is_base_of<ThreadUnsafeResource, T>::value;
if (mustNotLoadInThread && !IsMainThread()) {
LOG_ERROR("Failed to Load \"%s\": ThreadUnsafeResource type \"%s\" load in the constructor of another resource that is loaded asyncronously.", resourceName.c_str(), iter->second.c_str());
throw Resource::FailedLoadingException();
}
auto cacheKey = std::make_pair(resourceType, resourceName);
decltype(m_ResourceCache)::iterator it;
//If a thread has already been launched to load this resource.
auto tIt = m_LoadingThreads.find(cacheKey);
if (UseThreading && tIt != m_LoadingThreads.end()) {
if (async) {
//Throw StillLoadingException if the thread is still working.
if (!tIt->second.try_join_for(boost::chrono::nanoseconds(1))) {
throw Resource::StillLoadingException();
}
//Else we know the thread has completed.
} else {
//Wait for the thread to finish loading.
tIt->second.join();
}
//When the thread is done, delete the thread.
m_LoadingThreads.erase(tIt);
//Rethrow the thread exception if it threw any.
auto excIt = m_LoadingThreadExceptions.find(cacheKey);
std::exception_ptr exception = excIt->second;
m_LoadingThreadExceptions.erase(excIt);
if (exception) {
std::rethrow_exception(exception);
}
}
//If resource has already been cached and completely loaded.
it = m_ResourceCache.find(cacheKey);
if (it != m_ResourceCache.end()) {
if (it->second != nullptr) {
return static_cast<T*>(it->second);
} else {
//Don't return null on failure, exception instead.
throw Resource::FailedLoadingException();
}
}
//If resource is not cached..
if (UseThreading && async) {
if (mustNotLoadInThread) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
throw;
}
} else {
//Create a thread that loads the resource into cache.
m_LoadingThreads[cacheKey] = boost::thread(createResource, resourceType, resourceName, parent, m_LoadingThreadExceptions[cacheKey]);
throw Resource::StillLoadingException();
}
} else {
//load and return the resource.
while (true) {
try {
return static_cast<T*>(createResourceThrowing(resourceType, resourceName, parent));
} catch (const Resource::StillLoadingException&) {
continue;
} catch (const std::exception&) {
throw;
}
}
}
}
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Transform_h__
#define Transform_h__
#include "../GLM.h"
#include "World.h"
namespace Transform
{
glm::vec3 AbsolutePosition(World* world, EntityID entity);
glm::quat AbsoluteOrientation(World* world, EntityID entity);
glm::vec3 AbsoluteScale(World* world, EntityID entity);
glm::mat4 ModelMatrix(EntityID entity, World* world);
}
#endif
+5 -5
View File
@@ -9,9 +9,8 @@
#include "../Core/ConfigFile.h"
#include "../Input/EInputCommand.h"
#include "../Rendering/IRenderer.h"
#include "../Rendering/EPicking.h"
#include "../Core/Transform.h"
#include "../Core/EFileDropped.h"
#include "../Rendering/RenderQueueFactory.h"
#include "../Core/EntityFilePreprocessor.h"
#include "../Core/EntityFileParser.h"
#include "../Core/EntityFileWriter.h"
@@ -26,6 +25,7 @@ public:
private:
IRenderer* m_Renderer;
World* m_World = nullptr;
Camera* m_Camera = nullptr;
bool m_Enabled;
bool m_Visible;
@@ -57,6 +57,7 @@ private:
EntityID m_WidgetOrigin = EntityID_Invalid;
glm::vec3 m_WidgetCurrentAxis;
float m_WidgetPickingDepth = 0.f;
glm::vec3 m_WidgetPickingPosition = glm::vec3(0);
EntityID m_Selection = EntityID_Invalid;
EntityID m_LastSelection = EntityID_Invalid;
@@ -75,11 +76,10 @@ private:
bool OnMousePress(const Events::MousePress& e);
EventRelay<EditorSystem, Events::MouseMove> m_EMouseMove;
bool OnMouseMove(const Events::MouseMove& e);
EventRelay<EditorSystem, Events::Picking> m_EPicking;
bool OnPicking(const Events::Picking& e);
EventRelay<EditorSystem, Events::FileDropped> m_EFileDropped;
bool OnFileDropped(const Events::FileDropped& e);
void Picking();
void createWidget();
void updateWidget();
void setWidgetMode(WidgetMode newMode);
+1 -1
View File
@@ -40,7 +40,7 @@ public:
m_TexturePressed = resourceName;
}
void Draw(RenderQueueCollection& rq) override
void Draw(RenderScene& rq) override
{
if (m_Texture == nullptr && !m_TextureReleased.empty()) {
SetTexture(m_TextureReleased);
+2 -2
View File
@@ -212,7 +212,7 @@ public:
virtual void Update(double dt) { }
void DrawLayered(RenderQueueCollection& rq)
void DrawLayered(RenderScene& rq)
{
if (this->Hidden())
return;
@@ -232,7 +232,7 @@ public:
}
}
virtual void Draw(RenderQueueCollection& rq) { }
virtual void Draw(RenderScene& rq) { }
protected:
::EventBroker* m_EventBroker;
+1 -1
View File
@@ -16,7 +16,7 @@ public:
void EnableScissor() { m_ScissorEnabled = true; }
void DisableScissor() { m_ScissorEnabled = false; }
void Draw(RenderQueueCollection& rq) override
void Draw(RenderScene& rq) override
{
if (m_Texture == nullptr)
return;
+3 -4
View File
@@ -23,7 +23,6 @@ public:
~Client();
void Start(World* world, EventBroker* eventBroker) override;
void Update() override;
void Close();
private:
// Assio UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
@@ -32,7 +31,7 @@ private:
// Sending message to server logic
int bytesRead = -1;
char readBuf[1024] = { 0 };
char readBuf[INPUTSIZE] = { 0 };
int snapshotInterval = 33;
std::clock_t previousSnapshotMessage = std::clock();
@@ -49,7 +48,6 @@ private:
// Network logic
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
SnapshotDefinitions m_NextSnapshot;
bool m_ThreadIsRunning = true;
double m_DurationOfPingTime;
std::clock_t m_StartPingTime;
// Use to check if we should send disconnect message
@@ -59,7 +57,7 @@ private:
// Private member functions
void readFromServer();
void sendSnapshotToServer();
int receive(char* data, size_t length);
int receive(char* data, size_t length);
void send(Packet& packet);
void connect();
void disconnect();
@@ -67,6 +65,7 @@ private:
void moveMessageHead(char*& data, size_t& length, size_t stepSize);
void parseMessageType(Packet& packet);
void parseEventMessage(Packet& packet);
void updateFields(Packet& packet, const ComponentInfo& componentInfo, const EntityID& entityID, const std::string& componentType);
void parseConnect(Packet& packet);
void parsePing();
void parseServerPing();
+1 -1
View File
@@ -6,7 +6,7 @@
#include "Network/Packet.h"
#define MAXCONNECTIONS 8
#define INPUTSIZE 128
#define INPUTSIZE 4097
class Network
{
+9 -4
View File
@@ -14,15 +14,17 @@ public:
Packet(MessageType type, unsigned int& packetID);
// Used to create packet from already existing data buffer.
Packet(char* data, const int sizeOfPacket);
~Packet();
void Init(MessageType type, unsigned int& packetID);
// Add primitive types like int, float, char...
template<typename T>
void WritePrimitive(T val)
{
// Check if we are trying to add more than the package can fit.
if (m_MaxPacketSize < m_Offset + sizeof(T)) {
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for!");
LOG_WARNING("Packet AddPrimitive(): You are trying to add more than we have allocated for! New size is %i bytes\n", m_MaxPacketSize*2);
resizeData();
}
memcpy(m_Data + m_Offset, &val, sizeof(T));
m_Offset += sizeof(T);
@@ -41,7 +43,7 @@ public:
return returnValue;
}
// Add a string to the message
void WriteString(std::string str);
void WriteString(const std::string& str);
// Add data to the message
void WriteData(char* data, int sizeOfData);
// Pops the first element as if it was a string.
@@ -50,12 +52,15 @@ public:
int Size() { return m_Offset; };
char* Data() { return m_Data; };
unsigned int DataReadSize() { return m_ReturnDataOffset; }
unsigned int MaxSize() { return m_MaxPacketSize; }
private:
char* m_Data;
unsigned int m_ReturnDataOffset = 0;
int m_Offset = 0;
unsigned int m_MaxPacketSize = 128;
unsigned int m_MaxPacketSize = 512;
void resizeData();
};
#endif
+1 -6
View File
@@ -20,8 +20,6 @@ public:
~Server();
void Start(World* m_world, EventBroker *eventBroker) override;
void Update() override;
void Close();
private:
// UDP logic
boost::asio::ip::udp::endpoint m_ReceiverEndpoint;
@@ -30,7 +28,7 @@ private:
PlayerDefinition m_PlayerDefinitions[MAXCONNECTIONS];
// Sending messages to client logic
char readBuffer[1024] = { 0 };
char readBuffer[INPUTSIZE] = { 0 };
int bytesRead = 0;
// time for previouse message
std::clock_t previousePingMessage = std::clock();
@@ -55,9 +53,6 @@ private:
unsigned int m_PacketID;
unsigned int m_PreviousPacketID;
unsigned int m_SendPacketID;
// Close logic
bool m_ThreadIsRunning = true;
// Private member functions
int receive(char* data, size_t length);
+1 -1
View File
@@ -3,7 +3,7 @@
#include "../Core/ResourceManager.h"
class BaseTexture : public Resource
class BaseTexture : public ThreadUnsafeResource
{
friend class ResourceManager;
+6 -8
View File
@@ -26,13 +26,12 @@ public:
glm::quat Orientation() const { return m_Orientation; }
void SetOrientation(glm::quat val);
/*float Pitch() const { return m_Pitch; }
void Pitch(float val);
float Yaw() const { return m_Yaw; }
void Yaw(float val);*/
glm::mat4 ProjectionMatrix() const { return m_ProjectionMatrix; }
void SetProjectionMatrix(glm::mat4 val);
glm::mat4 ViewMatrix() const { return m_ViewMatrix; }
void SetViewMatrix(glm::mat4 val);
float AspectRatio() const { return m_AspectRatio; }
void SetAspectRatio(float val);
@@ -46,11 +45,10 @@ public:
float FarClip() const { return m_FarClip; }
void SetFarClip(float val);
void UpdateViewMatrix();
void UpdateProjectionMatrix();
private:
void UpdateViewMatrix();
void UpdateProjectionMatrix();
glm::vec3 m_Position;
glm::quat m_Orientation;
@@ -9,6 +9,9 @@ public:
: FirstPersonInputController(eventBroker, playerID)
{ }
void SetPosition(const glm::vec3 position) { m_Position = position; }
void SetOrientation(const glm::quat orientation) { m_Orientation = orientation; }
const glm::vec3 Position() const { return m_Position; }
void SetBaseSpeed(float speed) { m_BaseSpeed = speed; }
+38
View File
@@ -0,0 +1,38 @@
#ifndef DrawFinalPass_h__
#define DrawFinalPass_h__
#include "IRenderer.h"
#include "DrawFinalPassState.h"
#include "LightCullingPass.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "Util/UnorderedMapVec2.h"
#include "Texture.h"
class DrawFinalPass
{
public:
DrawFinalPass(IRenderer* renderer, LightCullingPass* lightCullingPass);
~DrawFinalPass() { }
void InitializeTextures();
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(RenderScene& scene);
//Getters
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
Texture* m_WhiteTexture;
const IRenderer* m_Renderer;
const LightCullingPass* m_LightCullingPass;
ShaderProgram* m_ForwardPlusProgram;
};
#endif
@@ -0,0 +1,15 @@
#ifndef DrawFinalPassState_h__
#define DrawFinalPassState_h__
#include "Rendering/RenderState.h"
class DrawFinalPassState : public RenderState
{
public:
DrawFinalPassState();
~DrawFinalPassState();
private:
};
#endif
+7 -1
View File
@@ -17,7 +17,7 @@ public:
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(RenderQueueCollection& rq);
void Draw(RenderScene& scene);
//Getters
@@ -25,12 +25,18 @@ public:
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
static bool DepthSort(const std::shared_ptr<RenderJob> &i, const std::shared_ptr<RenderJob> &j)
{
return (i->Depth < j->Depth);
};
Texture* m_WhiteTexture;
const IRenderer* m_Renderer;
ShaderProgram* m_BasicForwardProgram;
};
#endif
+1 -1
View File
@@ -9,7 +9,7 @@ class DummyRenderer : public IRenderer
{
public:
virtual void Initialize() override;
virtual void Draw(RenderQueueCollection& rq) override;
virtual void Draw(RenderFrame& rq) override;
};
#endif
-74
View File
@@ -1,74 +0,0 @@
#ifndef Events_Picking_h__
#define Events_Picking_h__
#include "../OpenGL.h"
#include "../GLM.h"
#include "../Core/EventBroker.h"
#include "Util/ScreenCoords.h"
#include "FrameBuffer.h"
#include "../Core/Entity.h"
#include "Util/UnorderedMapVec2.h"
namespace Events
{
/** Thrown Every frame, use functions to pick*/
struct Picking : Event
{
public:
Picking(FrameBuffer* pickingBuffer, GLuint* depthBuffer, glm::mat4 projectionMatrix, glm::mat4 viewMatrix, Rectangle resolution, const std::unordered_map<glm::vec2, EntityID>* pickingColorsToEntity)
: PickingBuffer(pickingBuffer)
, DepthBuffer(depthBuffer)
, ProjectionMatrix(projectionMatrix)
, ViewMatrix(viewMatrix)
, Resolution(resolution)
, PickingColorsToEntity(pickingColorsToEntity)
{ }
struct PickData
{
//Picked Entity
EntityID Entity;
//World position of the "pick"
glm::vec3 Position;
// Depth
float Depth;
};
PickData Pick(glm::vec2 screenCoord) const
{
PickData pickData;
// Invert screen y coordinate
screenCoord.y = Resolution.Height - screenCoord.y;
ScreenCoords::PixelData data = ScreenCoords::ToPixelData(screenCoord, PickingBuffer, *DepthBuffer);
pickData.Depth = data.Depth;
auto it = PickingColorsToEntity->find(glm::vec2(data.Color[0], data.Color[1]));
if (it != PickingColorsToEntity->end()) {
pickData.Entity = it->second;
} else {
pickData.Entity = EntityID_Invalid;
}
pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix);
return pickData;
}
private:
FrameBuffer* PickingBuffer;
GLuint* DepthBuffer;
const glm::mat4 ProjectionMatrix;
const glm::mat4 ViewMatrix;
const Rectangle Resolution;
const std::unordered_map<glm::vec2, EntityID>* PickingColorsToEntity;
};
}
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef Events_SetCamera_h__
#define Events_SetCamera_h__
#include "../Core/EventBroker.h"
#include "../Core/Entity.h"
#include <string.h>
namespace Events
{
struct SetCamera : Event
{
public:
SetCamera() { };
std::string Name;
private:
};
}
#endif
+26 -13
View File
@@ -9,6 +9,17 @@
#include "Camera.h"
#include "RenderQueue.h"
#include "Model.h"
#include "../Core/World.h" //So temp
struct PickData
{
EntityID Entity;
glm::vec3 Position; //World position
float Depth;
::Camera* Camera;
const ::World* World;
};
class IRenderer
{
@@ -20,19 +31,21 @@ public:
void SetFullscreen(bool fullscreen) { m_Fullscreen = fullscreen; }
bool VSYNC() const { return m_VSYNC; }
void SetVSYNC(bool vsync) { m_VSYNC = vsync; }
::Camera* Camera() const { return m_Camera; }
void SetCamera(::Camera* camera)
{
if (camera == nullptr) {
m_Camera = m_DefaultCamera;
} else {
m_Camera = camera;
}
}
::Camera* Camera() const { return m_Camera; }
void SetCamera(::Camera* camera)
{
if (camera == nullptr) {
m_Camera = m_DefaultCamera;
} else {
m_Camera = camera;
}
}
virtual void Initialize() = 0;
virtual void Update(double dt) = 0;
virtual void Draw(RenderQueueCollection& rq) = 0;
virtual void Draw(RenderFrame& rq) = 0;
virtual PickData Pick(glm::vec2 screenCord) = 0;
World* m_World; //Temp world, untill viktor merge.
protected:
Rectangle m_Resolution = Rectangle::Rectangle(1280, 720);
@@ -40,9 +53,9 @@ protected:
bool m_VSYNC = false;
int m_GLVersion[2];
std::string m_GLVendor;
::Camera* m_DefaultCamera;
::Camera* m_Camera = nullptr;
GLFWwindow* m_Window = nullptr;
::Camera* m_DefaultCamera;
::Camera* m_Camera = nullptr;
};
#endif // Renderer_h__
@@ -0,0 +1,83 @@
#ifndef LightCullingPass_h__
#define LightCullingPass_h__
#define TILE_SIZE 16
#define MAX_LIGHTS_PER_TILE 200
#include "IRenderer.h"
#include "LightCullingPassState.h"
#include "ShaderProgram.h"
#include "RenderQueue.h"
class LightCullingPass
{
public:
LightCullingPass(IRenderer* renderer);
~LightCullingPass();
void GenerateNewFrustum(RenderScene& scene);
void OnResolutionChange();
void SetSSBOSizes();
void CullLights(RenderScene& scene);
void FillLightList(RenderScene& scene);
GLuint FrustumSSBO() const { return m_FrustumSSBO; }
GLuint LightSSBO() const { return m_LightSSBO; }
GLuint LightGridSSBO() const { return m_LightGridSSBO; }
GLuint LightOffsetSSBO() const { return m_LightOffsetSSBO; }
GLuint LightIndexSSBO() const { return m_LightIndexSSBO; }
private:
void InitializeSSBOs();
void InitializeShaderPrograms();
const IRenderer* m_Renderer;
GLuint m_FrustumSSBO = 0;
GLuint m_LightSSBO = 0;
GLuint m_LightGridSSBO = 0;
GLuint m_LightOffsetSSBO = 0;
GLuint m_LightIndexSSBO = 0;
ShaderProgram* m_CalculateFrustumProgram;
ShaderProgram* m_LightCullProgram;
int m_NumberOfTiles = 0;
struct Plane {
glm::vec3 Normal;
float d;
};
struct Frustum {
Plane Planes[4];
};
Frustum* m_Frustums;
//This should be a component
struct PointLight {
glm::vec4 Position = glm::vec4(0.f);
glm::vec4 Color = glm::vec4(1.f);
float Radius = 5.f;
float Intensity = 0.8f;
float Falloff = 0.3f;
float Padding = 1337;
};
std::vector<PointLight> m_PointLights;
struct LightGrid {
float Start;
float Amount;
glm::vec2 Padding;
};
LightGrid* m_LightGrid;
int m_LightOffset = 0;
float* m_LightIndex;
};
#endif
+5 -1
View File
@@ -4,7 +4,7 @@
#include "RawModelAssimp.h"
#include "../OpenGL.h"
class Model : public RawModel
class Model : public ThreadUnsafeResource
{
friend class ResourceManager;
@@ -13,11 +13,15 @@ private:
public:
~Model();
const std::vector<RawModel::MaterialGroup>& MaterialGroups() const { return m_RawModel->MaterialGroups; }
const glm::mat4& Matrix() const { return m_RawModel->m_Matrix; }
const std::vector<RawModel::Vertex>& Vertices() const { return m_RawModel->m_Vertices; }
GLuint VAO;
GLuint ElementBuffer;
private:
RawModel* m_RawModel;
GLuint VertexBuffer;
GLuint DiffuseVertexColorBuffer;
GLuint SpecularVertexColorBuffer;
+55
View File
@@ -0,0 +1,55 @@
#ifndef ModelJob_h__
#define ModelJob_h__
#include <cstdint>
#include "../Common.h"
#include "../GLM.h"
#include "../Core/ComponentWrapper.h"
#include "Texture.h"
#include "Model.h"
#include "RenderJob.h"
#include "../Core/ResourceManager.h"
#include "Camera.h"
#include "../Core/World.h"
struct ModelJob : RenderJob
{
ModelJob(Model* model, Camera* camera, glm::mat4 matrix, ::RawModel::MaterialGroup matGroup, ComponentWrapper modelComponent, World* world)
: RenderJob()
{
Model = model;
TextureID = (matGroup.Texture) ? matGroup.Texture->ResourceID : 0;
DiffuseTexture = matGroup.Texture.get();
NormalTexture = matGroup.NormalMap.get();
SpecularTexture = matGroup.SpecularMap.get();
StartIndex = matGroup.StartIndex;
EndIndex = matGroup.EndIndex;
Matrix = matrix;
Color = modelComponent["Color"];
Entity = modelComponent.EntityID;
World = world;
};
unsigned int TextureID;
unsigned int ShaderID;
EntityID Entity;
glm::mat4 Matrix;
const Texture* DiffuseTexture;
const Texture* NormalTexture;
const Texture* SpecularTexture;
float Shininess = 0.f;
glm::vec4 Color;
const ::Model* Model = nullptr;
unsigned int StartIndex = 0;
unsigned int EndIndex = 0;
World* World;
void CalculateHash() override
{
Hash = TextureID;
}
};
#endif
+23 -6
View File
@@ -1,13 +1,17 @@
#ifndef PickingPass_h__
#define PickingPass_h__
#include "IRenderer.h"
#include "PickingPassState.h"
#include "FrameBuffer.h"
#include "ShaderProgram.h"
#include "Util/UnorderedMapVec2.h"
#include "Util/UnorderedMapiVec2.h"
#include "../Core/EventBroker.h"
#include "EPicking.h"
#include "../Core/World.h"
class PickingPass
{
@@ -18,16 +22,18 @@ public:
void InitializeFrameBuffers();
void InitializeShaderPrograms();
void Draw(RenderQueueCollection& rq);
void Draw(RenderScene& scene);
void ClearPicking();
//Getters
const ShaderProgram& PickingProgram() const { return *m_PickingProgram; }
const std::unordered_map<glm::vec2, EntityID>& PickingColorsToEntity() const { return m_PickingColorsToEntity; }
//const std::unordered_map<glm::ivec2, EntityID>& PickingColorsToEntity() const { return m_PickingColorsToEntity; }
GLuint PickingTexture() const { return m_PickingTexture; }
GLuint DepthBuffer() const { return m_DepthBuffer; }
const FrameBuffer& PickingBuffer() const { return m_PickingBuffer; }
PickData Pick(glm::vec2 screenCoord);
private:
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) const;
@@ -37,13 +43,24 @@ private:
const IRenderer* m_Renderer;
ShaderProgram* m_PickingProgram;
Camera* m_Camera;
std::unordered_map<glm::vec2, EntityID> m_PickingColorsToEntity;
struct PickingInfo
{
EntityID Entity;
const ::World* World;
::Camera* Camera;
};
std::unordered_map<glm::ivec2, PickingInfo> m_PickingColorsToEntity;
GLuint m_PickingTexture;
GLuint m_DepthBuffer;
FrameBuffer m_PickingBuffer;
int m_ColorCounter[2];
std::map<std::tuple<EntityID, const World*, Camera*>, glm::ivec2> m_EntityColors;
};
#endif
+39
View File
@@ -0,0 +1,39 @@
#ifndef PointLightJob_h__
#define PointLightJob_h__
#include <cstdint>
#include "../Common.h"
#include "../GLM.h"
#include "../Core/ComponentWrapper.h"
#include "RenderJob.h"
#include "../Core/Transform.h"
#include "../Core/World.h"
struct PointLightJob : RenderJob
{
PointLightJob(ComponentWrapper transformComponent, ComponentWrapper pointLightComponent, World* m_World)
: RenderJob()
{
Position = glm::vec4((glm::vec3)transformComponent["Position"], 1.0f);
Position = glm::vec4(Transform::AbsolutePosition(m_World, transformComponent.EntityID), 1.f);
Color = (glm::vec4)pointLightComponent["Color"];
Radius = (double)pointLightComponent["Radius"];
Intensity = (double)pointLightComponent["Intensity"];
Falloff = (double)pointLightComponent["Falloff"];
};
glm::vec4 Position;
glm::vec4 Color;
float Radius;
float Intensity;
float Falloff;
float padding = 123;
void CalculateHash() override
{
Hash = 0;
}
};
#endif
+5 -1
View File
@@ -42,14 +42,18 @@ public:
struct MaterialGroup
{
float Shininess;
float Transparency;
std::string TexturePath;
std::shared_ptr<::Texture> Texture;
std::string NormalMapPath;
std::shared_ptr<::Texture> NormalMap;
std::string SpecularMapPath;
std::shared_ptr<::Texture> SpecularMap;
unsigned int StartIndex;
unsigned int EndIndex;
};
std::vector<MaterialGroup> TextureGroups;
std::vector<MaterialGroup> MaterialGroups;
std::vector<Vertex> m_Vertices;
std::vector<unsigned int> m_Indices;
+32
View File
@@ -0,0 +1,32 @@
#ifndef RenderJob_h__
#define RenderJob_h__
#include <cstdint>
#include "../Common.h"
#include "../GLM.h"
#include "../Core/ComponentWrapper.h"
#include "RenderQueue.h"
struct RenderJob
{
friend class RenderQueue;
public:
float Depth;
protected:
uint64_t Hash;
virtual void CalculateHash() = 0;
bool operator<(const RenderJob& rhs)
{
return this->Hash < rhs.Hash;
}
};
#endif
+47 -103
View File
@@ -8,61 +8,13 @@
#include "../GLM.h"
#include "../Core/Util/Rectangle.h"
#include "../Core/Entity.h"
#include "Camera.h"
#include "RenderJob.h"
#include "ModelJob.h"
#include "PointLightJob.h"
class Model;
class Skeleton;
class Texture;
class RenderQueue;
//TODO: Render: Remove obsolete RenderJobs and fix standard values on variables.
struct RenderJob
{
friend class RenderQueue;
float Depth;
protected:
uint64_t Hash;
virtual void CalculateHash() = 0;
bool operator<(const RenderJob& rhs)
{
return this->Hash < rhs.Hash;
}
};
struct ModelJob : RenderJob
{
unsigned int ShaderID = 0;
unsigned int TextureID = 0;
//TODO: RENDERER: Not sure if the best solution for pickingColor to entity link is this
EntityID Entity;
glm::mat4 ModelMatrix;
const Texture* DiffuseTexture;
const Texture* NormalTexture;
const Texture* SpecularTexture;
float Shininess = 0.f;
glm::vec4 Color;
const Model* Model = nullptr;
unsigned int StartIndex = 0;
unsigned int EndIndex = 0;
// Animation
Skeleton* Skeleton = nullptr;
bool NoRootMotion = true;
std::string AnimationName;
double AnimationTime = 0;
void CalculateHash() override
{
Hash = TextureID;
}
};
/*
struct SpriteJob : RenderJob
{
unsigned int ShaderID = 0;
@@ -82,73 +34,65 @@ struct SpriteJob : RenderJob
struct PointLightJob : RenderJob
{
glm::vec3 Position;
glm::vec3 SpecularColor = glm::vec3(1, 1, 1);
glm::vec3 DiffuseColor = glm::vec3(1, 1, 1);
float Radius = 1.f;
float Intensity = 0.8f;
glm::vec4 Position;
glm::vec4 Color;
float Radius;
float Intensity;
float Falloff;
float padding = 123;
void CalculateHash() override
{
Hash = 0;
}
};
*/
class RenderQueue
struct RenderScene
{
public:
template <typename T>
void Add(T &job)
{
job.CalculateHash();
Jobs.push_back(std::shared_ptr<T>(new T(job)));
m_Size++;
}
void Sort()
{
Jobs.sort();
}
::Camera* Camera;
std::list<std::shared_ptr<RenderJob>> ForwardJobs;
std::list<std::shared_ptr<RenderJob>> PointLightJobs;
Rectangle Viewport;
void Clear()
{
Jobs.clear();
m_Size = 0;
ForwardJobs.clear();
PointLightJobs.clear();
}
int Size() const { return m_Size; }
std::list<std::shared_ptr<RenderJob>>::const_iterator begin()
{
return Jobs.begin();
}
std::list<std::shared_ptr<RenderJob>>::const_iterator end()
{
return Jobs.end();
}
std::list<std::shared_ptr<RenderJob>> Jobs;
private:
int m_Size = 0;
};
struct RenderQueueCollection
struct RenderFrame
{
RenderQueue Forward;
RenderQueue Lights;
public:
void Clear()
{
Forward.Clear();
Lights.Clear();
}
void Add(RenderScene &scene)
{
RenderScenes.push_back(std::shared_ptr<RenderScene>(new RenderScene(scene)));
m_Size++;
}
void Sort()
{
Forward.Sort();
Lights.Sort();
}
void Clear()
{
RenderScenes.clear();
m_Size = 0;
}
int Size() const { return m_Size; }
std::list<std::shared_ptr<RenderScene>>::const_iterator begin()
{
return RenderScenes.begin();
}
std::list<std::shared_ptr<RenderScene>>::const_iterator end()
{
return RenderScenes.end();
}
std::list<std::shared_ptr<RenderScene>> RenderScenes;
private:
int m_Size = 0;
};
#endif
@@ -1,31 +0,0 @@
#ifndef RenderQueueFactory_h__
#define RenderQueueFactory_h__
#include "../Core/World.h"
#include "RenderQueue.h"
#include "../Core/ResourceManager.h"
#include "Model.h"
#include "../GLM.h"
class RenderQueueFactory
{
public:
RenderQueueFactory();
void Update(World* world);
RenderQueueCollection RenderQueues() const { return m_RenderQueues; }
static glm::vec3 AbsolutePosition(World* world, EntityID entity);
static glm::quat AbsoluteOrientation(World* world, EntityID entity);
static glm::vec3 AbsoluteScale(World* world, EntityID entity);
private:
RenderQueueCollection m_RenderQueues;
void FillModels(World* world, RenderQueue* renderQueue);
void FillLights(World* world, RenderQueue* renderQueue);
glm::mat4 ModelMatrix(World* world, EntityID entity);
};
#endif
+55
View File
@@ -0,0 +1,55 @@
#ifndef RenderSystem_h__
#define RenderSystem_h__
#include "../Core/System.h"
#include "RenderQueue.h"
#include "../GLM.h"
#include "../OpenGL.h"
#include "../Core/ResourceManager.h"
#include "ESetCamera.h"
#include "Model.h"
#include "../Core/EKeyDown.h"
#include "../Input/EInputCommand.h"
#include "Camera.h"
#include "ModelJob.h"
#include "Renderer.h"
#include "PointLightJob.h"
#include "../Core/Transform.h"
#include "DebugCameraInputController.h"
class RenderSystem : public ImpureSystem
{
public:
RenderSystem(EventBroker* eventBrokerer, const IRenderer* renderer, RenderFrame* renderFrame);
~RenderSystem();
virtual void Update(World* world, double dt) override;
private:
World* m_World = nullptr;
const IRenderer* m_Renderer;
RenderFrame* m_RenderFrame;
bool m_SwitchCamera = false;
Camera* m_Camera;
DebugCameraInputController<RenderSystem>* m_DebugCameraInputController;
std::list<ComponentWrapper> m_CameraComponents;
EventRelay<RenderSystem, Events::SetCamera> m_ESetCamera;
bool OnSetCamera(const Events::SetCamera &event);
EntityID m_CurrentCamera = EntityID_Invalid;
void switchCamera(EntityID entity);
void updateCamera(World* world, double dt);
void updateProjectionMatrix(ComponentWrapper& cameraComponent);
void fillModels(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
void fillLight(std::list<std::shared_ptr<RenderJob>>& jobs, World* world);
EventRelay<RenderSystem, Events::InputCommand> m_EInputCommand;
bool OnInputCommand(const Events::InputCommand& e);
};
#endif
+14 -69
View File
@@ -12,45 +12,34 @@
#include "../Core/World.h"
#include "PickingPass.h"
#include "DrawScenePass.h"
#include "DebugCameraInputController.h"
#define TILE_SIZE 16
#define NUM_LIGHTS 3
enum lightType
{
Point,
Spot,
Directional,
Area
};
#include "LightCullingPass.h"
#include "DrawFinalPass.h"
#include "../Core/EventBroker.h"
#include "EPicking.h"
#include "ImGuiRenderPass.h"
#include "Camera.h"
#include "../Core/Transform.h"
class Renderer : public IRenderer
{
public:
Renderer(EventBroker* eventBroker)
Renderer(EventBroker* eventBroker, World* world)
: m_EventBroker(eventBroker)
, m_World(world)
{ }
virtual void Initialize() override;
virtual void Update(double dt) override;
virtual void Draw(RenderQueueCollection& rq) override;
virtual void Draw(RenderFrame& frame) override;
virtual PickData Pick(glm::vec2 screenCoord) override;
private:
//----------------------Variables----------------------//
EventBroker* m_EventBroker;
std::shared_ptr<DebugCameraInputController<Renderer>> m_DebugCameraInputController;
World* m_World;
Texture* m_ErrorTexture;
Texture* m_WhiteTexture;
float m_CameraMoveSpeed;
Model* m_ScreenQuad;
Model* m_UnitQuad;
@@ -58,70 +47,26 @@ private:
DrawScenePass* m_DrawScenePass;
PickingPass* m_PickingPass;
LightCullingPass* m_LightCullingPass;
ImGuiRenderPass* m_ImGuiRenderPass;
DrawFinalPass* m_DrawFinalPass;
//----------------------Functions----------------------//
void InitializeWindow();
void InitializeShaders();
void InitializeTextures();
void InitializeSSBOs();
void InitializeRenderPasses();
//TODO: Renderer: Get InputUpdate out of renderer
void InputUpdate(double dt);
//void PickingPass(RenderQueueCollection& rq);
void DrawScreenQuad(GLuint textureToDraw);
//----------------------Forward+-----------------------//
void CalculateFrustum();
void CullLights();
//Frustum
struct Plane {
glm::vec3 Normal;
float d;
};
struct Frustum {
Plane Planes[4];
};
Frustum m_Frustums[80*45]; //TODO: Renderer: Make this change with resolution
//Lights
void TEMPCreateLights();
//TODO: Renderer: Add Directionllights, spotlights and area lights to this as type.
struct PointLight {
glm::vec4 Position = glm::vec4(0.f);
glm::vec4 Color = glm::vec4(1.f);
float Radius = 5.f;
float Intensity = 0.8f;
float Falloff = 0.3f;
float Padding = 1337;
};
PointLight m_PointLights[NUM_LIGHTS];
struct LightGrid {
int Amount;
int Start;
glm::vec2 Padding;
};
LightGrid m_LightGrid[80*45];
int m_LightOffset = 0;
int m_LightIndex[80*45*200];
//-------------------------SSBO------------------------//
GLuint m_FrustumSSBO = 0;
GLuint m_LightSSBO = 1;
GLuint m_LightGridSSBO = 2;
GLuint m_LightOffsetSSBO = 3;
GLuint m_LightIndexSSBO = 4;
static bool DepthSort(const std::shared_ptr<RenderJob> &i, const std::shared_ptr<RenderJob> &j) { return (i->Depth < j->Depth); }
void FillDepth(RenderScene& scene);
void GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type);
//--------------------ShaderPrograms-------------------//
ShaderProgram* m_BasicForwardProgram;
ShaderProgram* m_DrawScreenQuadProgram;
ShaderProgram* m_CalculateFrustumProgram;
ShaderProgram* m_LightCullProgram;
};
#endif
@@ -0,0 +1,24 @@
#pragma once
#ifndef UnorderedMapiVec2_h__
#define UnorderedMapiVec2_h__
#include <functional>
#include <boost/functional/hash.hpp>
#include <glm/vec2.hpp>
template<>
struct std::hash<glm::ivec2>
{
inline std::size_t operator()(const glm::ivec2 &v) const
{
return boost::hash<float>()(v.x) ^ boost::hash<float>()(v.y);
}
inline bool operator()(const glm::ivec2& a, const glm::ivec2& b)const
{
return a.x == b.x && a.y == b.y;
}
};
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Events_ContinueSound_h__
#define Events_ContinueSound_h__
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
// Continues to play a sound from where it was paused.
struct ContinueSound : Event
{
EntityID EmitterID;
};
}
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Events_PauseSound_h__
#define Events_PauseSound_h__
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
// Pauses a playing sound
struct PauseSound : Event
{
EntityID EmitterID;
};
}
#endif
@@ -0,0 +1,18 @@
#ifndef Events_PlayBackgroundMusic_h__
#define Events_PlayBackgroundMusic_h__
#include <string>
#include "Core/Entity.h"
#include "Core/Event.h"
namespace Events
{
// Play a sound that will be heared the same anywhere
struct PlayBackgroundMusic : public Event
{
std::string FilePath = "";
};
}
#endif
+21
View File
@@ -0,0 +1,21 @@
#ifndef Events_PlaySoundOnEntity_h__
#define Events_PlaySoundOnEntity_h__
#include <string>
#include "Core/Entity.h"
#include "Core/Event.h"
namespace Events
{
// Plays a sound on an entity with a SoundEmitter component attached.
// Sound behavior is thereby specified in the SoundEmitter component.
struct PlaySoundOnEntity : public Event
{
EntityID EmitterID = 0;
std::string FilePath = "";
};
}
#endif
@@ -0,0 +1,26 @@
#ifndef Events_PlaySoundOnPosition_h__
#define Events_PlaySoundOnPosition_h__
#include <string>
#include <glm/common.hpp>
#include "Core/Event.h"
namespace Events
{
// Plays a sound on a given position. Idk if this would be useful.
struct PlaySoundOnPosition : public Event
{
glm::vec3 Position = glm::vec3(0);
std::string FilePath = "";
float Gain = 1;
float Pitch = 1;
bool Loop = false;
float MaxDistance = 20;
float RollOffFactor = 1;
float ReferenceDistance = 1;
};
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef Events_SetBGMGain_h__
#define Events_SetBGMGain_h__
#include "Core/Event.h"
namespace Events
{
// Set the "volume" for all background sounds
struct SetBGMGain : public Event
{
float Gain;
};
}
#endif
+16
View File
@@ -0,0 +1,16 @@
#ifndef Events_SetSFXGain_h__
#define Events_SetSFXGain_h__
#include "Core/Event.h"
namespace Events
{
// Set the "volume" for all effect sounds
struct SetSFXGain : public Event
{
float Gain;
};
}
#endif
+17
View File
@@ -0,0 +1,17 @@
#ifndef Events_StopSound_h__
#define Events_StopSound_h__
#include "Core/EventBroker.h"
#include "Core/Entity.h"
namespace Events
{
// Stops a sound emitter, and will also delete it.
struct StopSound : Event
{
EntityID EmitterID;
};
}
#endif
+113
View File
@@ -0,0 +1,113 @@
#ifndef Sound_h__
#define Sound_h__
#include "Core/ResourceManager.h"
class Sound : public Resource
{
friend class ResourceManager;
public:
Sound(std::string path) { m_Buffer = LoadFile(path); m_Path = path; }
~Sound() { ClearBuffer(); }
ALuint Buffer() { return m_Buffer; }
std::string Path() { return m_Path; }
float Gain() { return m_Gain; }
void SetGain(float value) { m_Gain = value; }
void ClearBuffer() { alDeleteBuffers(1, &m_Buffer); m_BufferCache.clear(); };
private:
float m_Gain = 1;
ALuint m_Buffer;
std::string m_Path;
// File info
char m_Type[4];
unsigned long m_Size, m_ChunkSize;
short m_FormatType, m_Channels;
unsigned long m_SampleRate, m_AvgBytesPerSec;
short m_BytesPerSample, m_BitsPerSample;
unsigned int m_DataSize;
std::map<std::string, ALuint> m_BufferCache;
ALuint LoadFile(std::string path)
{
if (m_BufferCache.find(path) != m_BufferCache.end()) {
return m_BufferCache[path];
}
// Open file
FILE *fp = fopen(path.c_str(), "rb");
if (!fp) {
printf("Sound: Failed to open file %s, no such file exists", path.c_str());
return 0;
}
//CHECK FOR VALID WAVE-FILE
fread(m_Type, sizeof(char), 4, fp);
if (m_Type[0] != 'R' || m_Type[1] != 'I' || m_Type[2] != 'F' || m_Type[3] != 'F') {
printf("ERROR: No RIFF in WAVE-file");
return 0;
}
fread(&m_Size, 4 * sizeof(char), 1, fp);
fread(m_Type, sizeof(char), 4, fp);
if (m_Type[0] != 'W' || m_Type[1] != 'A' || m_Type[2] != 'V' || m_Type[3] != 'E') {
printf("ERROR: Not WAVE-file");
return 0;
}
fread(m_Type, sizeof(char), 4, fp);
if (m_Type[0] != 'f' || m_Type[1] != 'm' || m_Type[2] != 't' || m_Type[3] != ' ') {
printf("ERROR: No fmt in WAVE-file");
return 0;
}
// READ THE DATA FROM WAVE-FILE
fread(&m_ChunkSize, 4 * sizeof(char), 1, fp);
fread(&m_FormatType, 2 * sizeof(char), 1, fp);
fread(&m_Channels, 2 * sizeof(char), 1, fp);
fread(&m_SampleRate, 4 * sizeof(char), 1, fp);
fread(&m_AvgBytesPerSec, 4 * sizeof(char), 1, fp);
fread(&m_BytesPerSample, 2 * sizeof(char), 1, fp);
fread(&m_BitsPerSample, 2 * sizeof(char), 1, fp);
fread(m_Type, sizeof(char), 4, fp);
if (m_Type[0] != 'd' || m_Type[1] != 'a' || m_Type[2] != 't' || m_Type[3] != 'a') {
printf("ERROR: WAVE-file Missing data");
return 0;
}
fread(&m_DataSize, 4 * sizeof(char), 1, fp);
unsigned char* buf = new unsigned char[m_DataSize];
fread(buf, sizeof(char), m_DataSize, fp);
fclose(fp);
// Create buffer
ALuint format = 0;
if (m_BitsPerSample == 8) {
if (m_Channels == 1) {
format = AL_FORMAT_MONO8;
} else if (m_Channels == 2) {
format = AL_FORMAT_STEREO8;
}
}
if (m_BitsPerSample == 16) {
if (m_Channels == 1) {
format = AL_FORMAT_MONO16;
} else if (m_Channels == 2) {
format = AL_FORMAT_STEREO16;
}
}
ALuint buffer;
alGenBuffers(1, &buffer);
alBufferData(buffer, format, buf, m_DataSize, m_SampleRate);
delete[] buf;
m_BufferCache[path] = buffer;
return buffer;
}
};
#endif
+101
View File
@@ -0,0 +1,101 @@
#ifndef SoundSystem_h__
#define SoundSystem_h__
#include <unordered_map>
#include "glm/common.hpp"
#include "glm/gtx/rotate_vector.hpp" // Calculate Up vector
#include "OpenAL/al.h"
#include "OpenAL/alc.h"
#include "Core/World.h"
#include "Core/EventBroker.h"
#include "Core/Transform.h" // Absolute transform
#include "Sound/Sound.h"
#include "Sound/EPlaySoundOnEntity.h"
#include "Sound/EPlaySoundOnPosition.h"
#include "Sound/EPlayBackgroundMusic.h"
#include "Sound/EPauseSound.h"
#include "Sound/EContinueSound.h"
#include "Sound/EStopSound.h"
#include "Sound/ESetBGMGain.h"
#include "Sound/ESetSFXGain.h"
enum class SoundType {
SFX,
BGM
};
struct Source
{
Source() { }
Sound* SoundResource = nullptr;
ALuint ALsource;
SoundType Type;
};
class SoundSystem
{
public:
SoundSystem() { }
SoundSystem(World* world, EventBroker* eventBroker, bool editorMode);
~SoundSystem();
// Update emitters / listener
void Update(double dt);
private:
// Help functions for working with OpenaAL
void setListenerPos(glm::vec3 pos) { alListener3f(AL_POSITION, pos.x, pos.y, pos.z); };
void setListenerVel(glm::vec3 vel) { alListener3f(AL_VELOCITY, vel.x, vel.y, vel.z); };
void setListenerOri(glm::vec3 ori);
glm::vec3 listnerPos() { glm::vec3 pos; alGetListener3f(AL_POSITION, &pos.x, &pos.y, &pos.z); return pos; };
glm::vec3 listenerVel() { glm::vec3 vel; alGetListener3f(AL_VELOCITY, &vel.x, &vel.y, &vel.z); return vel; };
glm::vec3 listenerOri() { glm::vec3 ori; alGetListener3f(AL_ORIENTATION, &ori.x, &ori.y, &ori.z); return ori; };
void setSourcePos(ALuint source, glm::vec3 pos) { ALfloat spos[3] = { pos.x, pos.y, pos.z }; alSourcefv(source, AL_POSITION, spos); };
void setSourceVel(ALuint source, glm::vec3 vel) { ALfloat svel[3] = { vel.x, vel.y, vel.z }; alSourcefv(source, AL_VELOCITY, svel); };
// Logic
void initOpenAL();
void updateEmitters(double dt);
void updateListener(double dt);
void deleteInactiveEmitters();
void addNewEmitters(double dt);
Source* createSource(std::string filePath);
void playSound(Source* source);
void stopSound(Source* source);
void stopEmitters();
ALenum getSourceState(ALuint source);
void setGain(Source* source, float gain);
void setSoundProperties(ALuint source, ComponentWrapper* soundComponent);
// OpenAL system variables
ALCdevice* m_ALCdevice = nullptr;
ALCcontext* m_ALCcontext = nullptr;
// Logic
World* m_World = nullptr;
EventBroker* m_EventBroker = nullptr;
std::unordered_map<EntityID, Source*> m_Sources;
float m_BGMVolumeChannel = 1.0f;
float m_SFXVolumeChannel = 1.f;
bool m_EditorEnabled = false;
// Events
EventRelay<SoundSystem, Events::PlaySoundOnEntity> m_EPlaySoundOnEntity;
bool OnPlaySoundOnEntity(const Events::PlaySoundOnEntity &e);
EventRelay<SoundSystem, Events::PlaySoundOnPosition> m_EPlaySoundOnPosition;
bool OnPlaySoundOnPosition(const Events::PlaySoundOnPosition &e);
EventRelay<SoundSystem, Events::PlayBackgroundMusic> m_EPlayBackgroundMusic;
bool OnPlayBackgroundMusic(const Events::PlayBackgroundMusic &e);
EventRelay<SoundSystem, Events::PauseSound> m_EPauseSound;
bool OnPauseSound(const Events::PauseSound &e);
EventRelay<SoundSystem, Events::StopSound> m_EStopSound;
bool OnStopSound(const Events::StopSound &e);
EventRelay<SoundSystem, Events::ContinueSound> m_EContinueSound;
bool OnContinueSound(const Events::ContinueSound &e);
EventRelay<SoundSystem, Events::SetBGMGain> m_ESetBGMGain;
bool OnSetBGMGain(const Events::SetBGMGain &e); // Not tested
EventRelay<SoundSystem, Events::SetSFXGain> m_ESetSFXGain;
bool OnSetSFXGain(const Events::SetSFXGain &e); // Not tested
};
#endif