From a7985b1686e8899e5d85841f6df371017170047a Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Fri, 4 Apr 2014 23:14:18 +0200 Subject: [PATCH] Adapted Escape the Dawn engine. --- src/Camera.cpp | 99 ++++ src/Camera.h | 59 ++ src/Color.h | 10 + src/Component.h | 14 + src/Components/Bounds.h | 17 + src/Components/Camera.h | 19 + src/Components/Collision.h | 21 + src/Components/DirectionalLight.h | 19 + src/Components/Input.h | 25 + src/Components/Model.h | 22 + src/Components/ParticleEmitter.h | 25 + src/Components/PointLight.h | 22 + src/Components/PowerUp.h | 15 + src/Components/SoundEmitter.h | 22 + src/Components/Sprite.h | 19 + src/Components/Stat.h | 16 + src/Components/Template.h | 12 + src/Components/Transform.h | 22 + src/CubemapTexture.cpp | 59 ++ src/CubemapTexture.h | 27 + src/Engine.h | 41 ++ src/Entity.h | 1 + src/Factory.h | 32 ++ src/GameWorld.cpp | 58 ++ src/GameWorld.h | 49 ++ src/Model.cpp | 251 +++++++++ src/Model.h | 59 ++ src/OBJ.cpp | 228 ++++++++ src/OBJ.h | 64 +++ src/OpenGL.h | 4 - src/PrecompiledHeader.cpp | 1 + src/{GLM.h => PrecompiledHeader.h} | 13 + src/Renderer.cpp | 533 ++++++++++++++++++ src/Renderer.h | 112 ++++ src/ShaderProgram.cpp | 145 +++++ src/ShaderProgram.h | 79 +++ src/Shaders/AABB.frag.glsl | 17 + src/Shaders/Fragment.glsl | 109 ++++ src/Shaders/Normals.frag.glsl | 9 + src/Shaders/Normals.geo.glsl | 34 ++ src/Shaders/ShadowMap.frag.glsl | 9 + src/Shaders/ShadowMap.vert.glsl | 22 + src/Shaders/Skybox.frag.glsl | 15 + src/Shaders/Skybox.vert.glsl | 15 + src/Shaders/Vertex.glsl | 25 + src/Shaders/VisualizeDepth.frag.glsl | 24 + src/Shaders/VisualizeDepth.vert.glsl | 17 + src/Skybox.cpp | 91 +++ src/Skybox.h | 30 + src/System.h | 34 ++ src/Systems/RenderSystem.cpp | 74 +++ src/Systems/RenderSystem.h | 44 ++ src/Systems/TransformSystem.cpp | 48 ++ src/Systems/TransformSystem.h | 25 + src/Texture.cpp | 26 + src/Texture.h | 21 + src/Util/GLError.h | 9 +- src/Util/Logging.h | 6 +- src/World.cpp | 132 +++++ src/World.h | 136 +++++ src/main.cpp | 57 +- vs12/Returngeance.sln | 5 +- vs12/Returngeance/Returngeance.vcxproj | 83 ++- .../Returngeance/Returngeance.vcxproj.filters | 132 ++++- 64 files changed, 3384 insertions(+), 79 deletions(-) create mode 100755 src/Camera.cpp create mode 100755 src/Camera.h create mode 100755 src/Color.h create mode 100755 src/Component.h create mode 100755 src/Components/Bounds.h create mode 100755 src/Components/Camera.h create mode 100755 src/Components/Collision.h create mode 100755 src/Components/DirectionalLight.h create mode 100755 src/Components/Input.h create mode 100755 src/Components/Model.h create mode 100755 src/Components/ParticleEmitter.h create mode 100755 src/Components/PointLight.h create mode 100755 src/Components/PowerUp.h create mode 100755 src/Components/SoundEmitter.h create mode 100755 src/Components/Sprite.h create mode 100755 src/Components/Stat.h create mode 100755 src/Components/Template.h create mode 100755 src/Components/Transform.h create mode 100755 src/CubemapTexture.cpp create mode 100755 src/CubemapTexture.h create mode 100755 src/Engine.h create mode 100755 src/Entity.h create mode 100755 src/Factory.h create mode 100755 src/GameWorld.cpp create mode 100755 src/GameWorld.h create mode 100755 src/Model.cpp create mode 100755 src/Model.h create mode 100755 src/OBJ.cpp create mode 100755 src/OBJ.h delete mode 100755 src/OpenGL.h create mode 100755 src/PrecompiledHeader.cpp rename src/{GLM.h => PrecompiledHeader.h} (59%) create mode 100755 src/Renderer.cpp create mode 100755 src/Renderer.h create mode 100755 src/ShaderProgram.cpp create mode 100755 src/ShaderProgram.h create mode 100755 src/Shaders/AABB.frag.glsl create mode 100755 src/Shaders/Fragment.glsl create mode 100755 src/Shaders/Normals.frag.glsl create mode 100755 src/Shaders/Normals.geo.glsl create mode 100755 src/Shaders/ShadowMap.frag.glsl create mode 100755 src/Shaders/ShadowMap.vert.glsl create mode 100755 src/Shaders/Skybox.frag.glsl create mode 100755 src/Shaders/Skybox.vert.glsl create mode 100755 src/Shaders/Vertex.glsl create mode 100755 src/Shaders/VisualizeDepth.frag.glsl create mode 100755 src/Shaders/VisualizeDepth.vert.glsl create mode 100755 src/Skybox.cpp create mode 100755 src/Skybox.h create mode 100755 src/System.h create mode 100755 src/Systems/RenderSystem.cpp create mode 100755 src/Systems/RenderSystem.h create mode 100755 src/Systems/TransformSystem.cpp create mode 100755 src/Systems/TransformSystem.h create mode 100755 src/Texture.cpp create mode 100755 src/Texture.h create mode 100755 src/World.cpp create mode 100755 src/World.h diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100755 index 0000000..698a1f1 --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,99 @@ +#include "PrecompiledHeader.h" +#include "Camera.h" + +Camera::Camera(float yFOV, float aspectRatio, float nearClip, float farClip) +{ + m_FOV = yFOV; + m_AspectRatio = aspectRatio; + m_NearClip = nearClip; + m_FarClip = farClip; + + m_Position = glm::vec3(0.0); + /*m_Pitch = 0.f; + m_Yaw = 0.f;*/ + + UpdateProjectionMatrix(); + UpdateViewMatrix(); +} + +//glm::vec3 Camera::Forward() +//{ +// return glm::rotate(glm::vec3(0.f, 0.f, -1.f), -m_Yaw, glm::vec3(0.f, 1.f, 0.f)); +//} +// +//glm::vec3 Camera::Right() +//{ +// return glm::rotate(glm::vec3(1.f, 0.f, 0.f), -m_Yaw, glm::vec3(0.f, 1.f, 0.f)); +//} + +//glm::mat4 Camera::Orientation() +//{ +// glm::mat4 orientation(1.f); +// orientation = glm::rotate(orientation, m_Pitch, glm::vec3(1.f, 0.f, 0.f)); +// orientation = glm::rotate(orientation, m_Yaw, glm::vec3(0.f, 1.f, 0.f)); +// return orientation; +//} + +void Camera::AspectRatio(float val) +{ + m_AspectRatio = val; + UpdateProjectionMatrix(); +} + +void Camera::Position(glm::vec3 val) +{ + m_Position = val; + UpdateViewMatrix(); +} + + +void Camera::Orientation(glm::quat val) +{ + m_Orientation = val; + UpdateViewMatrix(); +} + +//void Camera::Pitch(float val) +//{ +// m_Pitch = val; +// UpdateViewMatrix(); +//} +// +//void Camera::Yaw(float val) +//{ +// m_Yaw = val; +// UpdateViewMatrix(); +//} + +void Camera::UpdateProjectionMatrix() +{ + m_ProjectionMatrix = glm::perspective( + m_FOV, + m_AspectRatio, + m_NearClip, + m_FarClip + ); +} + +void Camera::UpdateViewMatrix() +{ + m_ViewMatrix = glm::translate(glm::toMat4(m_Orientation), -m_Position); +} + +void Camera::FOV(float val) +{ + m_FOV = val; + UpdateProjectionMatrix(); +} + +void Camera::NearClip(float val) +{ + m_NearClip = val; + UpdateProjectionMatrix(); +} + +void Camera::FarClip(float val) +{ + m_FarClip = val; + UpdateProjectionMatrix(); +} \ No newline at end of file diff --git a/src/Camera.h b/src/Camera.h new file mode 100755 index 0000000..2647a54 --- /dev/null +++ b/src/Camera.h @@ -0,0 +1,59 @@ +#ifndef Camera_h__ +#define Camera_h__ + +class Camera +{ +public: + Camera(float yFOV, float aspectRatio, float nearClip, float farClip); + + glm::vec3 Forward(); + glm::vec3 Right(); + + float AspectRatio() const { return m_AspectRatio; } + void AspectRatio(float val); + + glm::vec3 Position() const { return m_Position; } + void Position(glm::vec3 val); + + glm::quat Orientation() const { return m_Orientation; } + void Orientation(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 ProjectionMatrix(glm::mat4 val) { m_ProjectionMatrix = val; } + + glm::mat4 ViewMatrix() const { return m_ViewMatrix; } + void ViewMatrix(glm::mat4 val) { m_ViewMatrix = val; } + + float FOV() const { return m_FOV; } + void FOV(float val); + + float NearClip() const { return m_NearClip; } + void NearClip(float val); + + float FarClip() const { return m_FarClip; } + void FarClip(float val); + +private: + void UpdateProjectionMatrix(); + void UpdateViewMatrix(); + + float m_FOV; + float m_AspectRatio; + float m_NearClip; + float m_FarClip; + + glm::vec3 m_Position; + glm::quat m_Orientation; + //float m_Pitch; + //float m_Yaw; + + glm::mat4 m_ProjectionMatrix; + glm::mat4 m_ViewMatrix; +}; + +#endif // Camera_h__ diff --git a/src/Color.h b/src/Color.h new file mode 100755 index 0000000..015b1bc --- /dev/null +++ b/src/Color.h @@ -0,0 +1,10 @@ +#ifndef Color_h__ +#define Color_h__ + +struct Color +{ + float r; + float g; + float b; +}; +#endif // !Color_h__ diff --git a/src/Component.h b/src/Component.h new file mode 100755 index 0000000..21d59f6 --- /dev/null +++ b/src/Component.h @@ -0,0 +1,14 @@ +#ifndef Component_h__ +#define Component_h__ + +#include "Factory.h" +#include "Entity.h" + +struct Component +{ + EntityID Entity; +}; + +class ComponentFactory : public Factory { }; + +#endif // Component_h__ \ No newline at end of file diff --git a/src/Components/Bounds.h b/src/Components/Bounds.h new file mode 100755 index 0000000..f05c6d8 --- /dev/null +++ b/src/Components/Bounds.h @@ -0,0 +1,17 @@ +#ifndef Components_Bounds_h__ +#define Components_Bounds_h__ + +#include "Component.h" + +namespace Components +{ + +struct Bounds : Component +{ + //Axis Aligned Bounding Box + glm::vec3 Origin; + glm::vec3 VolumeVector; //The vector that defines the volume of the BB, it goes from one corner to the opposite one +}; + +} +#endif // !Components_Bounds_h__ \ No newline at end of file diff --git a/src/Components/Camera.h b/src/Components/Camera.h new file mode 100755 index 0000000..2cd379d --- /dev/null +++ b/src/Components/Camera.h @@ -0,0 +1,19 @@ +#ifndef Components_Camera_h__ +#define Components_Camera_h__ + +#include "Component.h" + +namespace Components +{ + +struct Camera : Component +{ + Camera() : FOV(glm::radians(45.f)), NearClip(0.1f), FarClip(100.f) { } + + float FOV; + float NearClip; + float FarClip; +}; + +} +#endif // !Components_Camera_h__ \ No newline at end of file diff --git a/src/Components/Collision.h b/src/Components/Collision.h new file mode 100755 index 0000000..83450a4 --- /dev/null +++ b/src/Components/Collision.h @@ -0,0 +1,21 @@ +#ifndef Components_Collision_h__ +#define Components_Collision_h__ + +#include "Entity.h" +#include "Component.h" +#include + +namespace Components +{ + +struct Collision : Component +{ + Collision() : Phantom(false), Interested(false) { } + + bool Phantom; + bool Interested; + std::vector CollidingEntities; +}; + +} +#endif // !Components_Collision_h__ \ No newline at end of file diff --git a/src/Components/DirectionalLight.h b/src/Components/DirectionalLight.h new file mode 100755 index 0000000..ee2dd72 --- /dev/null +++ b/src/Components/DirectionalLight.h @@ -0,0 +1,19 @@ +#ifndef Components_DirectionalLight_h__ +#define Components_DirectionalLight_h__ + +#include "Component.h" +#include "Color.h" + +namespace Components +{ + +struct DirectionalLight : Component +{ + float Intensity; + float MaxRange; + float SpecularIntensity; + Color Color; +}; + +} +#endif // !Components_DirectionalLight_h__ \ No newline at end of file diff --git a/src/Components/Input.h b/src/Components/Input.h new file mode 100755 index 0000000..b1c11b5 --- /dev/null +++ b/src/Components/Input.h @@ -0,0 +1,25 @@ +#ifndef Components_Input_h__ +#define Components_Input_h__ + +#include + +#include + +#include "Component.h" + +namespace Components +{ + +struct Input : Component +{ + std::array KeyState; + std::array LastKeyState; + std::array MouseState; + std::array LastMouseState; + float dX, dY; + float WheelDelta; +}; + +} + +#endif // !Components_Input_h__ \ No newline at end of file diff --git a/src/Components/Model.h b/src/Components/Model.h new file mode 100755 index 0000000..ad3b4f3 --- /dev/null +++ b/src/Components/Model.h @@ -0,0 +1,22 @@ +#ifndef Components_Model_h__ +#define Components_Model_h__ + +#include + +#include "Component.h" +#include "Color.h" + +namespace Components +{ + +struct Model : Component +{ + Model() : Visible(true), ShadowCaster(true) { } + std::string ModelFile; + Color Color; + bool Visible; + bool ShadowCaster; +}; + +} +#endif // !Components_Model_h__ \ No newline at end of file diff --git a/src/Components/ParticleEmitter.h b/src/Components/ParticleEmitter.h new file mode 100755 index 0000000..06a1658 --- /dev/null +++ b/src/Components/ParticleEmitter.h @@ -0,0 +1,25 @@ +#ifndef Components_ParticleEmitter_h__ +#define Components_ParticleEmitter_h__ + +#include "Component.h" +#include "Color.h" +#include + +namespace Components +{ + +struct ParticleEmitter : Component +{ + int ParticleTemplate; + float SpawnFrequency; + int SpawnCount; + std::vector ColorSpectrum; + std::vector ScaleSpectrum; + float SpreadAngle; + float LifeTime; + std::vector VelocitySpectrum; + std::vector AngularVelocitySpectrum; +}; + +} +#endif // !Components_ParticleEmitter_h__ \ No newline at end of file diff --git a/src/Components/PointLight.h b/src/Components/PointLight.h new file mode 100755 index 0000000..a7a5d4a --- /dev/null +++ b/src/Components/PointLight.h @@ -0,0 +1,22 @@ +#ifndef Components_PointLight_h__ +#define Components_PointLight_h__ + +#include "Component.h" +#include "Color.h" + +namespace Components +{ + +struct PointLight : Component +{ + float Intensity; + float MaxRange; + glm::vec3 Specular; + glm::vec3 Diffuse; + float constantAttenuation, linearAttenuation, quadraticAttenuation; + float spotExponent; + Color color; +}; + +} +#endif // !Components_PointLight_h__ \ No newline at end of file diff --git a/src/Components/PowerUp.h b/src/Components/PowerUp.h new file mode 100755 index 0000000..fce5d6e --- /dev/null +++ b/src/Components/PowerUp.h @@ -0,0 +1,15 @@ +#ifndef Components_PowerUp_h__ +#define Components_PowerUp_h__ + +#include "Component.h" + +namespace Components +{ + +struct PowerUp : Component +{ + float Speed; +}; + +} +#endif // !Components_PowerUp_h__ \ No newline at end of file diff --git a/src/Components/SoundEmitter.h b/src/Components/SoundEmitter.h new file mode 100755 index 0000000..8e471d5 --- /dev/null +++ b/src/Components/SoundEmitter.h @@ -0,0 +1,22 @@ +#ifndef Components_SoundEmitter_h__ +#define Components_SoundEmitter_h__ + +#include + +#include "Component.h" + +namespace Components +{ + +struct SoundEmitter : Component +{ + float Gain; + float MaxDistance; + float ReferenceDistance; + float Pitch; + bool Loop; + std::string Path; +}; + +} +#endif // !Components_SoundEmitter_h__ \ No newline at end of file diff --git a/src/Components/Sprite.h b/src/Components/Sprite.h new file mode 100755 index 0000000..f54d3d0 --- /dev/null +++ b/src/Components/Sprite.h @@ -0,0 +1,19 @@ +#ifndef Components_Sprite_h__ +#define Components_Sprite_h__ + +#include + +#include "Component.h" +#include "Color.h" + +namespace Components +{ + +struct Sprite : Component +{ + std::string SpriteFile; + Color Color; +}; + +} +#endif // !Components_Sprite_h__ \ No newline at end of file diff --git a/src/Components/Stat.h b/src/Components/Stat.h new file mode 100755 index 0000000..31a3dc3 --- /dev/null +++ b/src/Components/Stat.h @@ -0,0 +1,16 @@ +#ifndef Components_Stat_h__ +#define Components_Stat_h__ + +#include "Component.h" + +namespace Components +{ + +struct Stat : Component +{ + float Health; + bool Destroyable; +}; + +} +#endif // !Components_Stat_h__ \ No newline at end of file diff --git a/src/Components/Template.h b/src/Components/Template.h new file mode 100755 index 0000000..4bcb25c --- /dev/null +++ b/src/Components/Template.h @@ -0,0 +1,12 @@ +#ifndef Components_Template_h__ +#define Components_Template_h__ + +#include "Component.h" + +namespace Components +{ + +struct Template : Component { }; + +} +#endif // !Components_Template_h__ \ No newline at end of file diff --git a/src/Components/Transform.h b/src/Components/Transform.h new file mode 100755 index 0000000..8d0073f --- /dev/null +++ b/src/Components/Transform.h @@ -0,0 +1,22 @@ +#ifndef Components_Transform_h__ +#define Components_Transform_h__ + +#include "Component.h" + +namespace Components +{ + +struct Transform : Component +{ + Transform() + : Scale(glm::vec3(1.f)) { } + + glm::vec3 Position; + glm::quat Orientation; + glm::vec3 Velocity; + glm::vec3 Scale; +}; + +} + +#endif // Components_Transform_h__ diff --git a/src/CubemapTexture.cpp b/src/CubemapTexture.cpp new file mode 100755 index 0000000..fa01e1a --- /dev/null +++ b/src/CubemapTexture.cpp @@ -0,0 +1,59 @@ +#include "PrecompiledHeader.h" +#include "CubemapTexture.h" + +CubemapTexture::CubemapTexture(std::string posXFile, std::string negXFile, std::string posYFile, std::string negYFile, std::string posZFile, std::string negZFile) +{ + m_Loaded = false; + m_Texture = 0; + m_TextureFiles[0] = posXFile; + m_TextureFiles[1] = negXFile; + m_TextureFiles[2] = posYFile; + m_TextureFiles[3] = negYFile; + m_TextureFiles[4] = posZFile; + m_TextureFiles[5] = negZFile; +} + +CubemapTexture::~CubemapTexture() +{ + if (m_Texture != 0) { + //glDeleteTextures(1, &m_Texture); + } +} + +void CubemapTexture::Load() +{ + m_Loaded = true; + + m_Texture = SOIL_load_OGL_cubemap( + m_TextureFiles[0].c_str(), + m_TextureFiles[1].c_str(), + m_TextureFiles[2].c_str(), + m_TextureFiles[3].c_str(), + m_TextureFiles[4].c_str(), + m_TextureFiles[5].c_str(), + SOIL_LOAD_AUTO, + SOIL_CREATE_NEW_ID, + 0); + + if (m_Texture == 0) { + LOG_ERROR("SOIL cubemap loading error: %s", SOIL_last_result()); + return; + } + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); +} + +void CubemapTexture::Bind(GLenum textureUnit) +{ + if (!m_Loaded) { + LOG_WARNING("Cubemap \"%s\" was not loaded before being bound! Attempting to load now...", m_TextureFiles[0].c_str()); + Load(); + } + + glActiveTexture(textureUnit); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_Texture); +} \ No newline at end of file diff --git a/src/CubemapTexture.h b/src/CubemapTexture.h new file mode 100755 index 0000000..6f1c5fd --- /dev/null +++ b/src/CubemapTexture.h @@ -0,0 +1,27 @@ +#ifndef CubemapTexture_h__ +#define CubemapTexture_h__ + +#include + +class CubemapTexture +{ +public: + CubemapTexture( + std::string posXFile, + std::string negXFile, + std::string posYFile, + std::string negYFile, + std::string posZFile, + std::string negZFile); + ~CubemapTexture(); + + void Load(); + void Bind(GLenum textureSlot); + +private: + bool m_Loaded; + GLuint m_Texture; + std::string m_TextureFiles[6]; +}; + +#endif // CubemapTexture_h__ \ No newline at end of file diff --git a/src/Engine.h b/src/Engine.h new file mode 100755 index 0000000..4093d20 --- /dev/null +++ b/src/Engine.h @@ -0,0 +1,41 @@ +#include +#include + +#include "Renderer.h" +#include "GameWorld.h" + +class Engine +{ +public: + Engine(int argc, char* argv[]) + { + m_Renderer = std::make_shared(); + m_Renderer->Initialize(); + + m_World = std::make_shared(m_Renderer); + m_World->Initialize(); + + m_LastTime = glfwGetTime(); + } + + bool Running() const { return !glfwWindowShouldClose(m_Renderer->GetWindow()); } + + void Tick() + { + double currentTime = glfwGetTime(); + double dt = currentTime - m_LastTime; + m_LastTime = currentTime; + + m_World->Update(dt); + m_Renderer->Draw(dt); + + glfwPollEvents(); + } + +private: + std::shared_ptr m_Renderer; + // TODO: This should ultimately live in GameFrame + std::shared_ptr m_World; + + double m_LastTime; +}; \ No newline at end of file diff --git a/src/Entity.h b/src/Entity.h new file mode 100755 index 0000000..11e425f --- /dev/null +++ b/src/Entity.h @@ -0,0 +1 @@ +typedef unsigned int EntityID; \ No newline at end of file diff --git a/src/Factory.h b/src/Factory.h new file mode 100755 index 0000000..01429bd --- /dev/null +++ b/src/Factory.h @@ -0,0 +1,32 @@ +#ifndef ComponentFactory_h__ +#define ComponentFactory_h__ + +#include +#include +#include +#include + +template +class Factory +{ +public: + void Register(std::string name, std::function factoryFunction) + { + m_FactoryFunctions[name] = factoryFunction; + } + + T Create(std::string name) + { + auto it = m_FactoryFunctions.find(name); + if (it != m_FactoryFunctions.end()) { + return it->second(); + } else { + return nullptr; + } + } + +private: + std::map> m_FactoryFunctions; +}; + +#endif // ComponentFactory_h__ \ No newline at end of file diff --git a/src/GameWorld.cpp b/src/GameWorld.cpp new file mode 100755 index 0000000..3cdeb55 --- /dev/null +++ b/src/GameWorld.cpp @@ -0,0 +1,58 @@ +#include "PrecompiledHeader.h" +#include "GameWorld.h" + +void GameWorld::Initialize() +{ + World::Initialize(); + + auto terrain = CreateEntity(); + auto transform = AddComponent(terrain, "Transform"); + transform->Scale = glm::vec3(.0005f); + auto model = AddComponent(terrain, "Model"); + model->ModelFile = "Models/terrain/terrain.obj"; +} + +void GameWorld::Update(double dt) +{ + World::Update(dt); +} + +void GameWorld::RegisterComponents() +{ + m_ComponentFactory.Register("Bounds", []() { return new Components::Bounds(); }); + m_ComponentFactory.Register("Camera", []() { return new Components::Camera(); }); + m_ComponentFactory.Register("Collision", []() { return new Components::Collision(); }); + m_ComponentFactory.Register("DirectionalLight", []() { return new Components::DirectionalLight(); }); + m_ComponentFactory.Register("Input", []() { return new Components::Input(); }); + m_ComponentFactory.Register("Model", []() { return new Components::Model(); }); + m_ComponentFactory.Register("ParticleEmitter", []() { return new Components::ParticleEmitter(); }); + m_ComponentFactory.Register("PointLight", []() { return new Components::PointLight(); }); + m_ComponentFactory.Register("SoundEmitter", []() { return new Components::SoundEmitter(); }); + m_ComponentFactory.Register("Sprite", []() { return new Components::Sprite(); }); + m_ComponentFactory.Register("Template", []() { return new Components::Template(); }); + m_ComponentFactory.Register("Transform", []() { return new Components::Transform(); }); +} + +void GameWorld::RegisterSystems() +{ + //m_SystemFactory.Register("LevelGenerationSystem", [this]() { return new Systems::LevelGenerationSystem(this); }); + //m_SystemFactory.Register("InputSystem", [this]() { return new Systems::InputSystem(this, m_Renderer); }); + //m_SystemFactory.Register("CollisionSystem", [this]() { return new Systems::CollisionSystem(this); }); + ////m_SystemFactory.Register("ParticleSystem", [this]() { return new Systems::ParticleSystem(this); }); + //m_SystemFactory.Register("PlayerSystem", [this]() { return new Systems::PlayerSystem(this); }); + //m_SystemFactory.Register("SoundSystem", [this]() { return new Systems::SoundSystem(this); }); + m_SystemFactory.Register("TransformSystem", [this]() { return new Systems::TransformSystem(this); }); + m_SystemFactory.Register("RenderSystem", [this]() { return new Systems::RenderSystem(this, m_Renderer); }); +} + +void GameWorld::AddSystems() +{ + AddSystem("TransformSystem"); + //AddSystem("LevelGenerationSystem"); + //AddSystem("InputSystem"); + //AddSystem("CollisionSystem"); + ////AddSystem("ParticleSystem"); + //AddSystem("PlayerSystem"); + //AddSystem("SoundSystem"); + AddSystem("RenderSystem"); +} \ No newline at end of file diff --git a/src/GameWorld.h b/src/GameWorld.h new file mode 100755 index 0000000..eb33fcc --- /dev/null +++ b/src/GameWorld.h @@ -0,0 +1,49 @@ +#ifndef GameWorld_h__ +#define GameWorld_h__ + +#include "World.h" +#include "Renderer.h" + +//#include "Systems/TransformSystem.h" +//#include "Systems/CollisionSystem.h" +//#include "Systems/InputSystem.h" +//#include "Systems/LevelGenerationSystem.h" +//#include "Systems/ParticleSystem.h" +//#include "Systems/PlayerSystem.h" +#include "Systems/RenderSystem.h" +//#include "Systems/SoundSystem.h" + +#include "Components/Bounds.h" +#include "Components/Camera.h" +#include "Components/Collision.h" +#include "Components/DirectionalLight.h" +#include "Components/Input.h" +#include "Components/Model.h" +#include "Components/ParticleEmitter.h" +#include "Components/PointLight.h" +#include "Components/PowerUp.h" +#include "Components/SoundEmitter.h" +#include "Components/Sprite.h" +#include "Components/Stat.h" +#include "Components/Template.h" +#include "Components/Transform.h" + +class GameWorld : public World +{ +public: + GameWorld(std::shared_ptr renderer) + : m_Renderer(renderer), World() { } + + void Initialize(); + + void RegisterSystems() override; + void AddSystems() override; + void RegisterComponents() override; + + void Update(double dt); + +private: + std::shared_ptr m_Renderer; +}; + +#endif // GameWorld_h__ diff --git a/src/Model.cpp b/src/Model.cpp new file mode 100755 index 0000000..bc87c90 --- /dev/null +++ b/src/Model.cpp @@ -0,0 +1,251 @@ +#include "PrecompiledHeader.h" +#include "Model.h" + +Model::Model(const char* path) +{ + Loadobj(path, Vertices, Normals, TextureCoords); + CreateBuffers(Vertices, Normals, TextureCoords); +} + +Model::Model(OBJ &obj) +{ + OBJ::MaterialInfo* currentMaterial = nullptr; + TextureGroup* currentTexGroup = nullptr; + int index = 0; + for (auto face : obj.Faces) { + if (face.Material == nullptr) { + LOG_ERROR("Missing material for .obj file \"%s\"", obj.Path().string().c_str()); + return; + } + // New material + if (face.Material != currentMaterial) { + currentMaterial = face.Material; + // Load texture + std::shared_ptr texture = std::make_shared(currentMaterial->TextureFile); + // TODO: Load material parameters + // Create new texture group (start index of new group is upcoming index) + TextureGroup texGroup = { texture, index, index }; + TextureGroups.push_back(texGroup); + currentTexGroup = &TextureGroups.back(); + } + + // Face definitions + for (auto faceDef : face.Definitions) { + glm::vec3 vertex; + std::tie(vertex.x, vertex.y, vertex.z) = obj.Vertices.at(faceDef.VertexIndex - 1); + Vertices.push_back(vertex); + + if (faceDef.NormalIndex != 0) { + glm::vec3 normal; + std::tie(normal.x, normal.y, normal.z) = obj.Normals.at(faceDef.NormalIndex - 1); + Normals.push_back(normal); + } + + if (faceDef.TextureCoordIndex != 0) { + glm::vec2 texCoord; + // TODO: W-coord? + std::tie(texCoord.x, texCoord.y, std::ignore) = obj.TextureCoords.at(faceDef.TextureCoordIndex - 1); + TextureCoords.push_back(texCoord); + } + + currentTexGroup->EndIndex = index; + index++; + } + } + + if (Vertices.size() > 0) { + CreateBuffers(Vertices, Normals, TextureCoords); + } +} + +bool Model::Loadobj(const char* path, std::vector & out_vertices, std::vector &out_normals, std::vector & out_TextureCoords) +{ + std::vector< unsigned int > vertexIndices, TextureCoordIndices, normalIndices; + std::vector< glm::vec3 > temp_vertices; + std::vector< glm::vec2 > temp_TextureCoords; + std::vector< glm::vec3 > temp_normals; + + FILE * file = fopen(path, "r"); + LOG_INFO("Loading .obj file"); + if( file == NULL ) + { + LOG_INFO("Load .obj file: failed"); + return false; + } + char lineHeader[512]; + + while(true) + { + + //read the first word of the line + int res = fscanf(file, "%s", lineHeader); + + if( res == EOF ) // EOF - End Of File + { + for( unsigned int i = 0; i < vertexIndices.size(); i++ ) + { + unsigned int vertexIndex = vertexIndices[i]; + glm::vec3 vertex = temp_vertices[ vertexIndex-1]; + out_vertices.push_back(vertex); + + } + + for( unsigned int i = 0; i < TextureCoordIndices.size(); i++ ) + { + unsigned int TextureCoordIndex = TextureCoordIndices[i]; + glm::vec2 TextureCoord = temp_TextureCoords[ TextureCoordIndex-1]; + out_TextureCoords.push_back(TextureCoord); + } + + for( unsigned int i = 0; i < normalIndices.size(); i++ ) + { + unsigned int normalIndex = normalIndices[i]; + glm::vec3 normal = temp_normals[ normalIndex-1]; + out_normals.push_back(normal); + } + + + LOG_INFO("Model Loaded\n"); + break; + } + + if( strcmp( lineHeader, "v" ) == 0 ) // vertex + { + glm::vec3 vertex; + fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z); + temp_vertices.push_back(vertex); + } + else if ( strcmp( lineHeader, "vt" ) == 0 ) // texture coordinate + { + glm::vec2 TextureCoord; + fscanf(file, "%f %f\n", &TextureCoord.x, &TextureCoord.y ); + temp_TextureCoords.push_back(TextureCoord); + } + else if( strcmp( lineHeader, "vn" ) == 0 ) // normal + { + glm::vec3 normal; + fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z ); + temp_normals.push_back(normal); + } + else if( strcmp( lineHeader, "f" ) == 0) + { + unsigned int vertexIndex[3], TextureCoordIndex[3], normalIndex[3]; + int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &TextureCoordIndex[0], &normalIndex[0], &vertexIndex[1], &TextureCoordIndex[1], &normalIndex[1],&vertexIndex[2], &TextureCoordIndex[2], &normalIndex[2]); + if(matches != 9) + { + printf("File can't be read, try exporting with other options\n"); + return false; + } + vertexIndices.push_back(vertexIndex[0]); + vertexIndices.push_back(vertexIndex[1]); + vertexIndices.push_back(vertexIndex[2]); + TextureCoordIndices.push_back(TextureCoordIndex[0]); + TextureCoordIndices.push_back(TextureCoordIndex[1]); + TextureCoordIndices.push_back(TextureCoordIndex[2]); + normalIndices.push_back(normalIndex[0]); + normalIndices.push_back(normalIndex[1]); + normalIndices.push_back(normalIndex[2]); + + } + else if ( strcmp( lineHeader, "mtllib" ) == 0 ) + { + + char fileName[512]; + fscanf(file, "%s\n", &fileName); + + + FILE * mtlfile = fopen(fileName, "r"); + LOG_INFO("Loading .mtl file"); + if( mtlfile == NULL ) + { + LOG_INFO("Load .mtl file: failed"); + return false; + } + + char mtllineHeader[512]; + //read the first word of the line + + while (true) + { + int mtlres = fscanf(mtlfile, "%s", mtllineHeader); + + if( mtlres == EOF ) // EOF - End Of File + { + + break; + } + else if ( strcmp( mtllineHeader, "map_Kd" ) == 0 ) + { + char textureFileName[512]; + fscanf(mtlfile, "%s", textureFileName); + texture.push_back(std::make_shared(textureFileName)); + LOG_INFO("Texture Loaded\n"); + } + } + + + + } + } + return true; + +} + + +void Model::CreateBuffers( std::vector vertices, std::vector normals, std::vectortextureCoords) +{ + + LOG_INFO("Generating VertexBuffer"); + glGenBuffers(1, &VertexBuffer); + if (vertices.size() > 0) { + glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); + glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW); + GLERROR("GLEW: BufferFail, VertexBuffer"); + } else { + LOG_WARNING("Created empty vertex buffer!"); + } + + LOG_INFO("Generating NormalBuffer"); + glGenBuffers(1, &NormalBuffer); + if (normals.size() > 0) { + glBindBuffer(GL_ARRAY_BUFFER, NormalBuffer); + glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW); + GLERROR("GLEW: BufferFail, NormalBuffer"); + } else { + LOG_WARNING("Created empty normal buffer!"); + } + + + LOG_INFO("Generating textureCoordBuffer"); + glGenBuffers(1, &TextureCoordBuffer); + if (textureCoords.size() > 0) { + glBindBuffer(GL_ARRAY_BUFFER, TextureCoordBuffer); + glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), &textureCoords[0], GL_STATIC_DRAW); + GLERROR("GLEW: BufferFail, TextureCoordBuffer"); + } else { + LOG_WARNING("Created empty texture coordinate buffer!"); + } + + glGenVertexArrays(1, &VAO); + glBindVertexArray(VAO); + GLERROR("GLEW: BufferFail4"); + + glBindBuffer(GL_ARRAY_BUFFER, VertexBuffer); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + GLERROR("GLEW: BufferFail5"); + + glBindBuffer(GL_ARRAY_BUFFER, NormalBuffer); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0); + GLERROR("GLEW: BufferFail5"); + + glBindBuffer(GL_ARRAY_BUFFER, TextureCoordBuffer); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); + GLERROR("GLEW: BufferFail5"); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + GLERROR("GLEW: BufferFail5"); +} + + diff --git a/src/Model.h b/src/Model.h new file mode 100755 index 0000000..86e7f4d --- /dev/null +++ b/src/Model.h @@ -0,0 +1,59 @@ +#ifndef Model_h__ +#define Model_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Texture.h" +#include "OBJ.h" + +class Model +{ +public: + Model(OBJ &obj); + Model(const char* path); + + struct TextureGroup + { + std::shared_ptr Texture; + unsigned int StartIndex; + unsigned int EndIndex; + }; + + GLuint VAO; + std::vector TextureGroups; + + std::vector> texture; + glm::mat4 GetMatrix(); + std::vector Vertices; + +private: + + std::vector Normals; + std::vector TextureCoords; + + GLuint VertexBuffer; + GLuint NormalBuffer; + GLuint TextureCoordBuffer; + + bool Loadobj( + const char* path, + std::vector & out_vertices, + std::vector &out_normals, + std::vector & out_TextureCoords + ); + + void CreateBuffers( + std::vector _Vertices, + std::vector _Normals, + std::vector_TextureCoords + ); + +}; +#endif // Model_h__ \ No newline at end of file diff --git a/src/OBJ.cpp b/src/OBJ.cpp new file mode 100755 index 0000000..1c19c18 --- /dev/null +++ b/src/OBJ.cpp @@ -0,0 +1,228 @@ +#include "PrecompiledHeader.h" +#include "OBJ.h" + +bool OBJ::LoadFromFile(std::string filename) +{ + m_Path = boost::filesystem::path(filename); + + // http://paulbourke.net/dataformats/obj/ + std::ifstream file(m_Path.string()); + if (!file.is_open()) { + LOG_ERROR("Failed to open .obj \"%s\"", m_Path.string().c_str()); + return false; + } + + LOG_INFO("Parsing .obj \"%s\"", m_Path.string().c_str()); + + std::string line; + while (std::getline(file, line)) { + if (line.length() == 0) + continue; + + std::stringstream ss(line); + + std::string prefix; + ss >> prefix; + + // Ignore comments + if (prefix == "#") + continue; + + // Material files + if (prefix == "mtllib") { + std::string materialFilename; + ss >> materialFilename; + m_MaterialPath = m_Path.branch_path() / materialFilename; + ParseMaterial(); + continue; + } + + // Material statement + if (prefix == "usemtl") { + std::string material; + ss >> material; + m_CurrentMaterial = &Materials[material]; + continue; + } + + // Vertices + if (prefix == "v") { + float x, y, z; + ss >> x >> y >> z; + Vertices.push_back(std::make_tuple(x, y, z)); + continue; + } + + // Normals + if (prefix == "vn") { + float x, y, z; + ss >> x >> y >> z; + Normals.push_back(std::make_tuple(x, y, z)); + } + + // Texture coordinates + if (prefix == "vt") { + float u, v, w; + ss >> u >> v >> w; + TextureCoords.push_back(std::make_tuple(u, v, w)); + } + + // Face definitions + if (prefix == "f") { + Face face; + face.Material = m_CurrentMaterial; + + std::string faceDefString; + while (ss >> faceDefString) { + std::stringstream ss2(faceDefString); + FaceDefinition faceDef = { 0, 0, 0 }; + + ss2 >> faceDef.VertexIndex; + ss2.ignore(); // Ignore first delimiter + if (!ss2) + continue; + + if (ss2.peek() == '/') { + ss2.ignore(); + ss2 >> faceDef.NormalIndex; + } else { + ss2 >> faceDef.TextureCoordIndex; + ss2.ignore(); + ss2 >> faceDef.NormalIndex; + } + face.Definitions.push_back(faceDef); + } + Faces.push_back(face); + } + } + + return true; +} + +void OBJ::ParseMaterial() +{ + // http://paulbourke.net/dataformats/mtl/ + std::ifstream file(m_MaterialPath.string()); + if (!file.is_open()) { + LOG_ERROR("Failed to open .mtl \"%s\"", m_MaterialPath.string().c_str()); + return; + } + + LOG_INFO("Parsing .mtl \"%s\"", m_MaterialPath.string().c_str()); + + std::string currentMaterialName; + MaterialInfo* currentMaterial = nullptr; + + std::string line; + while (std::getline(file, line)) { + if (line.length() == 0) + continue; + + std::stringstream ss(line); + + std::string prefix; + ss >> prefix; + + // Create a new material definition + if (prefix == "newmtl") { + MaterialInfo mat = + { + "", + std::make_tuple(0.2f, 0.2f, 0.2f), + std::make_tuple(0.8f, 0.8f, 0.8f), + std::make_tuple(1.0f, 1.0f, 1.0f), + std::make_tuple(1.0f, 1.0f, 1.0f), + 1.0f, + 1.0f, + 0.0f, + 0, + }; + + ss >> currentMaterialName; + LOG_INFO("Parsing material %s", currentMaterialName.c_str()); + Materials[currentMaterialName] = mat; + currentMaterial = &Materials[currentMaterialName]; + continue; + } + + if (!currentMaterial) + continue; + + // Ambient color + if (prefix == "Ka") { + float r, g, b; + ss >> r >> g >> b; + currentMaterial->AmbientColor = std::make_tuple(r, g, b); + continue; + } + // Diffuse color + if (prefix == "Kd") { + float r, g, b; + ss >> r >> g >> b; + currentMaterial->DiffuseColor = std::make_tuple(r, g, b); + continue; + } + // Specular color + if (prefix == "Ks") { + float r, g, b; + ss >> r >> g >> b; + currentMaterial->SpecularColor = std::make_tuple(r, g, b); + continue; + } + // Transmission filter + if (prefix == "Tf") { + std::stringstream ss2; + ss2 << ss.str(); + + std::string command; + ss2 >> command; + if (command == "xyz") { + // TODO: "The "Ks xyz" statement specifies the specular reflectivity using CIEXYZ values." + } + else if (command == "spectral") { + // TODO: "The "Tf spectral" statement specifies the transmission filter using a spectral curve." + } else { + float r, g, b; + ss >> r; + // G and B are optional + if (!(ss >> g >> b)) + { + g = r; + b = r; + } + currentMaterial->TransmissionFilter = std::make_tuple(r, g, b); + } + continue; + } + // Optical density + if (prefix == "Ni") { + ss >> currentMaterial->OpticalDensity; + continue; + } + // Alpha + if (prefix == "d" || prefix == "Tr") { + ss >> currentMaterial->Alpha; + continue; + } + // Shininess + if (prefix == "Ns") { + ss >> currentMaterial->Shininess; + continue; + } + // Illumination model + if (prefix == "illum") { + int illum = 0; + ss >> illum; + currentMaterial->IlluminationModel = illum; + continue; + } + // Texture file + // TODO: + if (prefix == "map_Ka" || prefix == "map_Kd") { + std::string textureFile; + ss >> textureFile; + currentMaterial->TextureFile = (m_MaterialPath.branch_path() / textureFile).string(); + continue; + } + } +} diff --git a/src/OBJ.h b/src/OBJ.h new file mode 100755 index 0000000..62bce8d --- /dev/null +++ b/src/OBJ.h @@ -0,0 +1,64 @@ +#ifndef OBJ_h__ +#define OBJ_h__ + +#include +#include +#include +#include +#include +#include +#include + +#include + +class OBJ +{ +public: + struct MaterialInfo + { + std::string TextureFile; + std::tuple AmbientColor; + std::tuple DiffuseColor; + std::tuple SpecularColor; + std::tuple TransmissionFilter; + float OpticalDensity; + float Alpha; + float Shininess; + int IlluminationModel; + }; + + struct FaceDefinition + { + int VertexIndex; + int TextureCoordIndex; + int NormalIndex; + }; + + struct Face + { + Face() : Material(nullptr) { } + std::vector Definitions; + MaterialInfo* Material; + }; + + OBJ() : m_CurrentMaterial(nullptr) { } + OBJ(std::string filename) : m_CurrentMaterial(nullptr) { LoadFromFile(filename); } + + std::vector> Vertices; + std::vector> Normals; + std::vector> TextureCoords; + std::vector Faces; + std::map Materials; + + bool LoadFromFile(std::string filename); + boost::filesystem::path Path() const { return m_Path; } + +private: + boost::filesystem::path m_Path; + boost::filesystem::path m_MaterialPath; + MaterialInfo* m_CurrentMaterial; + + void ParseMaterial(); +}; + +#endif // OBJ_h__ \ No newline at end of file diff --git a/src/OpenGL.h b/src/OpenGL.h deleted file mode 100755 index 2e34a34..0000000 --- a/src/OpenGL.h +++ /dev/null @@ -1,4 +0,0 @@ -#include -#define GLFW_INCLUDE_GLU -#include -#include \ No newline at end of file diff --git a/src/PrecompiledHeader.cpp b/src/PrecompiledHeader.cpp new file mode 100755 index 0000000..f07790a --- /dev/null +++ b/src/PrecompiledHeader.cpp @@ -0,0 +1 @@ +#include "PrecompiledHeader.h" \ No newline at end of file diff --git a/src/GLM.h b/src/PrecompiledHeader.h similarity index 59% rename from src/GLM.h rename to src/PrecompiledHeader.h index db5bcc1..3430978 100755 --- a/src/GLM.h +++ b/src/PrecompiledHeader.h @@ -1,3 +1,16 @@ +#include +#include + +#include "Util/Logging.h" + +// OpenGL +#include +#define GLFW_INCLUDE_GLU +#include +#include +#include "Util/GLError.h" + +// GLM #define GLM_FORCE_RADIANS #include #include diff --git a/src/Renderer.cpp b/src/Renderer.cpp new file mode 100755 index 0000000..4d952c4 --- /dev/null +++ b/src/Renderer.cpp @@ -0,0 +1,533 @@ +#include "PrecompiledHeader.h" +#include "Renderer.h" + +Renderer::Renderer() +{ + m_VSync = false; +#ifdef DEBUG + m_DrawNormals = false; + m_DrawWireframe = false; + m_DrawBounds = true; +#else + m_DrawNormals = false; + m_DrawWireframe = false; + m_DrawBounds = false; +#endif + + m_ShadowMapRes = 2048*8; + m_SunPosition = glm::vec3(0, 1.5f, 10); + m_SunTarget = glm::vec3(0, 0, 0); + m_SunProjection = glm::ortho(-200, 200, -100, 400, -800, 600); + Lights = 0; +} + +void Renderer::Initialize() +{ + // Initialize GLFW + if (!glfwInit()) { + LOG_ERROR("GLFW: Initialization failed"); + exit(EXIT_FAILURE); + } + + // Create a window + WIDTH = 1920; + HEIGHT = 1080; + glfwWindowHint(GLFW_SAMPLES, 16); + m_Window = glfwCreateWindow(WIDTH, HEIGHT, "OpenGL", nullptr, nullptr); + if (!m_Window) { + LOG_ERROR("GLFW: Failed to create window"); + exit(EXIT_FAILURE); + } + glfwMakeContextCurrent(m_Window); + + // GL version info + glGetIntegerv(GL_MAJOR_VERSION, &m_glVersion[0]); + glGetIntegerv(GL_MINOR_VERSION, &m_glVersion[1]); + m_glVendor = (GLchar*)glGetString(GL_VENDOR); + std::stringstream ss; + ss << m_glVendor << " OpenGL " << m_glVersion[0] << "." << m_glVersion[1]; +#ifdef DEBUG + ss << " DEBUG"; +#endif + LOG_INFO(ss.str().c_str()); + glfwSetWindowTitle(m_Window, ss.str().c_str()); + + // Initialize GLEW + if (glewInit() != GLEW_OK) { + LOG_ERROR("GLEW: Initialization failed"); + exit(EXIT_FAILURE); + } + + // Create Camera + m_Camera = std::make_shared(45.f, (float)WIDTH / HEIGHT, 0.01f, 1000.f); + m_Camera->Position(glm::vec3(0.0f, 0.0f, 2.f)); + + glfwSwapInterval(m_VSync); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glEnable(GL_DEPTH_TEST); + + LoadContent(); +} + +void Renderer::LoadContent() +{ + auto standardVS = std::shared_ptr(new VertexShader("Shaders/Vertex.glsl")); + auto standardFS = std::shared_ptr(new FragmentShader("Shaders/Fragment.glsl")); + + m_ShaderProgram.AddShader(standardVS); + m_ShaderProgram.AddShader(standardFS); + m_ShaderProgram.Compile(); + m_ShaderProgram.Link(); + + m_ShaderProgramNormals.AddShader(std::shared_ptr(new GeometryShader("Shaders/Normals.geo.glsl"))); + m_ShaderProgramNormals.AddShader(standardVS); + m_ShaderProgramNormals.AddShader(std::shared_ptr(new FragmentShader("Shaders/Normals.frag.glsl"))); + m_ShaderProgramNormals.Compile(); + m_ShaderProgramNormals.Link(); + + m_ShaderProgramShadows.AddShader(std::shared_ptr(new VertexShader("Shaders/ShadowMap.vert.glsl"))); + m_ShaderProgramShadows.AddShader(std::shared_ptr(new FragmentShader("Shaders/ShadowMap.frag.glsl"))); + m_ShaderProgramShadows.Compile(); + m_ShaderProgramShadows.Link(); + + m_ShaderProgramShadowsDrawDepth.AddShader(std::shared_ptr(new VertexShader("Shaders/VisualizeDepth.vert.glsl"))); + m_ShaderProgramShadowsDrawDepth.AddShader(std::shared_ptr(new FragmentShader("Shaders/VisualizeDepth.frag.glsl"))); + m_ShaderProgramShadowsDrawDepth.Compile(); + m_ShaderProgramShadowsDrawDepth.Link(); + + m_ShaderProgramDebugAABB.AddShader(standardVS); + m_ShaderProgramDebugAABB.AddShader(std::shared_ptr(new FragmentShader("Shaders/AABB.frag.glsl"))); + m_ShaderProgramDebugAABB.Compile(); + m_ShaderProgramDebugAABB.Link(); + + m_ShaderProgramSkybox.AddShader(std::shared_ptr(new VertexShader("Shaders/Skybox.vert.glsl"))); + m_ShaderProgramSkybox.AddShader(std::shared_ptr(new FragmentShader("Shaders/Skybox.frag.glsl"))); + m_ShaderProgramSkybox.Compile(); + m_ShaderProgramSkybox.Link(); + + m_Skybox = std::make_shared("Textures/Skybox/Sunset", "jpg"); + + m_DebugAABB = CreateAABB(); + m_ScreenQuad = CreateQuad(); + CreateShadowMap(m_ShadowMapRes); +} + +void Renderer::CreateShadowMap(int resolution) +{ + glGenFramebuffers(1, &m_ShadowFrameBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_ShadowFrameBuffer); + + // Depth texture + glGenTextures(1, &m_ShadowDepthTexture); + glBindTexture(GL_TEXTURE_2D, m_ShadowDepthTexture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, resolution, resolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + //glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE ); + //glTexParameteri( GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY ); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_ShadowDepthTexture, 0); + glDrawBuffer(GL_NONE); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG_ERROR("Framebuffer incomplete!"); + return; + } +} +void Renderer::Draw(double dt) +{ + glDisable(GL_BLEND); + + DrawSkybox(); + DrawShadowMap(); + DrawScene(); + +#ifdef DEBUG + // Draw bounding boxes + if (m_DrawBounds) { + glEnable(GL_BLEND); + glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO); + m_ShaderProgramDebugAABB.Bind(); + for (auto tuple : AABBsToRender) { + glm::mat4 modelMatrix; + bool colliding; + std::tie(modelMatrix, colliding) = tuple; + // Model matrix + glm::mat4 cameraMatrix = m_Camera->ProjectionMatrix() * m_Camera->ViewMatrix(); + glm::mat4 MVP = cameraMatrix * modelMatrix; + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgramDebugAABB.GetHandle(), "MVP"), 1, GL_FALSE, glm::value_ptr(MVP)); + // Color + glm::vec4 color(1.f, 1.f, 1.f, 0.f); + if (colliding) + color = glm::vec4(1.f, 0.f, 0.f, 0.f); + glUniform4fv(glGetUniformLocation(m_ShaderProgramDebugAABB.GetHandle(), "Color"), 1, glm::value_ptr(color)); + glBindVertexArray(m_DebugAABB); + glDrawArrays(GL_LINES, 0, 24); + } + } + + //DrawDebugShadowMap(); +#endif + + ClearStuff(); + glfwSwapBuffers(m_Window); +} + +void Renderer::DrawSkybox() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, WIDTH, HEIGHT); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_ShaderProgramSkybox.Bind(); + glm::mat4 cameraMatrix = m_Camera->ProjectionMatrix() * glm::toMat4(m_Camera->Orientation()); + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgramSkybox.GetHandle(), "MVP"), 1, GL_FALSE, glm::value_ptr(cameraMatrix)); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + m_Skybox->Draw(); +} + +void Renderer::DrawScene() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, WIDTH, HEIGHT); + + glClear(GL_DEPTH_BUFFER_BIT); + //glClearColor(1.0f, 1.0f, 0.0f, 1.0f); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); +#ifdef DEBUG + glDisable(GL_CULL_FACE); + glPolygonMode(GL_BACK, GL_LINE); +#endif + + // Draw models + glm::mat4 depthViewMatrix = glm::lookAt(m_SunPosition, m_SunTarget, glm::vec3(0, 1, 0)) * glm::translate(-m_Camera->Position() * glm::vec3(1, 0, 0)); + glm::mat4 depthCamera = m_SunProjection * depthViewMatrix; + glm::mat4 biasMatrix( + 0.5, 0.0, 0.0, 0.0, + 0.0, 0.5, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.5, 0.5, 0.5, 1.0 + ); + + m_ShaderProgram.Bind(); + glUniform1i(glGetUniformLocation(m_ShaderProgram.GetHandle(), "numberOfLights"), Lights); + glUniform3fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "position"), Lights, Light_position.data()); + glUniform3fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "specular"), Lights, Light_specular.data()); + glUniform3fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "diffuse"), Lights, Light_diffuse.data()); + glUniform1fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "constantAttenuation"), Lights, Light_constantAttenuation.data()); + glUniform1fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "linearAttenuation"), Lights, Light_linearAttenuation.data()); + glUniform1fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "quadraticAttenuation"), Lights, Light_quadraticAttenuation.data()); + glUniform1fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "spotExponent"), Lights, Light_spotExponent.data()); + if (m_DrawWireframe) { + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + } + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, m_ShadowDepthTexture); + //DrawModels(m_ShaderProgram); + glm::mat4 cameraMatrix = m_Camera->ProjectionMatrix() * m_Camera->ViewMatrix(); + glm::mat4 depthCameraMatrix = biasMatrix * depthCamera; + glm::mat4 MVP; + glm::mat4 depthMVP; + for (auto tuple : ModelsToRender) + { + Model* model; + glm::mat4 modelMatrix; + bool visible; + std::tie(model, modelMatrix, visible, std::ignore) = tuple; + if (!visible) + continue; + + MVP = cameraMatrix * modelMatrix; + depthMVP = depthCameraMatrix * modelMatrix; + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "MVP"), 1, GL_FALSE, glm::value_ptr(MVP)); + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "DepthMVP"), 1, GL_FALSE, glm::value_ptr(depthMVP)); + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix)); + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgram.GetHandle(), "view"), 1, GL_FALSE, glm::value_ptr(m_Camera->ViewMatrix())); + glBindVertexArray(model->VAO); + for (auto texGroup : model->TextureGroups) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texGroup.Texture->texture); + glDrawArrays(GL_TRIANGLES, texGroup.StartIndex, texGroup.EndIndex - texGroup.StartIndex + 1); + } + } + +#ifdef DEBUG + // Debug draw model normals + if (m_DrawNormals) { + m_ShaderProgramNormals.Bind(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + DrawModels(m_ShaderProgramNormals); + } +#endif +} + +void Renderer::DrawShadowMap() +{ + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + glBindFramebuffer(GL_FRAMEBUFFER, m_ShadowFrameBuffer); + glViewport(0, 0, m_ShadowMapRes, m_ShadowMapRes); + + glClear(GL_DEPTH_BUFFER_BIT); + //glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + glm::mat4 depthViewMatrix = glm::lookAt(m_SunPosition, m_SunTarget, glm::vec3(0, 1, 0)) * glm::translate(-m_Camera->Position() * glm::vec3(1, 0, 0)); +// glm::mat4 depthViewMatrix = glm::lookAt(m_SunPosition, m_SunTarget, glm::vec3(0, 1, 0)); + glm::mat4 depthCamera = m_SunProjection * depthViewMatrix; + + //glm::mat4 cameraMatrix = depthProjectionMatrix * m_Camera->ViewMatrix(); + + glm::mat4 MVP; + + m_ShaderProgramShadows.Bind(); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + for (auto tuple : ModelsToRender) + { + Model* model; + glm::mat4 modelMatrix; + bool shadow; + std::tie(model, modelMatrix, std::ignore, shadow) = tuple; + if (!shadow) + continue; + + MVP = depthCamera * modelMatrix; + glUniformMatrix4fv(glGetUniformLocation(m_ShaderProgramShadows.GetHandle(), "MVP"), 1, GL_FALSE, glm::value_ptr(MVP)); + + glBindVertexArray(model->VAO); + for (auto texGroup : model->TextureGroups) { + glDrawArrays(GL_TRIANGLES, texGroup.StartIndex, texGroup.EndIndex - texGroup.StartIndex + 1); + } + } +} + +void Renderer::DrawDebugShadowMap() +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, 400, 400); + + glClear(GL_DEPTH_BUFFER_BIT); + //glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + + m_ShaderProgramShadowsDrawDepth.Bind(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_ShadowDepthTexture); + glBindVertexArray(m_ScreenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void Renderer::DrawModels(ShaderProgram &shader) +{ + /*glm::mat4 cameraMatrix = m_Camera->ProjectionMatrix() * m_Camera->ViewMatrix(); + + glm::mat4 MVP; + for (auto tuple : ModelsToRender) + { + Model* model; + glm::mat4 modelMatrix; + std::tie(model, modelMatrix) = tuple; + + MVP = cameraMatrix * modelMatrix; + glUniformMatrix4fv(glGetUniformLocation(shader.GetHandle(), "MVP"), 1, GL_FALSE, glm::value_ptr(MVP)); + glUniformMatrix4fv(glGetUniformLocation(shader.GetHandle(), "model"), 1, GL_FALSE, glm::value_ptr(modelMatrix)); + glUniformMatrix4fv(glGetUniformLocation(shader.GetHandle(), "view"), 1, GL_FALSE, glm::value_ptr(m_Camera->ViewMatrix())); + glBindVertexArray(model->VAO); + for (auto texGroup : model->TextureGroups) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texGroup.Texture->texture); + glDrawArrays(GL_TRIANGLES, texGroup.StartIndex, texGroup.EndIndex - texGroup.StartIndex + 1); + } + }*/ +} + +void Renderer::DrawText() +{ + //DrawShitInTextForm +} + +void Renderer::AddTextToDraw() +{ + //Add to draw shit vector +} + +void Renderer::AddModelToDraw(std::shared_ptr model, glm::vec3 position, glm::quat orientation, glm::vec3 scale, bool visible, bool shadowCaster) +{ + glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale); + // You can now use ModelMatrix to build the MVP matrix + ModelsToRender.push_back(std::make_tuple(model.get(), modelMatrix, visible, shadowCaster)); +} + +void Renderer::AddPointLightToDraw( + glm::vec3 _position, + glm::vec3 _specular, + glm::vec3 _diffuse, + float _constantAttenuation, + float _linearAttenuation, + float _quadraticAttenuation, + float _spotExponent + ) +{ + Light_position.push_back(_position.x); + Light_position.push_back(_position.y); + Light_position.push_back(_position.z); + Light_specular.push_back(_specular.x); + Light_specular.push_back(_specular.y); + Light_specular.push_back(_specular.z); + Light_diffuse.push_back(_diffuse.x); + Light_diffuse.push_back(_diffuse.y); + Light_diffuse.push_back(_diffuse.z); + Light_constantAttenuation.push_back(_constantAttenuation); + Light_linearAttenuation.push_back(_linearAttenuation); + Light_quadraticAttenuation.push_back(_quadraticAttenuation); + Light_spotExponent.push_back(_spotExponent); + Lights = Light_constantAttenuation.size(); +} + +void Renderer::AddAABBToDraw(glm::vec3 origin, glm::vec3 volumeVector, bool colliding) +{ + glm::mat4 model; + model *= glm::translate(origin); + model *= glm::scale(volumeVector); + AABBsToRender.push_back(std::make_tuple(model, colliding)); +} + +GLuint Renderer::CreateQuad() +{ + float quadVertices[] = { + -1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + + -1.0f, -1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, + 1.0f, 1.0f, 0.0f, + }; + float quadTexCoords[] = { + 0.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + }; + GLuint vbo[2], vao; + glGenBuffers(2, vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); + glBufferData(GL_ARRAY_BUFFER, 3 * 6 * sizeof(float), quadVertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); + glBufferData(GL_ARRAY_BUFFER, 2 * 6 * sizeof(float), quadTexCoords, GL_STATIC_DRAW); + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(2); + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return vao; +} + +GLuint Renderer::CreateAABB() +{ + float vertices[] = { + // Bottom + -1.0f, -1.0f, 1.0f, // 0 + 1.0f, -1.0f, 1.0f, // 1 + 1.0f, -1.0f, 1.0f, // 1 + 1.0f, -1.0f, -1.0f, // 2 + 1.0f, -1.0f, -1.0f, // 2 + -1.0f, -1.0f, -1.0f, // 3 + -1.0f, -1.0f, -1.0f, // 3 + -1.0f, -1.0f, 1.0f, // 0 + + // Top + -1.0f, 1.0f, 1.0f, // 4 + 1.0f, 1.0f, 1.0f, // 5 + 1.0f, 1.0f, 1.0f, // 5 + 1.0f, 1.0f, -1.0f, // 6 + 1.0f, 1.0f, -1.0f, // 6 + -1.0f, 1.0f, -1.0f, // 7 + -1.0f, 1.0f, -1.0f, // 7 + -1.0f, 1.0f, 1.0f, // 4 + + // Connectors + -1.0f, -1.0f, 1.0f, // 0 + -1.0f, 1.0f, 1.0f, // 4 + 1.0f, -1.0f, 1.0f, // 1 + 1.0f, 1.0f, 1.0f, // 5 + 1.0f, -1.0f, -1.0f, // 2 + 1.0f, 1.0f, -1.0f, // 6 + -1.0f, -1.0f, -1.0f, // 3 + -1.0f, 1.0f, -1.0f, // 7 + }; + + GLuint vbo, vao; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + return vao; +} + +GLuint Renderer::CreateSkybox() +{ + glm::vec3 skyBoxVertices[] = + { + glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3( 1.0f, -1.0f, -1.0f), + glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(-1.0f, -1.0f, 1.0f), + glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(-1.0f, 1.0f, -1.0f), + glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3(-1.0f, -1.0f, 1.0f), + glm::vec3( 1.0f, -1.0f, 1.0f), glm::vec3(-1.0f, -1.0f, 1.0f), glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3(-1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, 1.0f, 1.0f), glm::vec3( 1.0f, -1.0f, 1.0f), + glm::vec3(-1.0f, -1.0f, -1.0f), glm::vec3( 1.0f, -1.0f, -1.0f), glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3( 1.0f, 1.0f, -1.0f), glm::vec3(-1.0f, 1.0f, -1.0f), glm::vec3(-1.0f, -1.0f, -1.0f) + }; + + GLuint vbo, vao; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(skyBoxVertices), skyBoxVertices, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0); + glEnableVertexAttribArray(0); + glBindVertexArray(0); + + return vao; +} +void Renderer::ClearStuff() +{ + AABBsToRender.clear(); + ModelsToRender.clear(); + Light_position.clear(); + Light_specular.clear(); + Light_diffuse.clear(); + Light_constantAttenuation.clear(); + Light_linearAttenuation.clear(); + Light_quadraticAttenuation.clear(); + Light_spotExponent.clear(); + Lights = 0; +} \ No newline at end of file diff --git a/src/Renderer.h b/src/Renderer.h new file mode 100755 index 0000000..69eee8f --- /dev/null +++ b/src/Renderer.h @@ -0,0 +1,112 @@ +#ifndef Renderer_h__ +#define Renderer_h__ + +#include +#include +#include +#include +#include + +#include "Camera.h" +#include "ShaderProgram.h" +#include "Model.h" +#include "Components/PointLight.h" +#include "Skybox.h" + +class Renderer +{ +public: + + glm::mat4 viewMatrix; + glm::mat4 projectionMatrix; + + int HEIGHT, WIDTH; + + std::list> ModelsToRender; + int Lights; + std::vector Light_position; + std::vector Light_specular; + std::vector Light_diffuse; + std::vector Light_constantAttenuation; + std::vector Light_linearAttenuation; + std::vector Light_quadraticAttenuation; + std::vector Light_spotExponent; + std::list> AABBsToRender; + + Renderer(); + + void Initialize(); + void Draw(double dt); + void DrawText(); + + void AddModelToDraw(std::shared_ptr model, glm::vec3 position, glm::quat orientation, glm::vec3 scale, bool visible, bool shadowCaster); + void AddTextToDraw(); + void AddPointLightToDraw( + glm::vec3 _position, + glm::vec3 _specular, + glm::vec3 _diffuse, + float _constantAttenuation, + float _linearAttenuation, + float _quadraticAttenuation, + float _spotExponent + ); + void AddAABBToDraw(glm::vec3 origin, glm::vec3 volumeVector, bool colliding); + + void LoadContent(); + + GLFWwindow* GetWindow() const { return m_Window; } + std::shared_ptr GetCamera() const { return m_Camera; } + + bool DrawNormals() const { return m_DrawNormals; } + void DrawNormals(bool val) { m_DrawNormals = val; } + bool DrawWireframe() const { return m_DrawWireframe; } + void DrawWireframe(bool val) { m_DrawWireframe = val; } + bool DrawBounds() const { return m_DrawBounds; } + void DrawBounds(bool val) { m_DrawBounds = val; } + void DrawSkybox(); + + + +private: + GLFWwindow* m_Window; + GLint m_glVersion[2]; + GLchar* m_glVendor; + bool m_VSync; + bool m_DrawNormals; + bool m_DrawWireframe; + bool m_DrawBounds; + + std::shared_ptr m_Skybox; + + int m_ShadowMapRes; + glm::vec3 m_SunPosition; + glm::vec3 m_SunTarget; + glm::mat4 m_SunProjection; + + GLuint m_DebugAABB; + GLuint m_ScreenQuad; + GLuint m_ShadowFrameBuffer; + GLuint m_ShadowDepthTexture; + + std::shared_ptr m_Camera; + + ShaderProgram m_ShaderProgram; + ShaderProgram m_ShaderProgramNormals; + ShaderProgram m_ShaderProgramShadows; + ShaderProgram m_ShaderProgramShadowsDrawDepth; + ShaderProgram m_ShaderProgramDebugAABB; + ShaderProgram m_ShaderProgramSkybox; + + void ClearStuff(); + void DrawScene(); + void DrawModels(ShaderProgram &shader); + void DrawShadowMap(); + void CreateShadowMap(int resolution); + GLuint CreateQuad(); + void DrawDebugShadowMap(); + GLuint CreateAABB(); + GLuint CreateSkybox(void); + +}; + +#endif // Renderer_h__ \ No newline at end of file diff --git a/src/ShaderProgram.cpp b/src/ShaderProgram.cpp new file mode 100755 index 0000000..79eaea9 --- /dev/null +++ b/src/ShaderProgram.cpp @@ -0,0 +1,145 @@ +#include "PrecompiledHeader.h" +#include "ShaderProgram.h" + +GLuint Shader::CompileShader(GLenum shaderType, std::string fileName) +{ + LOG_INFO("Compiling shader \"%s\"", fileName.c_str()); + + std::string shaderFile; + std::ifstream in(fileName, std::ios::in); + if (!in) { + LOG_ERROR("Error: Failed to open shader file \"%s\"", fileName.c_str()); + return 0; + } + in.seekg(0, std::ios::end); + shaderFile.resize((int)in.tellg()); + in.seekg(0, std::ios::beg); + in.read(&shaderFile[0], shaderFile.size()); + in.close(); + + GLuint shader = glCreateShader(shaderType); + if(GLERROR("glCreateShader")) + return 0; + + const GLchar* shaderFiles = shaderFile.c_str(); + const GLint length = shaderFile.length(); + glShaderSource(shader, 1, &shaderFiles, &length); + if(GLERROR("glShaderSource")) + return 0; + + glCompileShader(shader); + + GLint compileStatus; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); + if(compileStatus != GL_TRUE) { + LOG_ERROR("Shader compilation failed"); + GLsizei infoLogLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + GLchar* infolog = new GLchar[infoLogLength]; + glGetShaderInfoLog(shader, infoLogLength, &infoLogLength, infolog); + LOG_ERROR(infolog); + delete[] infolog; + } + + if(GLERROR("glCompileShader")) + return 0; + + return shader; +} + +Shader::Shader(GLenum shaderType, std::string fileName) : m_ShaderType(shaderType), m_FileName(fileName) +{ + m_ShaderHandle = 0; +} + +Shader::~Shader() +{ + if (m_ShaderHandle != 0) { + glDeleteShader(m_ShaderHandle); + } +} + +GLuint Shader::Compile() +{ + m_ShaderHandle = CompileShader(m_ShaderType, m_FileName); + return m_ShaderHandle; +} + +GLenum Shader::GetType() const +{ + return m_ShaderType; +} + +std::string Shader::GetFileName() const +{ + return m_FileName; +} + +GLuint Shader::GetHandle() const +{ + return m_ShaderHandle; +} + +bool Shader::IsCompiled() const +{ + return m_ShaderHandle != 0; +} + +ShaderProgram::~ShaderProgram() +{ + if (m_ShaderProgramHandle != 0) { + glDeleteProgram(m_ShaderProgramHandle); + } +} + +void ShaderProgram::AddShader(std::shared_ptr shader) +{ + m_Shaders.push_back(shader); +} + +void ShaderProgram::Compile() +{ + for (auto &shader : m_Shaders) { + if (!shader->IsCompiled()) { + shader->Compile(); + } + } +} + +GLuint ShaderProgram::Link() +{ + if (m_Shaders.size() == 0) { + LOG_ERROR("Failed to link shader program: No shaders bound"); + return 0; + } + + LOG_INFO("Linking shader program"); + m_ShaderProgramHandle = glCreateProgram(); + for (auto &shader : m_Shaders) { + glAttachShader(m_ShaderProgramHandle, shader->GetHandle()); + } + glLinkProgram(m_ShaderProgramHandle); + if (GLERROR("glLinkProgram")) + return 0; + m_Shaders.clear(); + + return m_ShaderProgramHandle; +} + +GLuint ShaderProgram::GetHandle() +{ + return m_ShaderProgramHandle; +} + +void ShaderProgram::Bind() +{ + if (m_ShaderProgramHandle == 0) + return; + + glUseProgram(m_ShaderProgramHandle); +} + +void ShaderProgram::Unbind() +{ + glActiveShaderProgram(0, 0); +} \ No newline at end of file diff --git a/src/ShaderProgram.h b/src/ShaderProgram.h new file mode 100755 index 0000000..df0c41c --- /dev/null +++ b/src/ShaderProgram.h @@ -0,0 +1,79 @@ +#ifndef ShaderProgram_h__ +#define ShaderProgram_h__ + +#include +#include +#include +#include + +class Shader +{ +public: + static GLuint CompileShader(GLenum shaderType, std::string fileName); + + Shader(GLenum shaderType, std::string fileName); + + virtual ~Shader(); + + GLuint Compile(); + + GLenum GetType() const; + std::string GetFileName() const; + GLuint GetHandle() const; + bool IsCompiled() const; + +protected: + GLenum m_ShaderType; + std::string m_FileName; + GLint m_ShaderHandle; +}; + +template +class ShaderType : public Shader +{ +public: + ShaderType(std::string fileName) + : Shader(SHADERTYPE, fileName) { } +}; + +class VertexShader : public ShaderType +{ +public: + VertexShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class FragmentShader : public ShaderType +{ +public: + FragmentShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class GeometryShader : public ShaderType +{ +public: + GeometryShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class ShaderProgram +{ +public: + ShaderProgram() + : m_ShaderProgramHandle(0) { } + ~ShaderProgram(); + + void AddShader(std::shared_ptr shader); + void Compile(); + GLuint Link(); + GLuint GetHandle(); + void Bind(); + void Unbind(); + +private: + GLuint m_ShaderProgramHandle; + std::vector> m_Shaders; +}; + +#endif // ShaderProgram_h__ \ No newline at end of file diff --git a/src/Shaders/AABB.frag.glsl b/src/Shaders/AABB.frag.glsl new file mode 100755 index 0000000..16bbb30 --- /dev/null +++ b/src/Shaders/AABB.frag.glsl @@ -0,0 +1,17 @@ +#version 430 + +uniform vec4 Color; + +in VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; + vec3 ShadowCoord; +} Input; + +out vec4 FragmentColor; + +void main() { + //FragmentColor = vec4(1.0 - gl_Color.r, 1.0 - gl_Color.g, 1.0 - gl_Color.b, 0.0); + FragmentColor = Color; +} \ No newline at end of file diff --git a/src/Shaders/Fragment.glsl b/src/Shaders/Fragment.glsl new file mode 100755 index 0000000..4aead15 --- /dev/null +++ b/src/Shaders/Fragment.glsl @@ -0,0 +1,109 @@ +#version 430 + +uniform mat4 model; +uniform mat4 view; + +layout(binding=0) uniform sampler2D texture0; +layout(binding=1) uniform sampler2D shadowMap; + +const int maxNumberOfLights = 82; +uniform int numberOfLights; +uniform vec3 position[maxNumberOfLights]; +uniform vec3 specular[maxNumberOfLights]; +uniform vec3 diffuse[maxNumberOfLights]; +uniform float constantAttenuation[maxNumberOfLights]; +uniform float linearAttenuation[maxNumberOfLights]; +uniform float quadraticAttenuation[maxNumberOfLights]; +uniform float spotExponent[maxNumberOfLights]; + +in VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; + vec3 ShadowCoord; +} Input; + +vec3 scene_ambient = vec3(0.5, 0.5, 0.5); + +out vec4 fragmentColor; + +void main() { + + // Texture + vec4 texel = texture2D(texture0, Input.TextureCoord); + //vec4 texel = (blend.x * texel0) + (blend.y * texel1) + (blend.z * texel2); + + // + // Phong shading + // + + // Ambient light + vec3 La = scene_ambient; // Ambient light + vec3 Ks = vec3(0.3, 0.3, 0.3); // Specular reflectance + vec3 Kd = vec3(1.0, 1.0, 1.0); // Diffuse reflectance + vec3 Ka = vec3(1.0, 1.0, 1.0); // Ambient reflectance + vec3 Is; + vec3 Id; + + // Shadows + //float cosTheta = clamp(dot(Input.Normal, vec3(0, 1, 0)), 0.0, 1.0); + //float bias = 0.001 * tan(acos(cosTheta)); // cosTheta is dot( n,l ), clamped between 0 and 1 + //bias = clamp(bias, 0.0, 0.01); + float visibility = 1.0; + if (Input.ShadowCoord.x >= 0.0 && Input.ShadowCoord.x <= 1.0 && Input.ShadowCoord.y >= 0.0 && Input.ShadowCoord.y <= 1.0) { + float bias = 0.0005; + vec4 shadowMapValue = texture(shadowMap, Input.ShadowCoord.xy); + if (shadowMapValue.z < clamp(Input.ShadowCoord.z - bias, 0, 1)) { + visibility = 0.3; + } + } + + vec3 totalLighting = La * Ka * visibility; + + float attenuation; + + for(int i = 0; i < numberOfLights && i < maxNumberOfLights; i++) + { + // Light + //vec3 lightPosition = vec3(0, 0, 2); + vec3 Ls = specular[i]; // Specular light + vec3 Ld = diffuse[i]; // Diffuse light + + vec3 lightPosView = vec3(view * vec4(position[i], 1.0)); + vec3 surfacePosition = vec3(model * vec4(Input.Position, 1.0)); + vec3 surfacePosView = vec3(view * vec4(surfacePosition, 1.0)); + vec3 surfaceToLight = normalize(lightPosView - surfacePosView); + mat3 normalMatrix = transpose(inverse(mat3(view * model))); + vec3 surfaceNormal = normalize(normalMatrix * Input.Normal); + + float dist = length(position[i] - surfacePosition); + + attenuation = 1.0 / (constantAttenuation[i] + + linearAttenuation[i] * dist + + quadraticAttenuation[i] * pow(dist, 2.0)); + //attenuation = attenuation * pow(clampedCosine, spotExponent[i]); + + // Diffuse light + float dotProd = dot(surfaceToLight, surfaceNormal); + dotProd = max(dotProd, 0.0); + + Id = Ld * Kd * abs(dotProd) * attenuation; + + // Specular light + vec3 reflection = reflect(-surfaceToLight, surfaceNormal); + float dotSpecular = dot(reflection, normalize(-surfacePosView)); + dotSpecular = max(dotSpecular, 0.0); + float specularFactor = pow(dotSpecular, 30.0); // Specular factor + + Is = attenuation * Ls * Ks * specularFactor; + + totalLighting = totalLighting + Id + Is; + } + + fragmentColor = vec4(totalLighting, 1.0) * texel; + + + //fragmentColor = vec4(Id, 1.0) * texel; + + //fragmentColor = texel; +} \ No newline at end of file diff --git a/src/Shaders/Normals.frag.glsl b/src/Shaders/Normals.frag.glsl new file mode 100755 index 0000000..fd1bb9a --- /dev/null +++ b/src/Shaders/Normals.frag.glsl @@ -0,0 +1,9 @@ +#version 430 + +uniform mat4 MVP; + +out vec4 FragmentColor; + +void main() { + FragmentColor = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/src/Shaders/Normals.geo.glsl b/src/Shaders/Normals.geo.glsl new file mode 100755 index 0000000..0f72a8e --- /dev/null +++ b/src/Shaders/Normals.geo.glsl @@ -0,0 +1,34 @@ +#version 430 + +uniform mat4 MVP; + +layout(triangles) in; +layout(line_strip, max_vertices = 6) out; + +in VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; +} Input[3]; + +out VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; +} Output; + +void main() +{ + for (int i = 0; i < gl_in.length(); i++) + { + gl_Position = MVP * vec4(Input[i].Position, 1.0); + EmitVertex(); + gl_Position = MVP * vec4(Input[i].Position + Input[i].Normal, 1.0); + EmitVertex(); + EndPrimitive(); + + Output.Position = Input[i].Position; + Output.Normal = Input[i].Normal; + Output.TextureCoord = Input[i].TextureCoord; + } +} \ No newline at end of file diff --git a/src/Shaders/ShadowMap.frag.glsl b/src/Shaders/ShadowMap.frag.glsl new file mode 100755 index 0000000..adae8d5 --- /dev/null +++ b/src/Shaders/ShadowMap.frag.glsl @@ -0,0 +1,9 @@ +#version 430 + +uniform mat4 MVP; + +layout(location = 0) out float FragmentDepth; + +void main() { + FragmentDepth = gl_FragCoord.z; +} \ No newline at end of file diff --git a/src/Shaders/ShadowMap.vert.glsl b/src/Shaders/ShadowMap.vert.glsl new file mode 100755 index 0000000..042411c --- /dev/null +++ b/src/Shaders/ShadowMap.vert.glsl @@ -0,0 +1,22 @@ +#version 430 + +uniform mat4 MVP; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec2 TextureCoord; + +out VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; +} Output; + +void main() +{ + gl_Position = MVP * vec4(Position, 1.0); + + Output.Position = Position; + Output.Normal = Normal; + Output.TextureCoord = TextureCoord; +} \ No newline at end of file diff --git a/src/Shaders/Skybox.frag.glsl b/src/Shaders/Skybox.frag.glsl new file mode 100755 index 0000000..66956b4 --- /dev/null +++ b/src/Shaders/Skybox.frag.glsl @@ -0,0 +1,15 @@ +#version 430 + +uniform samplerCube CubemapTexture; + +in VertexData { + vec3 TextureCoord; +} Input; + +out vec4 FragColor; + +void main() +{ + FragColor = texture(CubemapTexture, Input.TextureCoord); + //FragColor = vec4(1.0, 1.0, 1.0, 0.0); +} \ No newline at end of file diff --git a/src/Shaders/Skybox.vert.glsl b/src/Shaders/Skybox.vert.glsl new file mode 100755 index 0000000..f4f8c4c --- /dev/null +++ b/src/Shaders/Skybox.vert.glsl @@ -0,0 +1,15 @@ +#version 430 + +uniform mat4 MVP; + +layout(location = 0) in vec3 Position; + +out VertexData { + vec3 TextureCoord; +} Output; + +void main() +{ + gl_Position = MVP * vec4(Position, 1.0); + Output.TextureCoord = Position; +} \ No newline at end of file diff --git a/src/Shaders/Vertex.glsl b/src/Shaders/Vertex.glsl new file mode 100755 index 0000000..2b5b0e5 --- /dev/null +++ b/src/Shaders/Vertex.glsl @@ -0,0 +1,25 @@ +#version 430 + +uniform mat4 MVP; +uniform mat4 DepthMVP; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec2 TextureCoord; + +out VertexData { + vec3 Position; + vec3 Normal; + vec2 TextureCoord; + vec3 ShadowCoord; +} Output; + +void main() +{ + gl_Position = MVP * vec4(Position, 1.0); + + Output.Position = Position; + Output.Normal = Normal; + Output.TextureCoord = TextureCoord; + Output.ShadowCoord = vec3(DepthMVP * vec4(Position, 1.0)); +} \ No newline at end of file diff --git a/src/Shaders/VisualizeDepth.frag.glsl b/src/Shaders/VisualizeDepth.frag.glsl new file mode 100755 index 0000000..42e55f3 --- /dev/null +++ b/src/Shaders/VisualizeDepth.frag.glsl @@ -0,0 +1,24 @@ +#version 430 + +layout(binding = 0) uniform sampler2D DepthTexture; + +in VertexData { + vec3 Position; + vec2 TextureCoord; +} Input; + +out vec4 FragmentColor; + +float LinearizeDepth(float z) +{ + float n = 0.1; // camera z near + float f = 800.0; // camera z far + return (2.0 * n) / (f + n - z * (f - n)); +} + +void main() { + float z = texture(DepthTexture, Input.TextureCoord).x; + vec4 color = vec4(z, z, z, 0); + + FragmentColor = color; +} \ No newline at end of file diff --git a/src/Shaders/VisualizeDepth.vert.glsl b/src/Shaders/VisualizeDepth.vert.glsl new file mode 100755 index 0000000..32e6205 --- /dev/null +++ b/src/Shaders/VisualizeDepth.vert.glsl @@ -0,0 +1,17 @@ +#version 430 + +layout(location = 0) in vec3 Position; +layout(location = 2) in vec2 TextureCoord; + +out VertexData { + vec3 Position; + vec2 TextureCoord; +} Output; + +void main() +{ + gl_Position = vec4(Position, 1.0); + + Output.Position = Position; + Output.TextureCoord = TextureCoord; +} \ No newline at end of file diff --git a/src/Skybox.cpp b/src/Skybox.cpp new file mode 100755 index 0000000..effb78b --- /dev/null +++ b/src/Skybox.cpp @@ -0,0 +1,91 @@ +#include "PrecompiledHeader.h" +#include "Skybox.h" + +Skybox::Skybox(std::string skyboxPath, std::string extension /* = "png" */) +{ + m_Cubemap = std::make_shared( + skyboxPath + "/right." + extension, + skyboxPath + "/left." + extension, + skyboxPath + "/top." + extension, + skyboxPath + "/bottom." + extension, + skyboxPath + "/front." + extension, + skyboxPath + "/back." + extension); + m_Cubemap->Load(); + Initialize(); +} + +void Skybox::Initialize() +{ + float cubeVertices[] = { + -1.0f, -1.0f, -1.0f, + 1.0f, -1.0f, -1.0f, + 1.0f, 1.0f, -1.0f, + -1.0f, 1.0f, -1.0f, + + -1.0f, -1.0f, 1.0f, + 1.0f, -1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, + -1.0f, 1.0f, 1.0f, + }; + //std::copy(cubeVertices, cubeVertices + (3*8 - 1), m_CubeVertices); + + unsigned int cubeIndices[] = { + // Back + 0, 2, 3, + 0, 1, 2, + + // Right + 1, 6, 2, + 1, 5, 6, + + // Front + 5, 7, 6, + 5, 4, 7, + + // Left + 4, 3, 7, + 4, 0, 3, + + // Top + 3, 6, 7, + 3, 2, 6, + + // Bottom + 4, 1, 0, + 4, 5, 1, + }; + //std::copy(cubeIndices, cubeIndices + (3*12 - 1), m_CubeIndices); + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, 3 * 8 * sizeof(float), cubeVertices, GL_STATIC_DRAW); + + glGenBuffers(1, &ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, 3 * 12 * sizeof(int), cubeIndices, GL_STATIC_DRAW); + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); + glEnableVertexAttribArray(0); + + GLERROR("Skybox init"); +} + + +Skybox::~Skybox() +{ + +} + +void Skybox::Draw() +{ + m_Cubemap->Bind(GL_TEXTURE0); + + glBindVertexArray(vao); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); + glDepthMask(GL_FALSE); + glDrawElements(GL_TRIANGLES, 3 * 12, GL_UNSIGNED_INT, 0); + glDepthMask(GL_TRUE); +} diff --git a/src/Skybox.h b/src/Skybox.h new file mode 100755 index 0000000..4de5951 --- /dev/null +++ b/src/Skybox.h @@ -0,0 +1,30 @@ +#ifndef Skybox_h__ +#define Skybox_h__ + +#include + +#include "CubemapTexture.h" + +class Skybox +{ +public: + Skybox(std::string skyboxPath, std::string extension = "png"); + Skybox(std::shared_ptr cubemap) + : m_Cubemap(cubemap) { Initialize(); } + ~Skybox(); + + void Draw(); + +private: + std::shared_ptr m_Cubemap; + + GLuint ibo; + GLuint vao; + + float m_CubeVertices[3 * 8]; + int m_CubeIndices[1]; + + void Initialize(); +}; + +#endif // Skybox_h__ \ No newline at end of file diff --git a/src/System.h b/src/System.h new file mode 100755 index 0000000..cbe9cb8 --- /dev/null +++ b/src/System.h @@ -0,0 +1,34 @@ +#ifndef System_h__ +#define System_h__ + +#include "Factory.h" +#include "Entity.h" +#include "Component.h" + +class World; + +class System +{ +public: + System(World* world) : m_World(world) { } + virtual ~System() { } + + virtual void Initialize() { } + + // Called once per system every tick + virtual void Update(double dt) { } + // Called once for every entity in the world every tick + virtual void UpdateEntity(double dt, EntityID entity, EntityID parent) { } + + // Called when a component is created + virtual void OnComponentCreated(std::string type, std::shared_ptr component) { } + // Called when a component is removed + virtual void OnComponentRemoved(std::string type, Component* component) { } + +protected: + World* m_World; +}; + +class SystemFactory : public Factory { }; + +#endif // System_h__ \ No newline at end of file diff --git a/src/Systems/RenderSystem.cpp b/src/Systems/RenderSystem.cpp new file mode 100755 index 0000000..7aaf17f --- /dev/null +++ b/src/Systems/RenderSystem.cpp @@ -0,0 +1,74 @@ +#include "PrecompiledHeader.h" +#include "RenderSystem.h" +#include "World.h" + +void Systems::RenderSystem::OnComponentCreated(std::string type, std::shared_ptr component) +{ + if(type == "Model") { + auto modelComponent = std::static_pointer_cast(component); + } +} + +void Systems::RenderSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) +{ + auto transformComponent = m_World->GetComponent(entity, "Transform"); + if (transformComponent == nullptr) + return; + + // Draw models + auto modelComponent = m_World->GetComponent(entity, "Model"); + if (modelComponent != nullptr) { + if (m_CachedModels.find(modelComponent->ModelFile) == m_CachedModels.end()){ + m_CachedModels[modelComponent->ModelFile] = std::make_shared(OBJ(modelComponent->ModelFile)); + } + + auto model = m_CachedModels[modelComponent->ModelFile]; + glm::vec3 position = m_TransformSystem->AbsolutePosition(entity); + glm::quat orientation = m_TransformSystem->AbsoluteOrientation(entity); + m_Renderer->AddModelToDraw(model, position, orientation, transformComponent->Scale, modelComponent->Visible, modelComponent->ShadowCaster); + } + + // Debug draw bounds +#ifdef DEBUG + auto collision = m_World->GetComponent(entity, "Collision"); + auto bounds = m_World->GetComponent(entity, "Bounds"); + if (bounds != nullptr) { + glm::vec3 origin = m_TransformSystem->AbsolutePosition(entity) + (transformComponent->Scale * bounds->Origin); + glm::vec3 volumeVector = transformComponent->Scale * bounds->VolumeVector; + m_Renderer->AddAABBToDraw(origin, volumeVector, (collision != nullptr && collision->CollidingEntities.size() > 0)); + } +#endif + + auto pointLightComponent = m_World->GetComponent(entity, "PointLight"); + if (pointLightComponent != nullptr) { + glm::vec3 position = m_TransformSystem->AbsolutePosition(entity); + m_Renderer->AddPointLightToDraw( + position, + pointLightComponent->Specular, + pointLightComponent->Diffuse, + pointLightComponent->constantAttenuation, + pointLightComponent->linearAttenuation, + pointLightComponent->quadraticAttenuation, + pointLightComponent->spotExponent); + } + + auto cameraComponent = m_World->GetComponent(entity, "Camera"); + if (cameraComponent != nullptr) { + m_Renderer->GetCamera()->Position(transformComponent->Position); + m_Renderer->GetCamera()->Orientation(transformComponent->Orientation); + + m_Renderer->GetCamera()->FOV(cameraComponent->FOV); + m_Renderer->GetCamera()->NearClip(cameraComponent->NearClip); + m_Renderer->GetCamera()->FarClip(cameraComponent->FarClip); + } +} + +void Systems::RenderSystem::Initialize() +{ + m_TransformSystem = m_World->GetSystem("TransformSystem"); +} + + + + + diff --git a/src/Systems/RenderSystem.h b/src/Systems/RenderSystem.h new file mode 100755 index 0000000..f9e5ee6 --- /dev/null +++ b/src/Systems/RenderSystem.h @@ -0,0 +1,44 @@ +#ifndef RenderSystem_h__ +#define RenderSystem_h__ + +#include + +#include "System.h" +#include "Systems/TransformSystem.h" +#include "Model.h" +#include "Texture.h" +#include "Components/Model.h" +#include "Components/Transform.h" +#include "Components/Camera.h" +#include "Components/Bounds.h" +#include "Components/Collision.h" +#include "Renderer.h" + +namespace Systems +{ + + class RenderSystem : public System + { + public: + RenderSystem(World* world, std::shared_ptr renderer) + : System(world), m_Renderer(renderer){ } + + void Initialize() override; + + std::unordered_map> m_CachedModels; + + void OnComponentCreated(std::string type, std:: shared_ptr component) override; + void UpdateEntity(double dt, EntityID entity, EntityID parent) override; + + private: + std::shared_ptr m_Renderer; + std::shared_ptr m_TransformSystem; + }; + + +} + + + + +#endif //RenderSystem_h__ \ No newline at end of file diff --git a/src/Systems/TransformSystem.cpp b/src/Systems/TransformSystem.cpp new file mode 100755 index 0000000..d243a9e --- /dev/null +++ b/src/Systems/TransformSystem.cpp @@ -0,0 +1,48 @@ +#include "PrecompiledHeader.h" +#include "TransformSystem.h" +#include "World.h" + +//void Systems::TransformSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) +//{ +// if (parent == 0) +// return; +// +// auto transform = m_World->GetComponent(entity, "Transform"); +// auto parentTransform = m_World->GetComponent(parent, "Transform"); +// +// transform->Position = parentTransform->Position + transform->RelativePosition; +//} + +glm::vec3 Systems::TransformSystem::AbsolutePosition(EntityID entity) +{ + glm::vec3 absPosition; + glm::quat accumulativeOrientation; + + do + { + auto transform = m_World->GetComponent(entity, "Transform"); + //absPosition += transform->Position; + entity = m_World->GetEntityParent(entity); + auto transform2 = m_World->GetComponent(entity, "Transform"); + if (entity != 0) + absPosition += transform2->Orientation * transform->Position; + else + absPosition += transform->Position; + } while (entity != 0); + + return absPosition * accumulativeOrientation; +} + +glm::quat Systems::TransformSystem::AbsoluteOrientation(EntityID entity) +{ + glm::quat absOrientation; + + do + { + auto transform = m_World->GetComponent(entity, "Transform"); + absOrientation *= transform->Orientation; + entity = m_World->GetEntityParent(entity); + } while (entity != 0); + + return absOrientation; +} \ No newline at end of file diff --git a/src/Systems/TransformSystem.h b/src/Systems/TransformSystem.h new file mode 100755 index 0000000..b0cc2fa --- /dev/null +++ b/src/Systems/TransformSystem.h @@ -0,0 +1,25 @@ +#ifndef TransformSystem_h__ +#define TransformSystem_h__ + +#include "System.h" +#include "Components/Transform.h" + +namespace Systems +{ + + class TransformSystem : public System + { + public: + TransformSystem(World* world) + : System(world) { } + + //void Update(double dt) override; + //void UpdateEntity(double dt, EntityID entity, EntityID parent) override; + + glm::vec3 AbsolutePosition(EntityID entity); + glm::quat AbsoluteOrientation(EntityID entity); + }; + +} + +#endif // TransformSystem_h__ diff --git a/src/Texture.cpp b/src/Texture.cpp new file mode 100755 index 0000000..05a3904 --- /dev/null +++ b/src/Texture.cpp @@ -0,0 +1,26 @@ +#include "PrecompiledHeader.h" +#include "Texture.h" + +Texture::Texture(std::string path) +{ + Load(path); +} + + +void Texture::Load(std::string path) +{ + texture = SOIL_load_OGL_texture(path.c_str(), 0, 0, SOIL_FLAG_INVERT_Y); +} + +void Texture::Bind() +{ + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture); +} + +Texture::~Texture() +{ + glDeleteTextures(1, &texture); +} + + diff --git a/src/Texture.h b/src/Texture.h new file mode 100755 index 0000000..9d66f51 --- /dev/null +++ b/src/Texture.h @@ -0,0 +1,21 @@ +#ifndef Texture_h__ +#define Texture_h__ + +#include + +#include + +class Texture +{ +public: + Texture(std::string path); + + ~Texture(); + + GLuint texture; + + void Load(std::string path); + void Bind(); +}; + +#endif // Texture_h__ diff --git a/src/Util/GLError.h b/src/Util/GLError.h index 40070ed..678bd05 100755 --- a/src/Util/GLError.h +++ b/src/Util/GLError.h @@ -1,10 +1,9 @@ -#ifndef glerror_h__ -#define glerror_h__ +#ifndef GLError_h__ +#define GLError_h__ +#include "PrecompiledHeader.h" #include -#include "logging.h" - inline bool _GLERROR(char* info, char* file, char* func, unsigned int line) { GLenum error = glGetError(); @@ -19,4 +18,4 @@ inline bool _GLERROR(char* info, char* file, char* func, unsigned int line) #define GLERROR(function) \ _GLERROR(function, __BASE_FILE__, __func__, __LINE__) -#endif // glerror_h__ \ No newline at end of file +#endif // GLError_h__ \ No newline at end of file diff --git a/src/Util/Logging.h b/src/Util/Logging.h index a2acdc1..49b7cf3 100755 --- a/src/Util/Logging.h +++ b/src/Util/Logging.h @@ -1,5 +1,5 @@ -#ifndef logging_h__ -#define logging_h__ +#ifndef Logging_h__ +#define Logging_h__ #ifdef _WIN32 // http://stackoverflow.com/a/2282433 @@ -80,4 +80,4 @@ static void _LOG(_LOG_LEVEL logLevel, char* file, char* func, unsigned int line, #define LOG_DEBUG(format, ...) \ LOG(LOG_LEVEL_DEBUG, format, ##__VA_ARGS__) -#endif // logging_h__ \ No newline at end of file +#endif // Logging_h__ \ No newline at end of file diff --git a/src/World.cpp b/src/World.cpp new file mode 100755 index 0000000..29bde4b --- /dev/null +++ b/src/World.cpp @@ -0,0 +1,132 @@ +#include "PrecompiledHeader.h" +#include "World.h" + +void World::RecycleEntityID(EntityID id) +{ + m_RecycledEntityIDs.push(id); +} + +EntityID World::GenerateEntityID() +{ + if (!m_RecycledEntityIDs.empty()) { + EntityID id = m_RecycledEntityIDs.top(); + m_RecycledEntityIDs.pop(); + return id; + } else { + return ++m_LastEntityID; + } +} + +void World::RecursiveUpdate(std::shared_ptr system, double dt, EntityID parentEntity) +{ + for (auto pair : m_EntityParents) { + EntityID child = pair.first; + EntityID parent = pair.second; + + if (parent == parentEntity) { + system->UpdateEntity(dt, child, parent); + RecursiveUpdate(system, dt, child); + } + } +} + +void World::Update(double dt) +{ + for (auto pair : m_Systems) { + auto system = pair.second; + system->Update(dt); + RecursiveUpdate(system, dt, 0); + } + + ProcessEntityRemovals(); +} + +//std::vector GetEntityChildren(EntityID entity); +//{ +// std::vector children; +// auto range = m_SceneGraph.equal_range(entity); +// for (auto it = range.first; it != range.second; ++it) +// children.push_back(it->second); +// return children; +//} + +EntityID World::GetEntityParent(EntityID entity) +{ + auto it = m_EntityParents.find(entity); + return it == m_EntityParents.end() ? 0 : it->second; +} + +bool World::ValidEntity(EntityID entity) +{ + return m_EntityParents.find(entity) != m_EntityParents.end(); +} + +void World::RemoveEntity(EntityID entity) +{ + m_EntitiesToRemove.push_back(entity); + for (auto pair : m_EntityParents) { + if (pair.second == entity) { + m_EntitiesToRemove.push_back(pair.first); + } + } +} + +void World::ProcessEntityRemovals() +{ + for (auto entity : m_EntitiesToRemove) { + m_EntityParents.erase(entity); + // Remove components + for (auto pair : m_EntityComponents[entity]) { + auto type = pair.first; + auto component = pair.second; + // Trigger events + for (auto pair : m_Systems) { + auto system = pair.second; + system->OnComponentRemoved(type, component.get()); + } + m_ComponentsOfType[type].remove(component); + } + m_EntityComponents.erase(entity); + + RecycleEntityID(entity); + } + m_EntitiesToRemove.clear(); +} + +EntityID World::CreateEntity(EntityID parent /*= 0*/) +{ + EntityID newEntity = GenerateEntityID(); + m_EntityParents.insert(std::pair(newEntity, parent)); + return newEntity; +} + +World::~World() +{ + +} + +World::World() +{ + m_LastEntityID = 0; +} + +void World::Initialize() +{ + RegisterSystems(); + AddSystems(); + for (auto system : m_Systems) { + system.second->Initialize(); + } + + RegisterComponents(); +} + +std::shared_ptr World::AddComponent(EntityID entity, std::string componentType) +{ + return AddComponent(entity, componentType); +} + +void World::AddSystem(std::string systemType) +{ + m_Systems[systemType] = std::shared_ptr(m_SystemFactory.Create(systemType)); +} diff --git a/src/World.h b/src/World.h new file mode 100755 index 0000000..ecc9fd1 --- /dev/null +++ b/src/World.h @@ -0,0 +1,136 @@ +#ifndef World_h__ +#define World_h__ + +#include +#include +#include +#include +#include +#include + +#include + +#include "Util/logging.h" + +#include "Factory.h" +#include "Entity.h" +#include "Component.h" +#include "System.h" + +class World +{ +public: + World(); + ~World(); + + virtual void Initialize(); + + virtual void RegisterSystems() = 0; + virtual void AddSystems() = 0; + virtual void RegisterComponents() = 0; + + + void AddSystem(std::string systemType); + template + std::shared_ptr GetSystem(std::string systemType); + + EntityID CreateEntity(EntityID parent = 0); + + void RemoveEntity(EntityID entity); + + bool ValidEntity(EntityID entity); + + EntityID GetEntityParent(EntityID entity); + + template + T GetProperty(EntityID entity, std::string property) + { + if(m_EntityProperties.find(entity) == m_EntityProperties.end()) + return T(); + if(m_EntityProperties[entity].find(property) == m_EntityProperties[entity].end()) + return T(); + + return boost::any_cast(m_EntityProperties[entity][property]); + } + + void SetProperty(EntityID entity, std::string property, boost::any value) + { + m_EntityProperties[entity][property] = value; + } + + template + std::shared_ptr AddComponent(EntityID entity, std::string componentType); + std::shared_ptr AddComponent(EntityID entity, std::string componentType); + template + T* GetComponent(EntityID entity, std::string componentType); + + /*std::vector GetEntityChildren(EntityID entity);*/ + + virtual void Update(double dt); + // Recursively update through the scene graph + void RecursiveUpdate(std::shared_ptr system, double dt, EntityID parentEntity); + + std::unordered_map* GetEntities() { return &m_EntityParents; } + +protected: + SystemFactory m_SystemFactory; + ComponentFactory m_ComponentFactory; + + std::unordered_map> m_Systems; + + EntityID m_LastEntityID; + std::stack m_RecycledEntityIDs; + // A bottom to top tree. A map of child entities to parent entities. + std::unordered_map m_EntityParents; + std::unordered_map> m_EntityProperties; + + std::unordered_map>> m_ComponentsOfType; + std::unordered_map>> m_EntityComponents; + + std::list m_EntitiesToRemove; + void ProcessEntityRemovals(); + + EntityID GenerateEntityID(); + + void RecycleEntityID(EntityID id); + +}; + +template +std::shared_ptr World::GetSystem(std::string systemType) +{ + if (m_Systems.find(systemType) == m_Systems.end()) { + LOG_WARNING("Tried to get pointer to unregistered system \"%s\"!", systemType.c_str()); + return nullptr; + } + + return std::static_pointer_cast(m_Systems.at(systemType)); +} + +template +std::shared_ptr World::AddComponent(EntityID entity, std::string componentType) +{ + std::shared_ptr component = std::shared_ptr(static_cast(m_ComponentFactory.Create(componentType))); + if (component == nullptr) { + LOG_ERROR("Failed to attach invalid component \"%s\" to entity #%i", componentType.c_str(), entity); + return nullptr; + } + + component->Entity = entity; + m_ComponentsOfType[componentType].push_back(component); + m_EntityComponents[entity][componentType] = component; + for (auto pair : m_Systems) { + auto system = pair.second; + system->OnComponentCreated(componentType, component); + } + return component; +} + + +template +T* World::GetComponent(EntityID entity, std::string componentType) +{ + return (T*)m_EntityComponents[entity][componentType].get(); +} + +#endif // World_h__ \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index bc5575d..5e069e8 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,58 +1,11 @@ -#include -#include - -#include "OpenGL.h" -#include "GLM.h" - -#include "Util/logging.h" -#include "Util/glerror.h" - -GLFWwindow* window; -GLint glVersion[2]; -GLchar* glVendor; +#include "PrecompiledHeader.h" +#include "Engine.h" int main(int argc, char* argv[]) { - // Initialize GLFW - if (!glfwInit()) - { - LOG_ERROR("GLFW: Initialization failed"); - return 1; - } - - // Create a window - window = glfwCreateWindow(1280, 720, "OpenGL", nullptr, nullptr); - if (!window) - { - LOG_ERROR("GLFW: Failed to create window"); - return 1; - } - glfwMakeContextCurrent(window); - - // GL version info - glGetIntegerv(GL_MAJOR_VERSION, &glVersion[0]); - glGetIntegerv(GL_MINOR_VERSION, &glVersion[1]); - glVendor = (GLchar*)glGetString(GL_VENDOR); - std::stringstream ss; - ss << glVendor << " OpenGL " << glVersion[0] << "." << glVersion[1]; -#ifdef DEBUG - ss << " DEBUG"; -#endif - LOG_INFO(ss.str().c_str()); - glfwSetWindowTitle(window, ss.str().c_str()); - - // Initialize GLEW - if (glewInit() != GLEW_OK) - { - LOG_ERROR("GLEW: Initialization failed"); - return 1; - } - - // Main loop - while (!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - } + Engine engine(argc, argv); + while (engine.Running()) + engine.Tick(); return 0; } \ No newline at end of file diff --git a/vs12/Returngeance.sln b/vs12/Returngeance.sln index 147ad31..0a9dc7f 100755 --- a/vs12/Returngeance.sln +++ b/vs12/Returngeance.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 2013 -VisualStudioVersion = 12.0.21005.1 +VisualStudioVersion = 12.0.30110.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Returngeance", "Returngeance\Returngeance.vcxproj", "{E8B4A2A2-882B-402A-98A7-8B4F7233C8B3}" EndProject @@ -19,4 +19,7 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(Performance) = preSolution + HasPerformanceSessions = true + EndGlobalSection EndGlobal diff --git a/vs12/Returngeance/Returngeance.vcxproj b/vs12/Returngeance/Returngeance.vcxproj index 71734cf..b6d4b0d 100755 --- a/vs12/Returngeance/Returngeance.vcxproj +++ b/vs12/Returngeance/Returngeance.vcxproj @@ -39,14 +39,14 @@ - $(BOOST_ROOT);$(SolutionDir)\..\libs;$(SolutionDir)\..\libs\glew-1.10.0\include;$(SolutionDir)\..\libs\glfw-3.0.4\include;$(SolutionDir)\..\libs\glm-0.9.5.3;$(SolutionDir)\..\libs\openal-soft-1.15.1\include;$(SolutionDir)\..\libs\bullet-2.82-r2704\src;$(IncludePath) - $(BOOST_ROOT)\lib32-msvc-12.0;$(SolutionDir)\..\libs\glew-1.10.0\lib\Debug\Win32;$(SolutionDir)\..\libs\glfw-3.0.4\lib\Debug;$(SolutionDir)\..\libs\openal-soft-1.15.1\lib\Win32\Debug;$(SolutionDir)\..\libs\bullet-2.82-r2704\lib\Debug;$(LibraryPath) + $(BOOST_ROOT);$(SolutionDir)\..\src;$(SolutionDir)\..\libs;$(SolutionDir)\..\libs\glew-1.10.0\include;$(SolutionDir)\..\libs\glfw-3.0.4\include;$(SolutionDir)\..\libs\glm-0.9.5.3;$(SolutionDir)\..\libs\openal-soft-1.15.1\include;$(SolutionDir)\..\libs\bullet-2.82-r2704\src;$(SolutionDir)\..\libs\SOIL\src;$(IncludePath) + $(BOOST_ROOT)\lib32-msvc-12.0;$(SolutionDir)\..\libs\glew-1.10.0\lib\Debug\Win32;$(SolutionDir)\..\libs\glfw-3.0.4\lib\Debug;$(SolutionDir)\..\libs\openal-soft-1.15.1\lib\Win32\Debug;$(SolutionDir)\..\libs\bullet-2.82-r2704\lib\Debug;$(SolutionDir)\..\libs\SOIL\lib\Debug;$(LibraryPath) $(SolutionDir)\..\bin\$(Configuration)\ $(SolutionDir)\..\obj\$(Configuration)\ - $(BOOST_ROOT);$(SolutionDir)\..\libs;$(SolutionDir)\..\libs\glew-1.10.0\include;$(SolutionDir)\..\libs\glfw-3.0.4\include;$(SolutionDir)\..\libs\glm-0.9.5.3;$(SolutionDir)\..\libs\openal-soft-1.15.1\include;$(SolutionDir)\..\libs\bullet-2.82-r2704\src;$(IncludePath) - $(BOOST_ROOT)\lib32-msvc-12.0;$(SolutionDir)\..\libs\glfw-3.0.4\lib\Release;$(SolutionDir)\..\libs\glew-1.10.0\lib\Release\Win32;$(SolutionDir)\..\libs\openal-soft-1.15.1\lib\Win32\Release;$(SolutionDir)\..\libs\bullet-2.82-r2704\lib\Release;$(LibraryPath) + $(BOOST_ROOT);$(SolutionDir)\..\src;$(SolutionDir)\..\libs;$(SolutionDir)\..\libs\glew-1.10.0\include;$(SolutionDir)\..\libs\glfw-3.0.4\include;$(SolutionDir)\..\libs\glm-0.9.5.3;$(SolutionDir)\..\libs\openal-soft-1.15.1\include;$(SolutionDir)\..\libs\bullet-2.82-r2704\src;$(SolutionDir)\..\libs\SOIL\src;$(IncludePath) + $(BOOST_ROOT)\lib32-msvc-12.0;$(SolutionDir)\..\libs\glfw-3.0.4\lib\Release;$(SolutionDir)\..\libs\glew-1.10.0\lib\Release\Win32;$(SolutionDir)\..\libs\openal-soft-1.15.1\lib\Win32\Release;$(SolutionDir)\..\libs\bullet-2.82-r2704\lib\Release;$(SolutionDir)\..\libs\SOIL\lib\Release;$(LibraryPath) $(SolutionDir)\..\bin\$(Configuration)\ $(SolutionDir)\..\obj\$(Configuration)\ @@ -56,11 +56,14 @@ Disabled true _CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) + Create + PrecompiledHeader.h true - OpenAL32.lib;opengl32.lib;glu32.lib;glew32d.lib;glfw3dll.lib;BulletCollision_Debug.lib;%(AdditionalDependencies) + OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32d.lib;glfw3dll.lib;BulletCollision_Debug.lib;%(AdditionalDependencies) + @@ -70,22 +73,82 @@ true true _CRT_SECURE_NO_WARNINGS;_MBCS;%(PreprocessorDefinitions) + Create + PrecompiledHeader.h true true true - OpenAL32.lib;opengl32.lib;glu32.lib;glew32.lib;glfw3dll.lib;BulletCollision.lib;%(AdditionalDependencies) + OpenAL32.lib;opengl32.lib;glu32.lib;SOIL.lib;glew32.lib;glfw3dll.lib;BulletCollision.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vs12/Returngeance/Returngeance.vcxproj.filters b/vs12/Returngeance/Returngeance.vcxproj.filters index be5cb7e..5208aa9 100755 --- a/vs12/Returngeance/Returngeance.vcxproj.filters +++ b/vs12/Returngeance/Returngeance.vcxproj.filters @@ -2,20 +2,144 @@ + + + + + + + + + + + + + Systems + + + Systems + {ce43847c-9745-46d2-b000-069af4882886} + + {8974329a-5c12-4b94-86e7-5931555bc129} + + + {e3f795ca-331e-4905-b423-93f651d93c09} + + + {1a6674dd-e1ce-4a28-a6e8-3f28468bb2f0} + - + + + + + + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + + Components + + Util - + Util - - + + + + + + + + + + + + + Systems + + + Systems + + + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + + + Shaders + \ No newline at end of file