diff --git a/src/Component.h b/src/Component.h index 21d59f6..05e0628 100755 --- a/src/Component.h +++ b/src/Component.h @@ -7,6 +7,8 @@ struct Component { EntityID Entity; + + virtual Component* Clone() const = 0; }; class ComponentFactory : public Factory { }; diff --git a/src/Components/BoxShape.h b/src/Components/BoxShape.h index dc836ec..a8aed66 100644 --- a/src/Components/BoxShape.h +++ b/src/Components/BoxShape.h @@ -14,6 +14,8 @@ struct BoxShape : Component float Width; float Height; float Depth; + + virtual BoxShape* Clone() const override { return new BoxShape(*this); } }; } diff --git a/src/Components/Camera.h b/src/Components/Camera.h index d30c537..fb3f7ef 100755 --- a/src/Components/Camera.h +++ b/src/Components/Camera.h @@ -17,6 +17,8 @@ struct Camera : Component float FOV; float NearClip; float FarClip; + + virtual Camera* Clone() const override { return new Camera(*this); } }; } diff --git a/src/Components/DirectionalLight.h b/src/Components/DirectionalLight.h index ee2dd72..1d7de1e 100755 --- a/src/Components/DirectionalLight.h +++ b/src/Components/DirectionalLight.h @@ -13,6 +13,8 @@ struct DirectionalLight : Component float MaxRange; float SpecularIntensity; Color Color; + + virtual DirectionalLight* Clone() const override { return new DirectionalLight(*this); } }; } diff --git a/src/Components/FreeSteering.h b/src/Components/FreeSteering.h index a972eaf..ba40534 100755 --- a/src/Components/FreeSteering.h +++ b/src/Components/FreeSteering.h @@ -9,6 +9,8 @@ struct FreeSteering : Component { FreeSteering() : Speed(35) { } float Speed; + + virtual FreeSteering* Clone() const override { return new FreeSteering(*this); } }; } diff --git a/src/Components/HingeConstraint.h b/src/Components/HingeConstraint.h index 96f0db3..367d73a 100644 --- a/src/Components/HingeConstraint.h +++ b/src/Components/HingeConstraint.h @@ -11,6 +11,8 @@ namespace Components EntityID LinkedEntity; glm::vec3 Pivot; glm::vec3 Axis; + + virtual HingeConstraint* Clone() const override { return new HingeConstraint(*this); } }; } diff --git a/src/Components/Input.h b/src/Components/Input.h index b1c11b5..15cb286 100755 --- a/src/Components/Input.h +++ b/src/Components/Input.h @@ -18,6 +18,8 @@ struct Input : Component std::array LastMouseState; float dX, dY; float WheelDelta; + + virtual Input* Clone() const override { return new Input(*this); } }; } diff --git a/src/Components/MeshShape.h b/src/Components/MeshShape.h index 64084ab..81ea9c0 100644 --- a/src/Components/MeshShape.h +++ b/src/Components/MeshShape.h @@ -11,6 +11,8 @@ namespace Components struct MeshShape : Component { std::string ResourceName; + + virtual MeshShape* Clone() const override { return new MeshShape(*this); } }; } diff --git a/src/Components/Model.h b/src/Components/Model.h index ad3b4f3..cacfe17 100755 --- a/src/Components/Model.h +++ b/src/Components/Model.h @@ -16,6 +16,8 @@ struct Model : Component Color Color; bool Visible; bool ShadowCaster; + + virtual Model* Clone() const override { return new Model(*this); } }; } diff --git a/src/Components/Particle.h b/src/Components/Particle.h new file mode 100644 index 0000000..d08b1a7 --- /dev/null +++ b/src/Components/Particle.h @@ -0,0 +1,25 @@ +#ifndef Components_Particle_h__ +#define Components_Particle_h__ + +#include "System.h" +#include "Component.h" +#include "Color.h" +#include + +namespace Components +{ + + struct Particle : Component + { + std::vector ColorSpectrum; + std::vector ScaleSpectrum; + double LifeTime; + std::vector VelocitySpectrum; + std::vector AngularVelocitySpectrum; + std::vector OrientationSpectrum; //Keep? + + virtual Particle* Clone() const override { return new Particle(*this); } + }; + +} +#endif // !Components_Particle_h__ \ No newline at end of file diff --git a/src/Components/ParticleEmitter.h b/src/Components/ParticleEmitter.h index 06a1658..bb57c99 100755 --- a/src/Components/ParticleEmitter.h +++ b/src/Components/ParticleEmitter.h @@ -5,20 +5,39 @@ #include "Color.h" #include +namespace Systems { class ParticleSystem; } + namespace Components { struct ParticleEmitter : Component { - int ParticleTemplate; + friend class Systems::ParticleSystem; + + ParticleEmitter() + : SpawnFrequency(0) + , SpawnCount(0) + , SpreadAngle(0) + , LifeTime(0) + , TimeSinceLastSpawn(0) { } + + EntityID ParticleTemplate; float SpawnFrequency; + float Speed; int SpawnCount; std::vector ColorSpectrum; - std::vector ScaleSpectrum; + std::vector ScaleSpectrum; float SpreadAngle; - float LifeTime; - std::vector VelocitySpectrum; - std::vector AngularVelocitySpectrum; + double LifeTime; + bool UseGoalVelocity; + glm::vec3 GoalVelocity; + std::vector AngularVelocitySpectrum; + std::vector OrientationSpectrum; //Keep? + + virtual ParticleEmitter* Clone() const override { return new ParticleEmitter(*this); } + +private: + double TimeSinceLastSpawn; }; } diff --git a/src/Components/Physics.h b/src/Components/Physics.h index df819c4..35844b5 100644 --- a/src/Components/Physics.h +++ b/src/Components/Physics.h @@ -13,6 +13,8 @@ struct Physics : Component float Mass; bool Static; + + virtual Physics* Clone() const override { return new Physics(*this); } }; } diff --git a/src/Components/PointLight.h b/src/Components/PointLight.h index a7a5d4a..248fec6 100755 --- a/src/Components/PointLight.h +++ b/src/Components/PointLight.h @@ -16,6 +16,8 @@ struct PointLight : Component float constantAttenuation, linearAttenuation, quadraticAttenuation; float spotExponent; Color color; + + virtual PointLight* Clone() const override { return new PointLight(*this); } }; } diff --git a/src/Components/SoundEmitter.h b/src/Components/SoundEmitter.h index b4c74ee..05c5f15 100755 --- a/src/Components/SoundEmitter.h +++ b/src/Components/SoundEmitter.h @@ -17,6 +17,8 @@ struct SoundEmitter : Component float Pitch; bool Loop; std::string Path; + + virtual SoundEmitter* Clone() const override { return new SoundEmitter(*this); } }; } diff --git a/src/Components/SphereShape.h b/src/Components/SphereShape.h index afc717b..20ab74d 100644 --- a/src/Components/SphereShape.h +++ b/src/Components/SphereShape.h @@ -12,6 +12,8 @@ struct SphereShape : Component : Radius(1.f){ } float Radius; + + virtual SphereShape* Clone() const override { return new SphereShape(*this); } }; } diff --git a/src/Components/Sprite.h b/src/Components/Sprite.h index f54d3d0..29c930f 100755 --- a/src/Components/Sprite.h +++ b/src/Components/Sprite.h @@ -13,6 +13,8 @@ struct Sprite : Component { std::string SpriteFile; Color Color; + + virtual Sprite* Clone() const override { return new Sprite(*this); } }; } diff --git a/src/Components/TankSteering.h b/src/Components/TankSteering.h index 963d81c..c9184b3 100644 --- a/src/Components/TankSteering.h +++ b/src/Components/TankSteering.h @@ -7,7 +7,7 @@ namespace Components { struct TankSteering : Component { - + TankSteering* Clone() const override { return new TankSteering(*this); } }; } diff --git a/src/Components/Template.h b/src/Components/Template.h index 4bcb25c..613622c 100755 --- a/src/Components/Template.h +++ b/src/Components/Template.h @@ -6,7 +6,12 @@ namespace Components { -struct Template : Component { }; +struct Template + : public Component +{ + virtual Template* Clone() const override { return nullptr; } +}; } + #endif // !Components_Template_h__ \ No newline at end of file diff --git a/src/Components/Transform.h b/src/Components/Transform.h index 2bfd58d..26b701e 100755 --- a/src/Components/Transform.h +++ b/src/Components/Transform.h @@ -6,7 +6,7 @@ namespace Components { -struct Transform : Component +struct Transform : public Component { Transform() : Scale(glm::vec3(1.f)) { } @@ -15,6 +15,8 @@ struct Transform : Component glm::quat Orientation; glm::vec3 Velocity; glm::vec3 Scale; + + virtual Transform* Clone() const override { return new Transform(*this); } }; } diff --git a/src/Components/Vehicle.h b/src/Components/Vehicle.h index 6522a1f..2957df5 100644 --- a/src/Components/Vehicle.h +++ b/src/Components/Vehicle.h @@ -23,6 +23,8 @@ struct Vehicle : Component float TopSpeed; float MaxSpeedFullSteeringAngle; float SpringDamping; + + Vehicle* Clone() const override { return new Vehicle(*this); } }; } diff --git a/src/Components/Wheel.h b/src/Components/Wheel.h index 533d193..be3638b 100644 --- a/src/Components/Wheel.h +++ b/src/Components/Wheel.h @@ -36,6 +36,8 @@ struct Wheel : Component private: int ID; glm::quat OriginalOrientation; + + Wheel* Clone() const override { return new Wheel(*this); } }; } diff --git a/src/Components/WheelPair.h b/src/Components/WheelPair.h index 0173e30..4e74a82 100644 --- a/src/Components/WheelPair.h +++ b/src/Components/WheelPair.h @@ -9,6 +9,8 @@ namespace Components struct WheelPair : Component { // Flag for pair wheels + + virtual WheelPair* Clone() const override { return new WheelPair(*this); } }; } diff --git a/src/GameWorld.cpp b/src/GameWorld.cpp index 411d27f..c3f653e 100755 --- a/src/GameWorld.cpp +++ b/src/GameWorld.cpp @@ -85,18 +85,7 @@ void GameWorld::Initialize() CommitEntity(ground); } - { - auto camera = CreateEntity(); - auto transform = AddComponent(camera, "Transform"); - transform->Position.z = 20.f; - transform->Position.y = 10.f; - transform->Orientation = glm::quat(glm::vec3(-glm::pi() / 8.f, 0.f, 0.f)); - auto cameraComp = AddComponent(camera, "Camera"); - cameraComp->FarClip = 2000.f; - AddComponent(camera, "Input"); - auto freeSteering = AddComponent(camera, "FreeSteering"); - CommitEntity(camera); - } + /*{ auto jeep = CreateEntity(); @@ -511,6 +500,30 @@ void GameWorld::Initialize() CommitEntity(shape); } CommitEntity(wheel); + + auto entity = CreateEntity(tank); + auto transformComponent = AddComponent(entity, "Transform"); + transformComponent->Position = glm::vec3(2,-1.7,2.0); + transformComponent->Scale = glm::vec3(3,3,3); + transformComponent->Orientation = glm::angleAxis(glm::pi()/2, glm::vec3(1,0,0)); + auto emitterComponent = AddComponent(entity, "ParticleEmitter"); + emitterComponent->SpawnCount = 2; + emitterComponent->SpawnFrequency = 0.005; + emitterComponent->SpreadAngle = glm::pi(); + emitterComponent->UseGoalVelocity = false; + emitterComponent->LifeTime = 0.5; + //emitterComponent->AngularVelocitySpectrum.push_back(glm::pi() / 100); + emitterComponent->ScaleSpectrum.push_back(glm::vec3(0.05)); + CommitEntity(entity); + + auto particleEntity = CreateEntity(entity); + auto TEMP = AddComponent(particleEntity, "Transform"); + TEMP->Scale = glm::vec3(0); + auto spriteComponent = AddComponent(particleEntity, "Sprite"); + spriteComponent->SpriteFile = "Models/Textures/Sprites/Dust.png"; + emitterComponent->ParticleTemplate = particleEntity; + + CommitEntity(particleEntity); } { @@ -571,11 +584,50 @@ void GameWorld::Initialize() CommitEntity(shape); } CommitEntity(wheel); + + auto entity = CreateEntity(tank); + auto transformComponent = AddComponent(entity, "Transform"); + transformComponent->Position = glm::vec3(-2,-1.7,2.0); + transformComponent->Scale = glm::vec3(3,3,3); + transformComponent->Orientation = glm::angleAxis(glm::pi()/2, glm::vec3(1,0,0)); + auto emitterComponent = AddComponent(entity, "ParticleEmitter"); + emitterComponent->SpawnCount = 2; + emitterComponent->SpawnFrequency = 0.005; + emitterComponent->SpreadAngle = glm::pi(); + emitterComponent->UseGoalVelocity = false; + emitterComponent->LifeTime = 0.5; + //emitterComponent->AngularVelocitySpectrum.push_back(glm::pi() / 100); + emitterComponent->ScaleSpectrum.push_back(glm::vec3(0.05)); + CommitEntity(entity); + + auto particleEntity = CreateEntity(entity); + auto TEMP = AddComponent(particleEntity, "Transform"); + TEMP->Scale = glm::vec3(0); + auto spriteComponent = AddComponent(particleEntity, "Sprite"); + spriteComponent->SpriteFile = "Models/Textures/Sprites/Dust.png"; + emitterComponent->ParticleTemplate = particleEntity; + + CommitEntity(particleEntity); } CommitEntity(tank); + { + auto camera = CreateEntity(tank); + auto transform = AddComponent(camera, "Transform"); + transform->Position.z = 20.f; + transform->Position.y = 7.f; + //transform->Orientation = glm::quat(glm::vec3(-glm::pi() / 8.f, 0.f, 0.f)); + transform->Orientation = glm::angleAxis(glm::pi() / 100, glm::vec3(1,0,0)); + auto cameraComp = AddComponent(camera, "Camera"); + cameraComp->FarClip = 2000.f; + AddComponent(camera, "Input"); + auto freeSteering = AddComponent(camera, "FreeSteering"); + CommitEntity(camera); + } } + + /* for(int i = 0; i < 10; i++) { @@ -663,6 +715,7 @@ void GameWorld::Initialize() GetSystem("SoundSystem")->PlaySound(emitter); CommitEntity(entity); }*/ + } void GameWorld::Update(double dt) @@ -683,7 +736,7 @@ void GameWorld::RegisterSystems() m_SystemFactory.Register("InputSystem", [this]() { return new Systems::InputSystem(this, m_EventBroker); }); m_SystemFactory.Register("DebugSystem", [this]() { return new Systems::DebugSystem(this, m_EventBroker); }); //m_SystemFactory.Register("CollisionSystem", [this]() { return new Systems::CollisionSystem(this); }); - ////m_SystemFactory.Register("ParticleSystem", [this]() { return new Systems::ParticleSystem(this); }); + m_SystemFactory.Register("ParticleSystem", [this]() { return new Systems::ParticleSystem(this, m_EventBroker); }); //m_SystemFactory.Register("PlayerSystem", [this]() { return new Systems::PlayerSystem(this); }); m_SystemFactory.Register("FreeSteeringSystem", [this]() { return new Systems::FreeSteeringSystem(this, m_EventBroker); }); m_SystemFactory.Register("TankSteeringSystem", [this]() { return new Systems::TankSteeringSystem(this, m_EventBroker); }); @@ -699,7 +752,7 @@ void GameWorld::AddSystems() AddSystem("InputSystem"); AddSystem("DebugSystem"); //AddSystem("CollisionSystem"); - ////AddSystem("ParticleSystem"); + AddSystem("ParticleSystem"); //AddSystem("PlayerSystem"); AddSystem("FreeSteeringSystem"); AddSystem("TankSteeringSystem"); diff --git a/src/GameWorld.h b/src/GameWorld.h index e924cc0..27a36dd 100755 --- a/src/GameWorld.h +++ b/src/GameWorld.h @@ -9,7 +9,7 @@ #include "Systems/InputSystem.h" #include "Systems/DebugSystem.h" //#include "Systems/LevelGenerationSystem.h" -//#include "Systems/ParticleSystem.h" +#include "Systems/ParticleSystem.h" //#include "Systems/PlayerSystem.h" #include "Systems/FreeSteeringSystem.h" #include "Systems/TankSteeringSystem.h" @@ -22,6 +22,7 @@ #include "Components/Input.h" #include "Components/Model.h" #include "Components/ParticleEmitter.h" +#include "Components/Particle.h" #include "Components/PointLight.h" #include "Components/SoundEmitter.h" #include "Components/Sprite.h" diff --git a/src/Physics/VehicleSetup.h b/src/Physics/VehicleSetup.h index 83647bb..7f78204 100644 --- a/src/Physics/VehicleSetup.h +++ b/src/Physics/VehicleSetup.h @@ -43,6 +43,7 @@ public: { Components::Wheel* WheelComponent; Components::Transform* TransformComponent; + }; std::vector m_Wheels; diff --git a/src/Renderer.cpp b/src/Renderer.cpp index 3e30e30..2905891 100755 --- a/src/Renderer.cpp +++ b/src/Renderer.cpp @@ -267,6 +267,31 @@ void Renderer::DrawScene() } } + for (auto tuple : TexturesToRender) + { + Texture* texture; + glm::mat4 modelMatrix; + glm::mat4 billboardMatrix; + std::tie(texture, modelMatrix, billboardMatrix) = tuple; + + //MVP = cameraMatrix * glm::inverse(glm::toMat4(m_Camera->Orientation()) * modelMatrix ); + MVP = cameraMatrix * modelMatrix * billboardMatrix; + + 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())); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, *texture); + glBindVertexArray(m_ScreenQuad); + glDrawArrays(GL_TRIANGLES, 0, 6); + } + + + + #ifdef DEBUG // Debug draw model normals if (m_DrawNormals) @@ -318,6 +343,8 @@ void Renderer::DrawShadowMap() glDrawArrays(GL_TRIANGLES, texGroup.StartIndex, texGroup.EndIndex - texGroup.StartIndex + 1); } } + + } void Renderer::DrawDebugShadowMap() @@ -376,6 +403,24 @@ void Renderer::AddModelToDraw(Model* model, glm::vec3 position, glm::quat orient ModelsToRender.push_back(std::make_tuple(model, modelMatrix, visible, shadowCaster)); } +void Renderer::AddTextureToDraw(Texture* texture, glm::vec3 position, glm::quat orientation, glm::vec3 scale) +{ + glm::mat4 modelMatrix = glm::translate(glm::mat4(), position) * glm::toMat4(orientation) * glm::scale(scale); + + glm::vec3 camToParticle = glm::normalize(m_Camera->Position() - position); + glm::vec3 up = glm::vec3(0,1,0); + glm::vec3 rightVec = glm::normalize(glm::cross(up, camToParticle)); + glm::vec3 up2 = glm::normalize(glm::cross(camToParticle, rightVec)); + + glm::mat4 billboardMatrix; + billboardMatrix[0] = glm::vec4(rightVec, 0); + billboardMatrix[1] = glm::vec4(up2, 0); + billboardMatrix[2] = glm::vec4(camToParticle, 0); + //billboardMatrix[3] = glm::vec4(position, 0); + + TexturesToRender.push_back(std::make_tuple(texture, modelMatrix, billboardMatrix)); +} + void Renderer::AddPointLightToDraw( glm::vec3 _position, glm::vec3 _specular, @@ -536,6 +581,7 @@ void Renderer::ClearStuff() { AABBsToRender.clear(); ModelsToRender.clear(); + TexturesToRender.clear(); Light_position.clear(); Light_specular.clear(); Light_diffuse.clear(); diff --git a/src/Renderer.h b/src/Renderer.h index 3c2d957..26891d6 100755 --- a/src/Renderer.h +++ b/src/Renderer.h @@ -25,6 +25,7 @@ public: int Height() const { return m_Height; } std::list> ModelsToRender; + std::list> TexturesToRender; int Lights; std::vector Light_position; std::vector Light_specular; @@ -42,6 +43,7 @@ public: void DrawText(); void AddModelToDraw(Model* model, glm::vec3 position, glm::quat orientation, glm::vec3 scale, bool visible, bool shadowCaster); + void AddTextureToDraw(Texture* texture, glm::vec3 position, glm::quat orientation, glm::vec3 scale); void AddTextToDraw(); void AddPointLightToDraw( glm::vec3 _position, diff --git a/src/Systems/FreeSteeringSystem.cpp b/src/Systems/FreeSteeringSystem.cpp index 8373c80..d59b475 100755 --- a/src/Systems/FreeSteeringSystem.cpp +++ b/src/Systems/FreeSteeringSystem.cpp @@ -56,19 +56,19 @@ bool Systems::FreeSteeringSystem::FreeSteeringInputController::OnCommand(const E } else if (event.Command == "+cam_right") { - Movement.x += 1.f; + Movement.x -= 1.f; } else if (event.Command == "-cam_right") { - Movement.x -= 1.f; + Movement.x += 1.f; } else if (event.Command == "+cam_left") { - Movement.x += -1.f; + Movement.x -= -1.f; } else if (event.Command == "-cam_left") { - Movement.x -= -1.f; + Movement.x += -1.f; } else if (event.Command == "+up") { diff --git a/src/Systems/ParticleSystem.cpp b/src/Systems/ParticleSystem.cpp new file mode 100644 index 0000000..0882f9d --- /dev/null +++ b/src/Systems/ParticleSystem.cpp @@ -0,0 +1,208 @@ +#include "PrecompiledHeader.h" +#include "ParticleSystem.h" + + +#include "World.h" + +void Systems::ParticleSystem::Initialize() +{ + m_TransformSystem = m_World->GetSystem("TransformSystem"); +} + +void Systems::ParticleSystem::Update(double dt) +{ + +} + +void Systems::ParticleSystem::UpdateEntity(double dt, EntityID entity, EntityID parent) +{ + auto transformComponent = m_World->GetComponent(entity, "Transform"); + if(!transformComponent) + return; + + auto emitterComponent = m_World->GetComponent(entity, "ParticleEmitter"); + if(emitterComponent) + { + emitterComponent->TimeSinceLastSpawn += dt; + auto emitterTransformComponent = m_World->GetComponent(entity, "Transform"); + if(emitterComponent->TimeSinceLastSpawn > emitterComponent->SpawnFrequency) + { + SpawnParticles(entity); + emitterComponent->TimeSinceLastSpawn = 0; + } + + std::list::iterator it; + for(it = m_ParticleEmitter[entity].begin(); it != m_ParticleEmitter[entity].end();) + { + EntityID particleID = (it)->ParticleID; + auto transformComponent = m_World->GetComponent(particleID, "Transform"); + auto particleComponent = m_World->GetComponent(particleID, "Particle"); + + double timeLived = glfwGetTime() - it->SpawnTime; + if(timeLived > particleComponent->LifeTime) + { + m_World->RemoveEntity(particleID); + it = m_ParticleEmitter[entity].erase(it); + } + else + { + // FIX: calculate once + float timeProgress = timeLived / particleComponent->LifeTime; + // ColorInterpolation(timeProgress, particleComponent->ColorSpectrum, color); + // Scale interpolation + if(particleComponent->ScaleSpectrum.size() > 1) + VectorInterpolation(timeProgress, particleComponent->ScaleSpectrum, transformComponent->Scale); + // Velocity interpolation + if(particleComponent->VelocitySpectrum.size() > 1) + VectorInterpolation(timeProgress, particleComponent->VelocitySpectrum, transformComponent->Velocity); + + // Angular velocity interpolation + if (particleComponent->AngularVelocitySpectrum.size() != 0) + { + if(particleComponent->AngularVelocitySpectrum.size() > 1) + { + ScalarInterpolation(timeProgress, particleComponent->AngularVelocitySpectrum, it->AngularVelocity); + transformComponent->Orientation = glm::angleAxis(it->AngularVelocity, it->Orientation); + } + else + { + transformComponent->Orientation *= glm::angleAxis(it->AngularVelocity, it->Orientation); + //it->Orientation = glm::angleAxis(it->AngularVelocity, it->Orientation); + } + } + + //Angular velocity interpolation + if(particleComponent->OrientationSpectrum.size() > 1) + { + VectorInterpolation(timeProgress, particleComponent->OrientationSpectrum, it->Orientation); + glm::vec3 v1 = (particleComponent->OrientationSpectrum[0]); + glm::vec3 v2 = (it->Orientation); + glm::vec3 v3 = glm::normalize(glm::cross(v1,v2)); + float angle = glm::acos(glm::dot(v1, v2) / (glm::length(v1) * glm::length(v2))); + + transformComponent->Orientation = glm::angleAxis(angle, v3); + } + + + transformComponent->Position += transformComponent->Velocity * (float)dt; + + it++; + } + } + } +} + +void Systems::ParticleSystem::RegisterComponents(ComponentFactory* cf) +{ + cf->Register("ParticleEmitter", []() { return new Components::ParticleEmitter(); }); + cf->Register("Particle", []() { return new Components::Particle(); }); +} + + +void Systems::ParticleSystem::SpawnParticles(EntityID emitterID) +{ + auto emitterComponent = m_World->GetComponent(emitterID, "ParticleEmitter"); + auto emitterTransform = m_World->GetComponent(emitterID, "Transform"); + glm::vec3 emitterPos = m_TransformSystem->AbsolutePosition(emitterID); + glm::quat emitterOrientation = emitterTransform->Orientation; + + float tempSpeed = 4; + glm::vec3 speed = glm::vec3(tempSpeed); + + for(int i = 0; i < emitterComponent->SpawnCount; i++) + { + auto ent = m_World->CloneEntity(emitterComponent->ParticleTemplate); + + auto particleTransform = m_World->GetComponent(ent, "Transform"); + particleTransform->Position = emitterPos; + + particleTransform->Orientation = emitterOrientation; + //The emitter's orientation as "start value" times the default direction for emitter. Times the speed, and then rotate on x and y axis with the randomized spread angle. + float spreadAngle = emitterComponent->SpreadAngle; + particleTransform->Velocity = emitterOrientation * glm::vec3(0, 0, -1) * speed * + glm::normalize(glm::angleAxis(RandomizeAngle(spreadAngle), glm::vec3(1, 0, 0))) * + glm::normalize(glm::angleAxis(RandomizeAngle(spreadAngle), glm::vec3(0, 1, 0))) * + glm::normalize(glm::angleAxis(RandomizeAngle(spreadAngle), glm::vec3(0, 0, 1))); + + auto particle = m_World->AddComponent(ent, "Particle"); + particle->LifeTime = emitterComponent->LifeTime; + particle->ScaleSpectrum = emitterComponent->ScaleSpectrum; + particle->VelocitySpectrum.push_back(particleTransform->Velocity); + + if (emitterComponent->ScaleSpectrum.size() > 0) + { + if (emitterComponent->ScaleSpectrum.size() > 1) + { + particle->ScaleSpectrum = emitterComponent->ScaleSpectrum; + } + else + { + particleTransform->Scale = emitterComponent->ScaleSpectrum[0]; + } + } + else + { + particleTransform->Scale = glm::vec3(1, 1, 1); + } + + if(emitterComponent->UseGoalVelocity) + particle->VelocitySpectrum.push_back(emitterComponent->GoalVelocity); + particle->OrientationSpectrum = emitterComponent->OrientationSpectrum; + if(particle->OrientationSpectrum.size() != 0) + particleTransform->Orientation = glm::angleAxis(0.f, particle->OrientationSpectrum[0]); + particle->AngularVelocitySpectrum = emitterComponent->AngularVelocitySpectrum; + + + ParticleData data; + data.ParticleID = ent; + data.SpawnTime = glfwGetTime(); + if (particle->AngularVelocitySpectrum.size() != 0) + data.AngularVelocity = particle->AngularVelocitySpectrum[0]; + if (particle->OrientationSpectrum.size() != 0) + data.Orientation = particle->OrientationSpectrum[0]; + else data.Orientation = emitterOrientation * glm::vec3(0,0,-1); + + m_ParticleEmitter[emitterID].push_back(data); + } +} + +//Randomizes between -spreadAngle/2 and spreadAngle/2 +float Systems::ParticleSystem::RandomizeAngle(float spreadAngle) +{ + return ((float)rand() / ((float)RAND_MAX + 1) * spreadAngle) - spreadAngle/2; +} + +//Interpolates the velocity of the particle +void Systems::ParticleSystem::VectorInterpolation(double timeProgress, std::vector spectrum, glm::vec3 &v) +{ + float dAxisValue = glm::abs(spectrum[0].x - spectrum[1].x); + if(spectrum[0].x > spectrum[1].x) + dAxisValue *= -1; + v.x = spectrum[0].x + dAxisValue * timeProgress; + dAxisValue = glm::abs(spectrum[0].y - spectrum[1].y); + if (spectrum[0].y > spectrum[1].y) + dAxisValue *= -1; + v.y = spectrum[0].y + dAxisValue * timeProgress; + dAxisValue = glm::abs(spectrum[0].z - spectrum[1].z); + if(spectrum[0].z > spectrum[1].z) + dAxisValue *= -1; + v.z = spectrum[0].z + dAxisValue * timeProgress; +} + +// void Systems::ParticleSystem::ColorInterpolation(double timeProgress, std::vector spectrum, Color &c) +// { +// float dColor = glm::abs(spectrum[0].r - spectrum[1].r); +// c.r = spectrum[0].r + dColor * timeProgress; +// dColor = glm::abs(spectrum[0].g - spectrum[1].g); +// c.g = spectrum[0].g + dColor * timeProgress; +// dColor = glm::abs(spectrum[0].b - spectrum[1].b); +// c.b = spectrum[0].b + dColor * timeProgress; +// } + +void Systems::ParticleSystem::ScalarInterpolation(double timeProgress, std::vector spectrum, float &alpha) +{ + float dAlpha = glm::abs(spectrum[0] - spectrum[1]); + if(spectrum[0] > spectrum[1]) + dAlpha *= -1; + alpha = spectrum[0] + dAlpha * timeProgress; +} \ No newline at end of file diff --git a/src/Systems/ParticleSystem.h b/src/Systems/ParticleSystem.h new file mode 100644 index 0000000..06cbe63 --- /dev/null +++ b/src/Systems/ParticleSystem.h @@ -0,0 +1,54 @@ +#ifndef ParticleSystem_h__ +#define ParticleSystem_h__ + +#include "System.h" +#include "Systems/TransformSystem.h" +#include "Components/Transform.h" +#include "Components/ParticleEmitter.h" +#include "Components/Particle.h" +#include "Components/Model.h" +#include "Components/PointLight.h" +#include "Color.h" +#include + +namespace Systems +{ + + struct ParticleData + { + EntityID ParticleID; + double SpawnTime; + float AngularVelocity; + glm::vec3 Orientation; + Color color; + }; + +class ParticleSystem : public System +{ +public: + ParticleSystem(World* world, std::shared_ptr<::EventBroker> eventBroker) + : System(world, eventBroker) { } + + void RegisterComponents(ComponentFactory* cf) override; + void Update(double dt) override; + void UpdateEntity(double dt, EntityID entity, EntityID parent) override; + void Initialize() override; +private: + void SpawnParticles(EntityID emitterID); + float RandomizeAngle(float spreadAngle); + //void ScaleInterpolation(double timeProgress, std::vector spectrum, glm::vec3 &scale); + void VectorInterpolation(double timeProgress, std::vector spectrum, glm::vec3 &velocity); + //void ColorInterpolation(double timeProgress, std::vector spectrum, Color &color); + void ScalarInterpolation(double timeProgress, std::vector spectrum, float &alpha); + void Billboard(); + std::map> m_ParticleEmitter; + std::map m_TimeSinceLastSpawn; + std::shared_ptr m_TransformSystem; + + +}; + +} + + +#endif // !ParticleSystem_h__ \ No newline at end of file diff --git a/src/Systems/RenderSystem.cpp b/src/Systems/RenderSystem.cpp index 23c8274..35a57d8 100755 --- a/src/Systems/RenderSystem.cpp +++ b/src/Systems/RenderSystem.cpp @@ -55,6 +55,17 @@ void Systems::RenderSystem::UpdateEntity(double dt, EntityID entity, EntityID pa m_Renderer->GetCamera()->NearClip(cameraComponent->NearClip); m_Renderer->GetCamera()->FarClip(cameraComponent->FarClip); } + + auto spriteComponent = m_World->GetComponent(entity, "Sprite"); + if(spriteComponent != nullptr) + { + //TEMP + Texture* texture = m_World->GetResourceManager()->Load("Texture", spriteComponent->SpriteFile); + //glBindTexture(GL_TEXTURE_2D, texture); + auto transform = m_World->GetComponent(spriteComponent->Entity, "Transform"); + glm::quat orientation2D = glm::angleAxis(glm::eulerAngles(transform->Orientation).z, glm::vec3(0, 0, -1)); + m_Renderer->AddTextureToDraw(texture, transform->Position, orientation2D, transform->Scale); + } } void Systems::RenderSystem::Initialize() diff --git a/src/World.cpp b/src/World.cpp index d8f2a0a..01713ab 100755 --- a/src/World.cpp +++ b/src/World.cpp @@ -90,6 +90,7 @@ void World::ProcessEntityRemovals() for (auto entity : m_EntitiesToRemove) { m_EntityParents.erase(entity); + m_EntityChildren.erase(entity); // Remove components for (auto pair : m_EntityComponents[entity]) { @@ -113,7 +114,8 @@ void World::ProcessEntityRemovals() EntityID World::CreateEntity(EntityID parent /*= 0*/) { EntityID newEntity = GenerateEntityID(); - m_EntityParents.insert(std::pair(newEntity, parent)); + m_EntityParents[newEntity] = parent; + m_EntityChildren[parent].push_back(newEntity); return newEntity; } @@ -144,7 +146,58 @@ void World::CommitEntity(EntityID entity) } } +void World::AddComponent(EntityID entity, std::string componentType, std::shared_ptr component) +{ + 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); + } +} + void World::AddSystem(std::string systemType) { m_Systems[systemType] = std::shared_ptr(m_SystemFactory.Create(systemType)); } + +EntityID World::CloneEntity(EntityID entity, EntityID parent /* = 0 */) +{ + int clone = CreateEntity(parent); + + for (auto pair : m_EntityComponents[entity]) + { + auto type = pair.first; + auto component = std::shared_ptr(pair.second->Clone()); + if (component != nullptr) + { + AddComponent(clone, type, component); + } + } + + auto itChildren = m_EntityChildren.find(entity); + if (itChildren != m_EntityChildren.end()) + { + for (EntityID child : itChildren->second) + { + CloneEntity(child, clone); + } + } + + return clone; +} + +std::list World::GetEntityChildren(EntityID entity) +{ + auto it = m_EntityChildren.find(entity); + if (it == m_EntityChildren.end()) + { + return std::list(); + } + else + { + return it->second; + } +} diff --git a/src/World.h b/src/World.h index 7ce77db..0c4d76e 100755 --- a/src/World.h +++ b/src/World.h @@ -37,6 +37,7 @@ public: std::shared_ptr GetSystem(std::string systemType); EntityID CreateEntity(EntityID parent = 0); + EntityID CloneEntity(EntityID entity, EntityID parent = 0); void RemoveEntity(EntityID entity); @@ -44,6 +45,7 @@ public: EntityID GetEntityParent(EntityID entity); EntityID GetEntityBaseParent(EntityID entity); + std::list GetEntityChildren(EntityID entity); template T GetProperty(EntityID entity, std::string property) @@ -95,13 +97,16 @@ protected: 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_EntityParents; // child -> parent + std::unordered_map> m_EntityChildren; // parent -> child + std::unordered_map> m_EntityProperties; std::unordered_map>> m_ComponentsOfType; std::unordered_map>> m_EntityComponents; + // Internal: Add a component to an entity + void AddComponent(EntityID entity, std::string componentType, std::shared_ptr component); + std::list m_EntitiesToRemove; void ProcessEntityRemovals(); @@ -133,14 +138,8 @@ std::shared_ptr World::AddComponent(EntityID entity, std::string componentTyp 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); - } + AddComponent(entity, componentType, component); + return component; } @@ -148,7 +147,14 @@ std::shared_ptr World::AddComponent(EntityID entity, std::string componentTyp template T* World::GetComponent(EntityID entity, std::string componentType) { + + /*auto it0 = m_EntityComponents.find(entity); + + if (it0 == m_EntityComponents.end()) + return nullptr;*/ + auto components = m_EntityComponents[entity]; + auto it = components.find(componentType); if (it != components.end()) { diff --git a/vs11/Returngeance/Returngeance.vcxproj b/vs11/Returngeance/Returngeance.vcxproj index 4b16aef..8d2c9e7 100755 --- a/vs11/Returngeance/Returngeance.vcxproj +++ b/vs11/Returngeance/Returngeance.vcxproj @@ -112,6 +112,7 @@ + @@ -134,6 +135,7 @@ + @@ -183,6 +185,7 @@ + diff --git a/vs11/Returngeance/Returngeance.vcxproj.filters b/vs11/Returngeance/Returngeance.vcxproj.filters index 21aa2cd..f3d89c8 100755 --- a/vs11/Returngeance/Returngeance.vcxproj.filters +++ b/vs11/Returngeance/Returngeance.vcxproj.filters @@ -50,6 +50,9 @@ + + Particle System\Systems + Physics @@ -264,6 +267,12 @@ Physics\Components + + Particle System\Systems + + + Particle System\Components + GUI