summaryrefslogtreecommitdiff
path: root/engine-ocean/Game/Systems
diff options
context:
space:
mode:
authorjjesswan <jessica_wan@brown.edu>2024-04-22 21:56:26 -0400
committerjjesswan <jessica_wan@brown.edu>2024-04-22 21:56:26 -0400
commita556b45abf18f1bd509daaf63b66b7d55e9fd291 (patch)
treebc9b8a2d184c12aee236e7f9f276a34b84ca552d /engine-ocean/Game/Systems
parentcd7c76017a12bb548036571c1ff13e551369d06d (diff)
add engine version
Diffstat (limited to 'engine-ocean/Game/Systems')
-rw-r--r--engine-ocean/Game/Systems/AI/Actions/btaction.cpp6
-rw-r--r--engine-ocean/Game/Systems/AI/Actions/btaction.h17
-rw-r--r--engine-ocean/Game/Systems/AI/Actions/walkaction.cpp90
-rw-r--r--engine-ocean/Game/Systems/AI/Actions/walkaction.h29
-rw-r--r--engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp6
-rw-r--r--engine-ocean/Game/Systems/AI/Conditions/btcondition.h18
-rw-r--r--engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp43
-rw-r--r--engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h27
-rw-r--r--engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp46
-rw-r--r--engine-ocean/Game/Systems/AI/aibehaviorcomponent.h27
-rw-r--r--engine-ocean/Game/Systems/AI/btnode.cpp6
-rw-r--r--engine-ocean/Game/Systems/AI/btnode.h18
-rw-r--r--engine-ocean/Game/Systems/AI/btselector.cpp29
-rw-r--r--engine-ocean/Game/Systems/AI/btselector.h21
-rw-r--r--engine-ocean/Game/Systems/AI/btsequence.cpp30
-rw-r--r--engine-ocean/Game/Systems/AI/btsequence.h20
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp234
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h106
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp127
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h67
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp6
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h11
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp183
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h53
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp370
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h69
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp93
-rw-r--r--engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h43
-rw-r--r--engine-ocean/Game/Systems/Inventory/inventoryitem.cpp33
-rw-r--r--engine-ocean/Game/Systems/Inventory/inventoryitem.h31
-rw-r--r--engine-ocean/Game/Systems/Inventory/inventorysystem.cpp206
-rw-r--r--engine-ocean/Game/Systems/Inventory/inventorysystem.h78
-rw-r--r--engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp35
-rw-r--r--engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h34
-rw-r--r--engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp321
-rw-r--r--engine-ocean/Game/Systems/Pathfinding/pathfinder.h83
-rw-r--r--engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp6
-rw-r--r--engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h13
-rw-r--r--engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp33
-rw-r--r--engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h21
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/UIButton.h94
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp202
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp130
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/uidisplay.h67
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp6
-rw-r--r--engine-ocean/Game/Systems/UI/UITextures/uitexture.h39
-rw-r--r--engine-ocean/Game/Systems/UI/uielement.cpp6
-rw-r--r--engine-ocean/Game/Systems/UI/uielement.h40
-rw-r--r--engine-ocean/Game/Systems/UI/uisystem.cpp383
-rw-r--r--engine-ocean/Game/Systems/UI/uisystem.h89
-rw-r--r--engine-ocean/Game/Systems/aisystem.cpp6
-rw-r--r--engine-ocean/Game/Systems/aisystem.h36
-rw-r--r--engine-ocean/Game/Systems/camerasystem.cpp210
-rw-r--r--engine-ocean/Game/Systems/camerasystem.h74
-rw-r--r--engine-ocean/Game/Systems/charactercontrollersystem.cpp132
-rw-r--r--engine-ocean/Game/Systems/charactercontrollersystem.h62
-rw-r--r--engine-ocean/Game/Systems/drawsystem.cpp60
-rw-r--r--engine-ocean/Game/Systems/drawsystem.h23
-rw-r--r--engine-ocean/Game/Systems/objectcreationsystem.cpp161
-rw-r--r--engine-ocean/Game/Systems/objectcreationsystem.h82
-rw-r--r--engine-ocean/Game/Systems/physicssystem.cpp72
-rw-r--r--engine-ocean/Game/Systems/physicssystem.h30
-rw-r--r--engine-ocean/Game/Systems/system.cpp6
-rw-r--r--engine-ocean/Game/Systems/system.h17
64 files changed, 4716 insertions, 0 deletions
diff --git a/engine-ocean/Game/Systems/AI/Actions/btaction.cpp b/engine-ocean/Game/Systems/AI/Actions/btaction.cpp
new file mode 100644
index 0000000..1b35340
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Actions/btaction.cpp
@@ -0,0 +1,6 @@
+#include "btaction.h"
+
+BTAction::BTAction()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/AI/Actions/btaction.h b/engine-ocean/Game/Systems/AI/Actions/btaction.h
new file mode 100644
index 0000000..180f72c
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Actions/btaction.h
@@ -0,0 +1,17 @@
+#ifndef BTACTION_H
+#define BTACTION_H
+#include "Game/Systems/AI/btnode.h"
+
+class BTAction : public BTNode
+{
+public:
+ BTAction();
+ virtual Status update(float seconds) = 0;
+ virtual void reset() = 0;
+
+private:
+ Status m_status;
+
+};
+
+#endif // BTACTION_H
diff --git a/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp b/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp
new file mode 100644
index 0000000..6a6d116
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Actions/walkaction.cpp
@@ -0,0 +1,90 @@
+#include "walkaction.h"
+#include "Game/Components/PathfindComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "glm/glm.hpp"
+#include <memory>
+
+
+WalkAction::WalkAction(std::string entity_id,
+ std::map<std::string, BlackboardData>& global_blackboard):
+ m_global_blackboard(global_blackboard)
+{
+
+ m_entity_id = entity_id;
+ m_path.clear();
+
+ m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false;
+ m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue = false;
+ m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue = false;
+
+
+
+
+}
+
+void WalkAction::setPath(glm::vec3 entity_pos){
+ std::cout << "---------SETTING PATHH" << std::endl;
+ m_destination = m_global_blackboard["player"].locationData.currPos;
+ m_path = m_global_blackboard["navmesh"].environment->getComponent<PathfindComponent>()->getPath(glm::vec3(-0.58249, 0, -0.0210782), glm::vec3(19.5371, 0, 1.39167));
+}
+
+// only activates if the previous conditions are true
+Status WalkAction::update(float seconds){
+
+ glm::vec3 pos = m_global_blackboard[m_entity_id].locationData.currPos;
+
+ // get a path if entity is not pathfinding
+ if (!m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue &&
+ !m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue &&
+ !m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue){
+ setPath(pos);
+ m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = true;
+ m_global_blackboard[m_entity_id].conditionData["pathfound"].conditionTrue = true;
+
+ }
+
+ if (!m_path.empty()){
+ if (m_global_blackboard[m_entity_id].conditionData["onGround"].conditionTrue){
+ //std::cout << "on ground" << std::endl;
+
+ std::shared_ptr<ModelTransform> temp_mt = std::make_shared<ModelTransform>();
+ temp_mt->setPos(pos);
+ glm::vec3 v = m_path.back();//glm::vec3(m_path.back().x, pos.y, m_path.back().z);
+ glm::vec3 dir = glm::normalize(v-temp_mt->getPos());
+ temp_mt->translate(dir);
+ //std::cout << "v: (" << v.x << ", " << v.y << ", " << v.z << ")" << std::endl;
+ glm::vec3 pos_eps = v + .01f;
+ glm::vec3 neg_eps = v - .01f;
+
+ // pop if entity within a certain episilon of node
+ if (neg_eps.x < temp_mt->getPos().x < pos_eps.x &&
+ neg_eps.z < temp_mt->getPos().z < pos_eps.z){
+ m_path.pop_back();
+ }
+
+ m_global_blackboard[m_entity_id].locationData.setToPos = temp_mt->getPos();
+ }
+
+ return Status::RUNNING;
+ }
+
+ // if reached destination, then walking succeeded
+ if (pos.x == m_destination.x && pos.z == m_destination.z){
+ m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false;
+ m_global_blackboard[m_entity_id].conditionData["atDestination"].conditionTrue = true;
+ std::cout << "-reached-" << std::endl;
+ return Status::SUCCESS;
+
+ }
+
+ // otherwise
+ m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue = false;
+ return Status::FAIL;
+
+}
+
+void WalkAction::reset(){}
+void WalkAction::addChildren(BTNode *node){}
+
+
diff --git a/engine-ocean/Game/Systems/AI/Actions/walkaction.h b/engine-ocean/Game/Systems/AI/Actions/walkaction.h
new file mode 100644
index 0000000..2e24864
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Actions/walkaction.h
@@ -0,0 +1,29 @@
+#ifndef WALKACTION_H
+#define WALKACTION_H
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/Systems/AI/btnode.h"
+#include "glm/fwd.hpp"
+#include <memory>
+#include "btaction.h"
+
+class WalkAction : public BTNode
+{
+public:
+ WalkAction(std::string entity_id, std::map<std::string, BlackboardData>& global_blackboard);
+ Status update(float seconds) override;
+ void reset() override;
+ void setPath(glm::vec3 entity_pos);
+ void addChildren(BTNode *node) override;
+
+
+
+private:
+ std::vector<glm::vec3> m_path;
+ glm::vec3 m_destination;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+ std::string m_entity_id;
+};
+
+
+#endif // WALKACTION_H
diff --git a/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp b/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp
new file mode 100644
index 0000000..f4de4af
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Conditions/btcondition.cpp
@@ -0,0 +1,6 @@
+#include "btcondition.h"
+
+BTCondition::BTCondition()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/AI/Conditions/btcondition.h b/engine-ocean/Game/Systems/AI/Conditions/btcondition.h
new file mode 100644
index 0000000..6ded57b
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Conditions/btcondition.h
@@ -0,0 +1,18 @@
+#ifndef BTCONDITION_H
+#define BTCONDITION_H
+#include "Game/Systems/AI/btnode.h"
+
+
+class BTCondition : public BTNode
+{
+public:
+ BTCondition();
+ virtual Status update(float seconds) = 0;
+ virtual void reset() = 0;
+
+
+private:
+ bool m_condition;
+};
+
+#endif // BTCONDITION_H
diff --git a/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp
new file mode 100644
index 0000000..2e40ce7
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.cpp
@@ -0,0 +1,43 @@
+#include "proximitycondition.h"
+#include "Game/Components/TransformComponent.h"
+#include "glm/glm.hpp"
+#include <memory>
+
+ProximityCondition::ProximityCondition(std::string entity_id,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ float proximity):
+ m_global_blackboard(global_blackboard)
+{
+ m_proximity = proximity;
+ m_entity_id = entity_id;
+ // initialize just in case
+ m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = false;
+
+
+}
+
+// maybe can check locations from blackboard
+// pass blackboard into constructor
+// struct: positiondata --> getCurrentPos, setCurrentPos
+bool ProximityCondition::checkProximity(){
+ // unrooted distance
+ glm::vec3 aiPos = m_global_blackboard[m_entity_id].locationData.currPos;
+ glm::vec3 otherPos = m_global_blackboard["player"].locationData.currPos;
+ float distance = pow(aiPos.x-otherPos.x, 2) + pow(aiPos.y-otherPos.y, 2) + pow(aiPos.z-otherPos.z, 2);
+
+ if (distance <= m_proximity) return true;
+ return false;
+}
+
+// at every update, check if AIPos is near otherPos
+Status ProximityCondition::update(float seconds){
+ // while entity is still pathfinding, keep returning success
+ if (m_global_blackboard[m_entity_id].conditionData["isPathfinding"].conditionTrue) return Status::SUCCESS;
+ if (checkProximity() && m_global_blackboard["player"].conditionData["isJumping"].conditionTrue) return Status::SUCCESS;
+
+ return Status::FAIL;
+}
+
+
+void ProximityCondition::reset(){}
+void ProximityCondition::addChildren(BTNode *node){}
diff --git a/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h
new file mode 100644
index 0000000..e43d178
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/Conditions/proximitycondition.h
@@ -0,0 +1,27 @@
+#ifndef PROXIMITYCONDITION_H
+#define PROXIMITYCONDITION_H
+#include "Game/Components/TransformComponent.h"
+#include "btcondition.h"
+#include <memory>
+
+
+class ProximityCondition : public BTNode
+{
+public:
+ ProximityCondition(std::string entity_id,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ float proximity);
+ Status update(float seconds) override;
+ void reset() override;
+ void addChildren(BTNode *node) override;
+
+
+private:
+ bool checkProximity();
+ float m_proximity;
+ std::string m_entity_id;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+
+};
+
+#endif // PROXIMITYCONDITION_H
diff --git a/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp
new file mode 100644
index 0000000..b43ed07
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.cpp
@@ -0,0 +1,46 @@
+#include "aibehaviorcomponent.h"
+#include "Game/Systems/AI/Actions/walkaction.h"
+#include "Game/Systems/AI/Conditions/proximitycondition.h"
+#include "Game/Systems/AI/btselector.h"
+#include "Game/Systems/AI/btsequence.h"
+
+AIBehaviorComponent::AIBehaviorComponent(std::string entity_id,
+ std::map<std::string, BlackboardData>& global_blackboard):
+ m_global_blackboard(global_blackboard)
+{
+ m_entity_id = entity_id;
+ makeBehaviorTree();
+
+}
+
+void AIBehaviorComponent::makeBehaviorTree(){
+ // leaves
+ //std::unique_ptr<BTNode> walk = std::make_unique<WalkAction>(m_entity_id, m_global_blackboard);
+ BTNode *proximCond = new ProximityCondition(m_entity_id, m_global_blackboard, 20.f);
+ BTNode *walk = new WalkAction(m_entity_id, m_global_blackboard);
+
+
+// // pathfind sequence
+ BTNode *pathfindSeq = new BTSequence;
+ pathfindSeq->addChildren(proximCond);
+ pathfindSeq->addChildren(walk);
+
+// // idle sequence
+
+// // root
+ m_root = new BTSelector;
+ m_root->addChildren(pathfindSeq);
+}
+
+// how might i be able to generalize the creation of the tree?
+void AIBehaviorComponent::update(float seconds){
+ // update root, which updates all its children
+ //std::cout << "---------in ai system" << std::endl;
+
+ m_status = m_root->update(seconds);
+}
+
+AIBehaviorComponent::~AIBehaviorComponent(){
+ delete m_root;
+}
+
diff --git a/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h
new file mode 100644
index 0000000..5a86b88
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/aibehaviorcomponent.h
@@ -0,0 +1,27 @@
+#ifndef AIBEHAVIORCOMPONENT_H
+#define AIBEHAVIORCOMPONENT_H
+
+
+#include "Game/Components/Component.h"
+#include "Game/Systems/AI/btselector.h"
+#include "Game/Systems/aisystem.h"
+#include <map>
+#include <string>
+class AIBehaviorComponent : public Component
+{
+public:
+ AIBehaviorComponent(std::string entity_id,
+ std::map<std::string, BlackboardData>& global_blackboard);
+ ~AIBehaviorComponent();
+ void update(float seconds);
+
+private:
+ void makeBehaviorTree();
+
+ std::string m_entity_id;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+ BTNode *m_root = 0;
+ Status m_status = Status::SUCCESS;
+};
+
+#endif // AIBEHAVIORCOMPONENT_H
diff --git a/engine-ocean/Game/Systems/AI/btnode.cpp b/engine-ocean/Game/Systems/AI/btnode.cpp
new file mode 100644
index 0000000..2740089
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btnode.cpp
@@ -0,0 +1,6 @@
+#include "btnode.h"
+
+BTNode::BTNode()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/AI/btnode.h b/engine-ocean/Game/Systems/AI/btnode.h
new file mode 100644
index 0000000..b025da6
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btnode.h
@@ -0,0 +1,18 @@
+#ifndef BTNODE_H
+#define BTNODE_H
+
+
+enum Status{
+ SUCCESS, FAIL, RUNNING
+};
+
+class BTNode
+{
+public:
+ BTNode();
+ virtual ~BTNode() = default;
+ virtual Status update(float seconds) = 0;
+ virtual void reset() = 0;
+ virtual void addChildren(BTNode *node) = 0;
+};
+#endif // BTNODE_H
diff --git a/engine-ocean/Game/Systems/AI/btselector.cpp b/engine-ocean/Game/Systems/AI/btselector.cpp
new file mode 100644
index 0000000..9652838
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btselector.cpp
@@ -0,0 +1,29 @@
+#include "btselector.h"
+#include <iostream>
+
+BTSelector::BTSelector()
+{
+
+}
+
+void BTSelector::addChildren(BTNode* node){
+ m_children.push_back(node);
+}
+
+Status BTSelector::update(float seconds){
+ // update each children until one doesnt fail
+ for (auto node : m_children){
+ Status result = node->update(seconds);
+
+ // select this one and return its status --> this node is currently running
+ if (result != Status::FAIL){
+ m_selected_node = node;
+ return result;
+ }
+ }
+
+ // otherwise if all children fail, then fail this selector
+ return Status::FAIL;
+}
+
+void BTSelector::reset(){}
diff --git a/engine-ocean/Game/Systems/AI/btselector.h b/engine-ocean/Game/Systems/AI/btselector.h
new file mode 100644
index 0000000..20058ac
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btselector.h
@@ -0,0 +1,21 @@
+#ifndef BTSELECTOR_H
+#define BTSELECTOR_H
+#include "Game/Systems/AI/btnode.h"
+#include <vector>
+
+
+class BTSelector : public BTNode
+{
+public:
+ BTSelector();
+ Status update(float seconds) override;
+ void reset() override;
+ void addChildren(BTNode *node) override;
+
+
+private:
+ std::vector<BTNode *> m_children;
+ BTNode *m_selected_node;
+};
+
+#endif // BTSELECTOR_H
diff --git a/engine-ocean/Game/Systems/AI/btsequence.cpp b/engine-ocean/Game/Systems/AI/btsequence.cpp
new file mode 100644
index 0000000..ba6169d
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btsequence.cpp
@@ -0,0 +1,30 @@
+#include "btsequence.h"
+#include <vector>
+
+BTSequence::BTSequence()
+{
+
+}
+
+void BTSequence::addChildren(BTNode *node){
+ m_sequence.push_back(node);
+}
+
+Status BTSequence::update(float seconds){
+
+ for (auto node : m_sequence){
+ if (node->update(seconds) == Status::FAIL){
+ return Status::RUNNING;
+ }
+ // if come across any node that fails
+ if (node->update(seconds) == Status::FAIL){
+ return Status::FAIL;
+ }
+ }
+
+ // if no node is fail or running, sequence is completed
+ return Status::SUCCESS;
+}
+
+void BTSequence::reset(){}
+
diff --git a/engine-ocean/Game/Systems/AI/btsequence.h b/engine-ocean/Game/Systems/AI/btsequence.h
new file mode 100644
index 0000000..5ff230c
--- /dev/null
+++ b/engine-ocean/Game/Systems/AI/btsequence.h
@@ -0,0 +1,20 @@
+#ifndef BTSEQUENCE_H
+#define BTSEQUENCE_H
+#include "btnode.h"
+#include <vector>
+
+
+class BTSequence : public BTNode
+{
+public:
+ BTSequence();
+ Status update(float seconds) override;
+ void reset() override;
+ void addChildren(BTNode* node) override;
+
+
+private:
+ std::vector<BTNode *> m_sequence;
+};
+
+#endif // BTSEQUENCE_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp
new file mode 100644
index 0000000..46155bc
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.cpp
@@ -0,0 +1,234 @@
+#include "bvhtree.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/boundingtriangle.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include <map>
+
+BVHTree::BVHTree(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) :
+ m_rigid_gameobjects(rigid_gameobjects)
+{
+ initializePrimitiveInfo();
+ buildBVH();
+ BVHNode one = m_bvhNodes[0];
+ BVHNode two = m_bvhNodes[1];
+ BVHNode three = m_bvhNodes[2];
+
+
+ std::cout << "primitives size: " << m_primitives.size() << std::endl;
+}
+
+// populate primitive info vector -> primitives = triangles
+void BVHTree::initializePrimitiveInfo(){
+ for (const auto &go : m_rigid_gameobjects){
+ N += go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getTriangleData().size();
+ for (const Triangle &tri : go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getTriangleData()){
+ // the order might not be accurate....
+ BVHPrimitive prim = {tri};
+ //std::cout << "centroid: (" << prim.centroid.x << ", " << prim.centroid.y << ", " << prim.centroid.z << ")" << std::endl;
+
+ m_primitives.push_back(prim);
+
+ }
+ }
+}
+
+void BVHTree::buildBVH(){
+ // initialize array of primitive indices
+ m_primitive_indices = new int[N];
+ for (int i=0; i<N; i++){
+ m_primitive_indices[i] = i;
+ }
+
+ m_bvhNodes = new BVHNode[N*2 - 1];
+ int rootNodeID = 0;
+ m_nodesUsed = 1;
+
+ // assign all primitives to root node
+ BVHNode& root = m_bvhNodes[0];
+ root.leftNode = 0;
+ root.firstPrimitiveIndex = 0;
+ root.primitiveCount = N;
+
+ updateNodeBounds(rootNodeID);
+ // subdivide recursively
+ subdivide(rootNodeID);
+}
+
+void BVHTree::updateNodeBounds(int nodeIndex){
+ BVHNode& node = m_bvhNodes[nodeIndex];
+ node.bounds.max = glm::vec3(-INFINITY);
+ node.bounds.min = glm::vec3(INFINITY);
+
+ for (int first = node.firstPrimitiveIndex, i=0; i<node.primitiveCount; i++){
+ int leafIndex = m_primitive_indices[first + i];
+ BVHPrimitive& leafPrimitive = m_primitives[leafIndex];
+ // update node bounds with the most max and most min coordinates
+ node.bounds = getNodeBounds<Bounds3f>(node.bounds, leafPrimitive.bounds);
+ }
+}
+
+void BVHTree::subdivide(int nodeIndex){
+ BVHNode& node = m_bvhNodes[nodeIndex];
+ // terminate recursion
+
+
+ if (node.primitiveCount <= 1) return;
+
+ // otherwise determine split axis and position
+// // SAHH HEREEEEE
+// int bestAxis = 0;
+// float bestPos = 0;
+// float bestCost = INFINITY;
+// for (int axis=0; axis<3; axis++){
+// for (int i=0; i<node.primitiveCount; i++){
+// BVHPrimitive& primitive = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]];
+// float candidatePos = primitive.centroid[axis];
+// float cost = evaluateSAH(node, axis, candidatePos);
+// if (cost < bestCost){
+// bestPos = candidatePos;
+// bestAxis = axis;
+// bestCost = cost;
+// }
+
+// }
+// }
+
+// int axis = bestAxis;
+// float splitPos = bestPos;
+
+// glm::vec3 e = node.bounds.max - node.bounds.min;
+// float parentArea = (e.x*e.y) + (e.y*e.z) * (e.z*e.x);
+// float parentCost = node.primitiveCount*parentArea;
+// if (bestCost >= parentCost) return;
+
+ // longest axis split (temporary)
+ glm::vec3 extent = node.bounds.max - node.bounds.min;
+ int axis = 0; // initialize to be x axis
+ if (extent.y > extent.x) axis = 1;
+ if (extent.z > extent[axis]) axis = 2;
+ float splitPos = node.bounds.min[axis] + extent[axis] * 0.5f;
+
+ // in-place partition
+ int i = node.firstPrimitiveIndex;
+ int j = i + node.primitiveCount - 1;
+ while (i <= j){
+ // if to the left of split axis
+ if (m_primitives[m_primitive_indices[i]].centroid[axis] < splitPos){
+ i++;
+ } else {
+ std::swap(m_primitive_indices[i], m_primitive_indices[j--]);
+ }
+ }
+
+ // abort split if one of the sides is empty
+ int leftCount = i - node.firstPrimitiveIndex;
+ if (leftCount == 0 || leftCount == node.primitiveCount) return;
+
+ // create child nodes
+ int leftChildID = m_nodesUsed++;
+ int rightChildID = m_nodesUsed++;
+
+ // left child
+ m_bvhNodes[leftChildID].firstPrimitiveIndex = node.firstPrimitiveIndex;
+ m_bvhNodes[leftChildID].primitiveCount = leftCount;
+
+ // right child
+ m_bvhNodes[rightChildID].firstPrimitiveIndex = i;
+ m_bvhNodes[rightChildID].primitiveCount = node.primitiveCount - leftCount;
+
+ node.leftNode = leftChildID;
+ node.primitiveCount = 0;
+
+ // recurse
+ updateNodeBounds(leftChildID);
+ updateNodeBounds(rightChildID);
+ subdivide(leftChildID);
+ subdivide(rightChildID);
+}
+
+float BVHTree::evaluateSAH(BVHNode& node, int axis, float pos){
+ BVHaabb leftBox, rightBox;
+ leftBox.bounds.min = glm::vec3(INFINITY), rightBox.bounds.min = glm::vec3(INFINITY);
+ leftBox.bounds.max = glm::vec3(-INFINITY), rightBox.bounds.max = glm::vec3(-INFINITY);
+
+ int leftCount = 0, rightCount = 0;
+ for (int i=0; i<node.primitiveCount; i++){
+ BVHPrimitive& primitive = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]];
+ if (primitive.centroid[axis] < pos){
+ leftCount++;
+ leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexA));
+ leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexB));
+ leftBox.grow(getNodeBounds_Point<Bounds3f>(leftBox.bounds, primitive.triangle.vertexC));
+ } else {
+ rightCount++;
+ rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexA));
+ rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexB));
+ rightBox.grow(getNodeBounds_Point<Bounds3f>(rightBox.bounds, primitive.triangle.vertexC));
+ }
+ }
+ float cost = leftCount * leftBox.area() + rightCount * rightBox.area();
+ return cost > 0 ? cost : INFINITY;
+}
+
+
+void BVHTree::intersectBVH(const glm::vec3 posA, const glm::vec3 posB, const int nodeIndex, std::vector<Triangle> &candidates, glm::vec3 ellip_R){
+ //std::cout << "-" << std::endl;
+
+ BVHNode& node = m_bvhNodes[nodeIndex];
+ if (!intersectsNode(posA, posB, node.bounds.min, node.bounds.max, ellip_R+glm::vec3(.001))){
+ return;
+ }
+ if (node.isLeaf()){
+ // intersect with primitives of the leaf
+ //std::cout << "candidate size: " << node.primitiveCount << std::endl;
+ for (int i=0; i<node.primitiveCount; i++){
+ Triangle triangle = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]].triangle;
+// BVHPrimitive prim = m_primitives[m_primitive_indices[node.firstPrimitiveIndex + i]];
+
+// if (prim.centroid == glm::vec3(39.42457, 1.84954, -15.7088)){
+// std::cout << "found correct triangle" << std::endl;
+// }
+ //std::cout << "centroid: (" << prim.centroid.x << ", " << prim.centroid.y << ", " << prim.centroid.z << ")" << std::endl;
+ candidates.push_back(triangle);
+
+ }
+ } else {
+ // recurse
+ intersectBVH(posA, posB, node.leftNode, candidates, ellip_R);
+ intersectBVH(posA, posB, node.leftNode + 1, candidates, ellip_R);
+ }
+}
+
+std::vector<Triangle> BVHTree::getBVHDetectedCollisions(glm::vec3 posA, glm::vec3 posB, glm::vec3 ellip_R){
+ // keep recursing, starting at root node, and then return final result in candidate_obstacles
+ std::vector<Triangle> candidate_rigid_tri;
+ intersectBVH(posA, posB, 0, candidate_rigid_tri, ellip_R);
+ return candidate_rigid_tri;
+}
+
+// determines if movement ray intersects an AABB via the slab test
+bool BVHTree::intersectsNode(glm::vec3 posA, glm::vec3 posB, glm::vec3 min, glm::vec3 max, glm::vec3 ellip_R){
+ glm::vec3 object_min = glm::vec3(std::min(posA.x, posB.x), std::min(posA.y, posB.y), std::min(posA.z, posB.z));
+ glm::vec3 object_max = glm::vec3(std::max(posA.x, posB.x), std::max(posA.y, posB.y), std::max(posA.z, posB.z));
+ object_min -= ellip_R;
+ object_max += ellip_R;
+
+ bool x_int = object_max.x > min.x && object_min.x < max.x;
+ bool y_int = object_max.y > min.y && object_min.y < max.y;
+ bool z_int = object_max.z > min.z && object_min.z < max.z;
+
+ if (x_int && y_int && z_int){
+ return true;
+ }
+ return false;
+}
+
+BVHTree::~BVHTree(){
+ delete[] m_bvhNodes;
+ delete[] m_primitive_indices;
+ m_bvhNodes = NULL;
+ m_primitive_indices = NULL;
+
+}
+
diff --git a/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h
new file mode 100644
index 0000000..b175e44
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/BVH/bvhtree.h
@@ -0,0 +1,106 @@
+#ifndef BVHTREE_H
+#define BVHTREE_H
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/GameObjects/GameObject.h"
+#include "glm/glm.hpp"
+#include <map>
+#include <vector>
+
+// primitive = triangle
+struct BVHPrimitive{
+
+ Bounds3f bounds;
+ glm::vec3 centroid;
+ Triangle triangle;
+
+ BVHPrimitive(const Triangle &tri):
+ triangle(tri),
+ bounds(tri.bounds),
+ centroid(.333f*(tri.vertexA + tri.vertexB + tri.vertexC)){}
+};
+
+struct BVHNode{
+ // glm::vec3 aabbMin, aabbMax;
+ Bounds3f bounds;
+ int leftNode, firstPrimitiveIndex, primitiveCount;
+ bool isLeaf(){
+ return primitiveCount > 0;
+ }
+};
+
+struct BVHaabb {
+ Bounds3f bounds;
+
+
+ void grow(Bounds3f newbounds){
+ bounds.min = newbounds.min;
+ bounds.max = newbounds.max;
+ }
+
+ float area(){
+ glm::vec3 e = bounds.max-bounds.min;
+ return (e.x*e.y) + (e.y*e.z) * (e.z*e.x);
+ }
+};
+
+
+template <typename T> Bounds3f
+getNodeBounds(const Bounds3f &b1, const Bounds3f &b2){
+ Bounds3f bounds;
+ bounds.min = glm::vec3(std::min(b1.min.x, b2.min.x),
+ std::min(b1.min.y, b2.min.y),
+ std::min(b1.min.z, b2.min.z));
+ bounds.max = glm::vec3(std::max(b1.max.x, b2.max.x),
+ std::max(b1.max.y, b2.max.y),
+ std::max(b1.max.z, b2.max.z));
+ return bounds;
+}
+
+template <typename T> Bounds3f
+getNodeBounds_Point(const Bounds3f &b, const glm::vec3 &p){
+ Bounds3f bounds;
+ bounds.min = glm::vec3(std::min(b.min.x, p.x),
+ std::min(b.min.y, p.y),
+ std::min(b.min.z, p.z));
+ bounds.max = glm::vec3(std::max(b.max.x, p.x),
+ std::max(b.max.y, p.y),
+ std::max(b.max.z, p.z));
+ return bounds;
+}
+
+class BVHTree
+
+{
+ BVHNode *m_bvhNodes;
+ int *m_primitive_indices;
+public:
+ BVHTree(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects);
+ ~BVHTree();
+ std::vector<Triangle> getBVHDetectedCollisions(glm::vec3 posA, glm::vec3 posB, glm::vec3 ellip_R);
+ void intersectBVH(glm::vec3 posA, glm::vec3 posB, const int nodeIndex, std::vector<Triangle> &candidates, glm::vec3 ellip_R);
+
+
+private:
+ float evaluateSAH(BVHNode& node, int axis, float pos);
+ void initializePrimitiveInfo();
+ void buildBVH();
+ void updateNodeBounds(int nodeIndex);
+ void subdivide(int nodeIndex);
+ bool intersectsNode(glm::vec3 posA, glm::vec3 posB, glm::vec3 min, glm::vec3 max, glm::vec3 ellip_R);
+
+
+ //std::unique_ptr<EllipsoidTriangleCollisionSystem> m_ellipsoid_triangle_collision_system;
+
+ std::vector<BVHPrimitive> m_primitives;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+
+
+ //std::vector<BVHNode> m_bvhNodes;
+ //std::vector<int> m_primitive_indices;
+ int m_nodesUsed = 1;
+ int N = 0;
+
+ // std::pair<std::vector<CollisionData>, glm::vec3> m_detected_collisions;
+};
+
+#endif // BVHTREE_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp
new file mode 100644
index 0000000..822129b
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.cpp
@@ -0,0 +1,127 @@
+#include "uniformgrid.h"
+#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include <algorithm>
+
+UniformGrid::UniformGrid(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects):
+ m_dynamic_gameobjects(dynamic_gameobjects)
+{
+ initializeGrid();
+}
+
+void UniformGrid::initializeGrid(){
+ // grid square: size it based on the largest entity
+
+ // set default square size to be same dimensions as player
+ m_square_dimensions = ceil(m_dynamic_gameobjects.at("player")->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions);
+
+
+ // find largest shape dimension in order to set grid square dimensions
+ for (const auto &go : m_dynamic_gameobjects){
+ if (go.second->hasComponent<CollisionComponent>()){
+ glm::vec3 shape_dimensions = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions;
+ // find the largest Bounds3f for a shape
+ if (glm::all(glm::greaterThan(shape_dimensions, m_square_dimensions))){
+ m_square_dimensions = ceil(shape_dimensions);
+ }
+ }
+ }
+
+ // initialize grid based on where entities are initially placed
+ for (const auto &go : m_dynamic_gameobjects){
+ updateUniformGrid(go);
+ }
+}
+
+std::string UniformGrid::vecToString(glm::vec3 v){
+ std::string square_bound = std::to_string(v.x) + std::to_string(v.y) + std::to_string(v.z);
+ return square_bound;
+}
+
+
+void UniformGrid::populateContainingCell(glm::vec3 bound_corner, std::string entity_id){
+ glm::vec3 factor = floor(bound_corner/m_square_dimensions);
+ glm::vec3 container_min = factor*m_square_dimensions;
+
+ for (auto &square : m_grid_map){
+ //if the containing square is already in map, then append entity id to its associate list
+ if (square.first == vecToString(container_min)){
+ m_grid_map.at(square.first).insert(entity_id);
+ return;
+ }
+ }
+ // if not yet in map, add to map
+ std::set<std::string> ids;
+ ids.insert(entity_id);
+ m_grid_map.insert(std::pair(vecToString(container_min), ids));
+}
+
+void UniformGrid::updateUniformGrid(const std::pair<std::string, std::shared_ptr<GameObject>> &go){
+ if (go.second->hasComponent<CollisionComponent>()){
+ Bounds3f shapeBounds = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().bounds;
+ // if bounds min is within an interval of square dimensions, then occupy map with that entity
+ glm::vec3 shape_dimensions = go.second->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder().aabbDimensions;
+
+
+ // check all 6 aabb corners
+ float x_val = shapeBounds.min.x;
+ for (int x=0; x<2; x++){
+ float y_val = shapeBounds.min.y;
+ for (int y=0; y<2; y++){
+ float z_val = shapeBounds.min.z;
+ for (int z=0; z<2; z++){
+ glm::vec3 corner = glm::vec3(x_val,y_val,z_val);
+ populateContainingCell(corner, go.first);
+ z_val += shape_dimensions.z;
+ }
+ y_val += shape_dimensions.y;
+ }
+ x_val += shape_dimensions.x;
+ }
+ }
+}
+
+// only for entities that moved:
+void UniformGrid::moveEntityGridPosition(const std::pair<std::string, std::shared_ptr<GameObject>> &go){
+ // remove previous cells that entity occupied
+ for (auto &cell : m_grid_map){
+ cell.second.erase(go.first);
+ }
+
+ // if there are no more ids associated with that cell, remove it from map
+ for (auto cell = m_grid_map.cbegin(), next_i = cell; cell != m_grid_map.cend(); cell = next_i){
+ ++next_i;
+ if (cell->second.empty()){
+ m_grid_map.erase(cell);
+ }
+ }
+
+ // then update based on new pos
+ updateUniformGrid(go);
+}
+
+void UniformGrid::updateAllGrid(){
+ // initialize grid based on where entities are initially placed
+ for (const auto &go : m_dynamic_gameobjects){
+ moveEntityGridPosition(go);
+ }
+
+ //std::cout << "new ugrid size: " << m_grid_map.size() << std::endl;
+}
+
+std::set<std::set<std::string>> UniformGrid::detectPossibleCollisions(){
+ // store list of names of objects that are near e/o
+ // uses set there are no duplicate inner sets of the same objects
+ std::set<std::set<std::string>> candidate_collision_sets;
+
+ for (const auto &cell : m_grid_map){
+ if (cell.second.size() > 1){
+ candidate_collision_sets.insert(cell.second);
+ }
+ }
+
+ // then for each inner set, detect collisions between the contained objects
+ return candidate_collision_sets;
+}
diff --git a/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h
new file mode 100644
index 0000000..c4e5aaa
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h
@@ -0,0 +1,67 @@
+#ifndef UNIFORMGRID_H
+#define UNIFORMGRID_H
+
+
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/GameObjects/GameObject.h"
+#include <set>
+#include <vector>
+
+struct GridSquare {
+ Bounds3f bounds;
+ glm::vec3 centroid = (bounds.max - bounds.min)/ 2.f;
+
+
+// bool operator<( const GridSquare & s ) const {
+// return glm::all(glm::lessThan(this->bounds.min,s.bounds.min)); // for example
+// }
+
+
+};
+
+//bool operator<(const GridSquare& l, const GridSquare& r)
+//{
+// return glm::all(glm::lessThan(l.bounds.min, r.bounds.min));
+//}
+
+//bool operator==(const GridSquare& l, const GridSquare& r)
+//{
+// return l.bounds.min == r.bounds.min;
+//}
+
+//bool operator<(const glm::vec3& l, const glm::vec3& r)
+//{
+// return glm::all(glm::lessThan(l, r));;
+//}
+
+//bool operator==(const glm::vec3& l, const glm::vec3& r)
+//{
+// return glm::all(glm::equal(l, r));;
+//}
+
+
+class UniformGrid
+{
+public:
+ UniformGrid(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects);
+ std::set<std::set<std::string>> detectPossibleCollisions();
+ void updateAllGrid();
+
+
+
+private:
+ void populateContainingCell(glm::vec3 bound_corner, std::string entity_id);
+ void updateUniformGrid(const std::pair<std::string, std::shared_ptr<GameObject>> &go);
+ void moveEntityGridPosition(const std::pair<std::string, std::shared_ptr<GameObject>> &go);
+ void initializeGrid();
+ std::string vecToString(glm::vec3 v);
+
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ // maps square corner to set of strings
+ std::map<std::string, std::set<std::string>> m_grid_map;
+ glm::vec3 m_square_dimensions;
+
+};
+
+#endif // UNIFORMGRID_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp
new file mode 100644
index 0000000..c81be68
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.cpp
@@ -0,0 +1,6 @@
+#include "accelerationsystem.h"
+
+AccelerationSystem::AccelerationSystem()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h
new file mode 100644
index 0000000..dd47731
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/accelerationsystem.h
@@ -0,0 +1,11 @@
+#ifndef ACCELERATIONSYSTEM_H
+#define ACCELERATIONSYSTEM_H
+
+
+class AccelerationSystem
+{
+public:
+ AccelerationSystem();
+};
+
+#endif // ACCELERATIONSYSTEM_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp
new file mode 100644
index 0000000..40816de
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.cpp
@@ -0,0 +1,183 @@
+#include "collisionsystem.h"
+#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include "Game/Components/TransformComponent.h"
+
+CollisionSystem::CollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<int, Input>& input_map,
+ std::map<std::string, BlackboardData>& global_blackboard) :
+ m_gameobjects(gameobjects),
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_rigid_gameobjects(rigid_gameobjects),
+ m_uniform_grid_system(std::make_unique<UniformGrid>(dynamic_gameobjects)),
+ m_global_blackboard(global_blackboard)
+{
+
+}
+
+TransformComponent* CollisionSystem::getTransform(std::shared_ptr<GameObject> &go){
+ return go->getComponent<TransformComponent>();
+
+}
+
+CollisionComponent* CollisionSystem::getCollisionComp(std::shared_ptr<GameObject> &go){
+ return go->getComponent<CollisionComponent>();
+}
+
+glm::vec2 CollisionSystem::calculateCircleMVT(const Cylinder &a, const Cylinder &b){
+ float len = glm::length(a.point - b.point);
+
+ glm::vec2 mtv = ((b.point - a.point)/len) * (a.radius+b.radius - len);
+ return mtv;
+}
+
+float CollisionSystem::calculateLineMVT(const Cylinder &a, const Cylinder &b){
+ float aRight = b.max - a.min;
+ float aLeft = a.max - b.min;
+ if ((aLeft < 0) || (aRight < 0)){
+ return -1.f;
+ }
+ if (aRight < aLeft){
+ return aRight;
+ }
+ return -aLeft;
+}
+
+glm::vec3 CollisionSystem::collideCylinderCylinder(const std::shared_ptr<GameObject> &a_go, const std::shared_ptr<GameObject> &b_go){
+ Cylinder a = a_go->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder();
+ Cylinder b = b_go->getComponent<CollisionComponent>()->getCollisionShape<BoundingDynamicMesh>()->getCylinder();
+
+ //std::cout << "a max: " << a.max << std::endl;
+ //std::cout << "b max: " << b.max << std::endl;
+
+
+
+ float len_squared = pow(a.point[0]-b.point[0],2) + pow(a.point[1]-b.point[1],2);
+ float radius_sum = pow(a.radius + b.radius, 2);
+
+ // check if circles overlap
+ if (len_squared < radius_sum){
+ //std::cout << "CIRCLES OVERLAP" << std::endl;
+ // check if lines overlap
+ if ((a.min < b.max) && (b.min < a.max)){
+ std::cout << "COLLIDINGGG" << std::endl;
+ // calculate both circle and line mtvs, and then return the shortest mtv
+ glm::vec2 circle_mtv = calculateCircleMVT(a, b);
+ float circle_len = glm::length(circle_mtv);
+
+ float line_mtv = calculateLineMVT(a, b);
+
+ if (abs(circle_len) < abs(line_mtv)){
+ return glm::vec3(circle_mtv[0], 0.f, circle_mtv[1]);
+ } else {
+ return glm::vec3(0.f, line_mtv, 0.f);
+ }
+ }
+ }
+
+ // return translation of 0 if there is no collision
+ return glm::vec3(0.f);
+}
+
+
+bool CollisionSystem::checkCollisionShape(const std::shared_ptr<GameObject> &go, std::string shape_type){
+ // add more collision shapes here
+ if (shape_type == "cylinder"){
+ return (go->getComponent<CollisionComponent>()->hasCollisionShape<CylinderCollider>());
+ }
+ return false;
+}
+
+void CollisionSystem::resolveCollision(std::shared_ptr<GameObject> &go,
+ glm::vec3 mtv,
+ float deltaTime,
+ std::string go_name){
+ glm::vec3 potential_pos = go->getComponent<TransformComponent>()->getPos();
+ go->getComponent<TransformComponent>()->old_pos = potential_pos;
+ go->getComponent<TransformComponent>()->movingLaterally = false;
+
+ // translate, and also update the collision cylinder point
+ float a = go->getComponent<CollisionComponent>()->getAcceleration();
+ float v = go->getComponent<CollisionComponent>()->getReboundVel();
+ float delta_x = mtv.x + v*deltaTime + .5*a*pow(deltaTime, 2);
+ float delta_z = mtv.z + v*deltaTime + .5*a*pow(deltaTime, 2);
+
+ // update estimated_final_pos, so that tri-ellip collision can see if the new pos collides with environment
+ glm::vec3 translationDir = glm::vec3(delta_x, mtv.y, delta_z);
+ if (delta_x != 0 || delta_z != 0){
+ go->getComponent<TransformComponent>()->movingLaterally = true;
+ }
+
+ std::shared_ptr<ModelTransform> temp_mt = go->getComponent<TransformComponent>()->getMT();
+ temp_mt->translate(translationDir);
+ potential_pos = temp_mt->getPos();
+
+
+ m_global_blackboard[go_name].locationData.setToPos = potential_pos;
+ go->getComponent<TransformComponent>()->estimated_final_pos = potential_pos;
+}
+
+void CollisionSystem::detectCylinderCollisions(std::shared_ptr<GameObject> &a,
+ std::shared_ptr<GameObject> &b,
+ float deltaTime,
+ std::string a_name, std::string b_name){
+ // if its a cyl-cyl collision
+ glm::vec3 mtv(0.f);
+
+ mtv = collideCylinderCylinder(a, b);
+ if (mtv != glm::vec3(0.f)){
+ resolveCollision(b, 1.f*mtv, deltaTime, b_name);
+ resolveCollision(a, -1.f*mtv, deltaTime, a_name);
+ }
+
+}
+
+bool CollisionSystem::areCollidable(const std::shared_ptr<GameObject> &a, const std::shared_ptr<GameObject> &b){
+ return (a->hasComponent<CollisionComponent>() && b->hasComponent<CollisionComponent>());
+}
+
+
+// DYNAMIC-DYNAMIC COLLISIONS: CYLINDER
+void CollisionSystem::dynamicDynamicCollisions(double deltaTime){
+ std::set<std::set<std::string>> candidate_collison_set = m_uniform_grid_system->detectPossibleCollisions();
+
+ // std::cout << "all collisions size : " << candidate_collison_set.size() << std::endl;
+
+ for (const std::set<std::string> &set : candidate_collison_set){
+
+ // std::cout << "collision group size : " << set.size() << std::endl;
+
+ std::vector<std::string> coll_group;
+ for (const std::string &name : set){
+ coll_group.push_back(name);
+ }
+
+ for (int i=0; i < coll_group.size(); i++){
+ auto a = m_dynamic_gameobjects.at(coll_group[i]);
+ for (int j=i+1; j < coll_group.size(); j++){
+ auto b = m_dynamic_gameobjects.at(coll_group[j]);
+ // if a is not the same GO as b, and at least has collide components and thus is collidable,
+ if ((a != b) && (areCollidable(a, b))){
+ //std::cout << "collide: " << coll_group[i] << " + " << coll_group[j] << std::endl;
+ detectCylinderCollisions(a, b, deltaTime, coll_group[i], coll_group[j]);
+ }
+ }
+ }
+ }
+}
+
+
+void CollisionSystem::update(double deltaTime){
+ // update uniform grid before detecting with it
+ m_uniform_grid_system->updateAllGrid();
+ dynamicDynamicCollisions(deltaTime);
+}
+
+void CollisionSystem::draw(){}
+void CollisionSystem::scrollEvent(double distance){}
+void CollisionSystem::mousePosEvent(double xpos, double ypos){}
+
+
diff --git a/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h
new file mode 100644
index 0000000..5c635ba
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/collisionsystem.h
@@ -0,0 +1,53 @@
+#ifndef COLLISIONSYSTEM_H
+#define COLLISIONSYSTEM_H
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameWorld.h"
+#include "Game/Systems/CollisionSystems/UniformGrid/uniformgrid.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include "Game/Systems/system.h"
+
+class CollisionSystem : public System
+{
+public:
+ CollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<int, Input>& input_map,
+ std::map<std::string, BlackboardData>& global_blackboard);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+private:
+ bool areCollidable(const std::shared_ptr<GameObject> &a, const std::shared_ptr<GameObject> &b);
+ void detectCylinderCollisions(std::shared_ptr<GameObject> &a, std::shared_ptr<GameObject> &b, float deltaTime,
+ std::string a_name, std::string b_name);
+ void resolveCollision(std::shared_ptr<GameObject> &go, glm::vec3 translation, float deltaTime, std::string go_name);
+ bool checkCollisionShape(const std::shared_ptr<GameObject> &go, std::string shape_type);
+ glm::vec3 projectMotion(const glm::vec3 &initial_pos, float deltaTime);
+
+ TransformComponent* getTransform(std::shared_ptr<GameObject> &go);
+ CollisionComponent* getCollisionComp(std::shared_ptr<GameObject> &go);
+
+ void rigidDynamicCollisions(double deltaTime);
+ void dynamicDynamicCollisions(double deltaTime);
+
+
+ // cylinder-cylinder
+ glm::vec3 collideCylinderCylinder(const std::shared_ptr<GameObject> &a_go, const std::shared_ptr<GameObject> &b_go);
+ float calculateLineMVT(const Cylinder &a, const Cylinder &b);
+ glm::vec2 calculateCircleMVT(const Cylinder &a, const Cylinder &b);
+
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+
+ std::unique_ptr<UniformGrid> m_uniform_grid_system;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+};
+
+
+#endif // COLLISIONSYSTEM_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp
new file mode 100644
index 0000000..52b8916
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.cpp
@@ -0,0 +1,370 @@
+#include "ellipsoidtrianglecollisionsystem.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/boundingellipsoid.h"
+#include "Game/Components/DrawComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include <memory>
+
+EllipsoidTriangleCollisionSystem::EllipsoidTriangleCollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) :
+ m_rigid_gameobjects(rigid_gameobjects),
+ m_bvh_system(std::make_unique<BVHTree>(rigid_gameobjects))
+{
+}
+
+
+Triangle EllipsoidTriangleCollisionSystem::convertTriangleToSphereSpace(const glm::vec3 &orig_R, const Triangle &orig_triangle){
+ Triangle transformed_triangle;
+
+ // divide vertex pos by Rs
+ transformed_triangle.vertexA = orig_triangle.vertexA / orig_R;
+ transformed_triangle.vertexB = orig_triangle.vertexB / orig_R;
+ transformed_triangle.vertexC = orig_triangle.vertexC / orig_R;
+
+ transformed_triangle.edge1 = transformed_triangle.vertexB - transformed_triangle.vertexA;
+ transformed_triangle.edge2 = transformed_triangle.vertexC - transformed_triangle.vertexA;
+
+ // does the normal stay the same across transformations?
+ transformed_triangle.normal = glm::normalize(glm::cross(transformed_triangle.edge1, transformed_triangle.edge2));
+
+ return transformed_triangle;
+}
+
+
+glm::vec3 EllipsoidTriangleCollisionSystem::getIntersectionPt(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const float t){
+ return ray_p + t*ray_d;
+}
+
+float EllipsoidTriangleCollisionSystem::solveQuadratic(float a, float b, float c){
+ float discriminant = pow(b,2) - 4*a*c;
+
+ // check for imaginary numbers
+ if (discriminant >= 0){
+ float pos_quad = (-b + sqrt(discriminant)) / (2*a);
+ float neg_quad = (-b - sqrt(discriminant)) / (2*a);
+
+ // if the mininum is a neg number, then return the larger of the two
+ if (fmin(pos_quad, neg_quad) < ZERO){
+ return fmax(pos_quad, neg_quad);
+ } else {
+ return fmin(pos_quad, neg_quad);
+ }
+ }
+ return -1;
+}
+
+
+float EllipsoidTriangleCollisionSystem::raycastSphere(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const glm::vec3 posA, const glm::vec3 posB){
+ // shift ray and ellipsoid to center first in order to use regular implicit sphere equation
+ glm::vec3 p = ray_p - posA;
+ glm::vec3 d = ray_d - posA;
+
+ float a = (d.x*d.x) + (d.y*d.y) + (d.z*d.z);
+ float b = (2.f*p.x*d.x) + (2.f*p.y*d.y) + (2.f*p.z*d.z);
+ float c = (p.x*p.x) + (p.y*p.y) + (p.z*p.z) - 1.f;
+
+ return solveQuadratic(a,b,c);
+}
+
+float EllipsoidTriangleCollisionSystem::raycastTriangle(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const Triangle &triangle){
+ float t = (glm::dot((triangle.vertexA - ray_p), triangle.normal))/(glm::dot(ray_d, triangle.normal));
+ return t;
+}
+
+glm::vec3 EllipsoidTriangleCollisionSystem::getTriangleEdge(const glm::vec3 v1, const glm::vec3 v2){
+ return v2 - v1;
+}
+
+bool EllipsoidTriangleCollisionSystem::isSameDirection(const glm::vec3 edge1, const glm::vec3 edge2, const glm::vec3 n){
+ if (glm::dot(glm::cross(edge1, edge2), n) > 0){
+ return true;
+ }
+ return false;
+}
+
+void EllipsoidTriangleCollisionSystem::makeCollisionData(const float t, const glm::vec3 triangle_n,
+ const glm::vec3 intersection_pos,
+ const glm::vec3 point_of_contact,
+ const bool isVertex){
+ CollisionData data;
+ data.t = t;
+ data.triangle_n = triangle_n;
+ data.intersection_pos = intersection_pos;
+ data.point_of_contact = point_of_contact;
+ data.isVertex = isVertex;
+ m_collisionData.push_back(data);
+}
+
+
+bool EllipsoidTriangleCollisionSystem::detectSphere_with_Interior(const Triangle &triangle, const glm::vec3 posA, const glm::vec3 posB){
+ // calculate point on sphere closest to the plane and cast a ray
+ glm::vec3 ray_p = posA-triangle.normal; // closest point on unit sphere
+ glm::vec3 ray_d = (posB-posA);
+
+ glm::vec3 n = triangle.normal;
+ glm::vec3 v = triangle.vertexA;
+ float plane_const = -1 * (n.x*v.x + n.y*v.y + n.z*v.z);
+
+ // pdf equation
+ float t = (1-(glm::dot(n, posA) + plane_const)) / (glm::dot(n, (posB-posA)));
+ if (t < ZERO || t > ONE){
+ return false;
+ }
+
+ // the point P on the sphere closest to plane surface
+ glm::vec3 P_edge = getIntersectionPt(ray_p, ray_d, t);
+
+
+ // determine if point is on triangle plane
+ // determine if point is also within triangle bounds
+ glm::vec3 AB = getTriangleEdge(triangle.vertexA, triangle.vertexB);
+ glm::vec3 BC = getTriangleEdge(triangle.vertexB, triangle.vertexC);
+ glm::vec3 CA = getTriangleEdge(triangle.vertexC, triangle.vertexA);
+
+ glm::vec3 AP = getTriangleEdge(triangle.vertexA, P_edge);
+ glm::vec3 BP = getTriangleEdge(triangle.vertexB, P_edge);
+ glm::vec3 CP = getTriangleEdge(triangle.vertexC, P_edge);
+
+ if (isSameDirection(AB, AP, triangle.normal) &&
+ isSameDirection(BC, BP, triangle.normal) &&
+ isSameDirection(CA, CP, triangle.normal)){
+
+ // the actual center of sphere
+ glm::vec3 P_centered = getIntersectionPt(posA, posB-posA, t);
+ makeCollisionData(t, triangle.normal, P_centered, P_edge, false);
+ return true;
+ }
+ return false;
+}
+
+// do this for each vertex pair AB, BC, CA
+bool EllipsoidTriangleCollisionSystem::detectSphere_with_Edge(const glm::vec3 &v1, const glm::vec3 &v2,
+ const glm::vec3 &triangle_normal,
+ const glm::vec3 &posA, const glm::vec3 &posB){
+ glm::vec3 C = v1;
+ glm::vec D = v2;
+
+ float a = pow(glm::length(glm::cross(posB-posA, D-C)),2);
+ float b = glm::dot(2.f*glm::cross(posB-posA, D-C), glm::cross(posA-C, D-C));
+ float c = pow(glm::length(glm::cross(posA-C, D-C)),2) - pow(glm::length(D-C),2);
+
+ float t = solveQuadratic(a,b,c);
+
+ // discard a negative t --> indicates no collision with edge
+ if (t < ZERO || t > ONE){
+ return false;
+ }
+
+ glm::vec3 P = getIntersectionPt(posA, posB-posA, t);
+
+ glm::vec3 AP = P-C;
+ glm::vec3 AB = D-C;
+ glm::vec3 normal = AP - (glm::dot(AB,AP)/glm::dot(AB,AB))*AB;
+
+ // determine if intersection pt is between C and D
+ if ( (0 < glm::dot(P-C,D-C)) && (glm::dot(P-C,D-C) < pow(glm::length(D-C),2)) ){
+ makeCollisionData(t, normal, P, P, false);
+ return true;
+ }
+
+ return false;
+}
+
+// needs to be done with each vertex
+bool EllipsoidTriangleCollisionSystem::detectSphere_with_Vertex(const glm::vec3 &v, const glm::vec3 triangle_normal, const glm::vec3 &posA, const glm::vec3 &posB){
+ glm::vec3 ray_p = v;
+ //glm::vec3 ray_d = v-(posB-posA);
+
+ // convert to origin space:
+ glm::vec3 vel = posB-posA;
+ glm::vec3 v_origined = v - posA;
+
+ float a = glm::dot(vel,vel);
+ float b = 2*(glm::dot(vel, -v_origined));
+ float c = pow(glm::length(v_origined),2) - 1.f;
+
+ float t = solveQuadratic(a,b,c);
+ if (t < ZERO || t > ONE){
+ return false;
+ }
+
+ // where the center is when the sphere hits vertex
+ glm::vec3 center_pt_origined = t*vel;
+ // convert back to non-origin space
+ glm::vec3 center_pt = center_pt_origined + posA;
+ glm::vec3 normal = center_pt - v;
+ makeCollisionData(t, normal, center_pt, v, true);
+ return true;
+}
+
+CollisionData EllipsoidTriangleCollisionSystem::getNearestCollision(const std::vector<CollisionData> &collisionData, const Triangle &sphere_tri){
+ CollisionData nearestCollision;
+ nearestCollision.t = INFINITY;
+
+ for (const CollisionData &data : collisionData){
+ if (data.t < nearestCollision.t){
+ // set nearest collision to datapoint
+ nearestCollision = data;
+ }
+ }
+ return nearestCollision;
+}
+
+// SPHERE SPACE
+CollisionData EllipsoidTriangleCollisionSystem::detectTriangleCollision(const Triangle &sphere_tri, const glm::vec3 &posA, const glm::vec3 &posB){
+
+ m_collisionData.clear();
+ // if interior is true, no need to check rest. get the only collision data
+ if (detectSphere_with_Interior(sphere_tri, posA, posB)){
+ return m_collisionData[0];
+ }
+
+ // otherwise check rest:
+
+ // detect edge with all 3 edges
+ // | operator executes regardless of if left hand side is true or not
+ if (
+ detectSphere_with_Edge(sphere_tri.vertexA, sphere_tri.vertexB, sphere_tri.normal, posA, posB) |
+ detectSphere_with_Edge(sphere_tri.vertexB, sphere_tri.vertexC, sphere_tri.normal, posA, posB) |
+ detectSphere_with_Edge(sphere_tri.vertexC, sphere_tri.vertexA, sphere_tri.normal, posA, posB) ){
+ return getNearestCollision(m_collisionData, sphere_tri);
+ }
+
+ // detect vertex with all 3 vertices
+ detectSphere_with_Vertex(sphere_tri.vertexA, sphere_tri.normal, posA, posB);
+ detectSphere_with_Vertex(sphere_tri.vertexB, sphere_tri.normal, posA, posB);
+ detectSphere_with_Vertex(sphere_tri.vertexC, sphere_tri.normal, posA, posB);
+
+ return getNearestCollision(m_collisionData, sphere_tri);
+}
+
+CollisionData EllipsoidTriangleCollisionSystem::revertDataToOriginalSpace(const CollisionData &sphere_datum, const glm::vec3 &ellip_R, const glm::vec3 orig_triangle_n){
+ CollisionData reverted_datum = sphere_datum;
+ reverted_datum.intersection_pos = reverted_datum.intersection_pos*ellip_R;
+ reverted_datum.point_of_contact = reverted_datum.point_of_contact*ellip_R;
+
+ return reverted_datum;
+}
+
+void EllipsoidTriangleCollisionSystem::setEllipsoidDimensions(const glm::vec3 &dimensions){
+ m_ellipsoid_dimensions = dimensions;
+}
+
+CollisionData EllipsoidTriangleCollisionSystem::collideWithWorld(const glm::vec3 &posA, const glm::vec3 &posB){
+ // makes ellipsoids
+ Ellipsoid ellipsoidA;
+ ellipsoidA.R = m_ellipsoid_dimensions;
+ ellipsoidA.center_pos = posA;
+
+
+ Ellipsoid ellipsoidB;
+ ellipsoidB.R = m_ellipsoid_dimensions;
+ ellipsoidB.center_pos = posB;
+
+ // convert ellipsoid centers to sphere space
+ glm::vec3 sphere_posA = ellipsoidA.center_pos/m_ellipsoid_dimensions;
+ glm::vec3 sphere_posB = ellipsoidB.center_pos/m_ellipsoid_dimensions;
+
+ CollisionData nearestCollision;
+ nearestCollision.t = INFINITY;
+
+
+ std::vector<Triangle> candidates = m_bvh_system->getBVHDetectedCollisions(posA, posB, ellipsoidA.R);
+ // std::cout << "candidate size: " << candidates.size() << std::endl;
+
+
+// for (auto &rigid_go : candidates){
+// //std::cout << "candidate shape name: " << rigid_go->getComponent<DrawComponent>()->getShapeName() << std::endl;
+// if (rigid_go->hasComponent<CollisionComponent>()){
+// if (rigid_go->getComponent<CollisionComponent>()->hasCollisionShape<BoundingTriangle>()){
+// // for every triangle in game obj, transform to sphere space and collide with ellipsoid (aka sphere)
+ for (int i=0; i< candidates.size(); i++){
+ Triangle triangle = candidates[i];
+// std::cout<< "triangle i: " << i << ", v1: (" << triangle.vertexA.x << ", " << triangle.vertexA.y << ", " << triangle.vertexA.z << "), v2: ("
+// << triangle.vertexB.x << ", " << triangle.vertexB.y << ", " << triangle.vertexB.z << "), v3: ("
+// << triangle.vertexC.x << ", " << triangle.vertexC.y << ", " << triangle.vertexC.z << ")" << std::endl;
+
+ // transform triangle to sphere space and detect collision data (in sphere space) for this specific triangle
+ Triangle sphere_triangle = convertTriangleToSphereSpace(m_ellipsoid_dimensions, triangle);
+ CollisionData sphere_collisionDatum = detectTriangleCollision(sphere_triangle, sphere_posA, sphere_posB);
+ CollisionData ellip_collisionDatum = revertDataToOriginalSpace(sphere_collisionDatum, m_ellipsoid_dimensions, triangle.normal);
+
+ // keep track of nearest Collision
+ if (ellip_collisionDatum.t < nearestCollision.t && ellip_collisionDatum.t <= ONE && ellip_collisionDatum.t >= ZERO){
+ nearestCollision = ellip_collisionDatum;
+ }
+ // repeat for the other triangles
+ }
+ //}
+ //}
+ // repeat for all gameobjects
+ //}
+
+ return nearestCollision;
+}
+
+glm::vec3 EllipsoidTriangleCollisionSystem::doNudge(glm::vec3 curr_pos, CollisionData collision){
+ glm::vec3 nudge = m_scale_normals_mt*collision.triangle_n;
+
+ glm::vec3 pos_nudged = collision.intersection_pos + nudge * .01f;
+ int MAX_NUDGES = 3;
+ for (int i=0; i<MAX_NUDGES; i++){
+ CollisionData nudge_collision = collideWithWorld(curr_pos, pos_nudged);
+ if (nudge_collision.t == INFINITY){
+ curr_pos = pos_nudged;
+ break;
+ } else {
+ if (glm::length((m_scale_normals_mt*nudge_collision.triangle_n) - nudge) < .0001 || glm::length((m_scale_normals_mt*nudge_collision.triangle_n) + nudge) < .0001){
+ nudge = -m_scale_normals_mt*nudge_collision.triangle_n;
+ } else {
+ nudge = m_scale_normals_mt*nudge_collision.triangle_n;
+ }
+ pos_nudged = nudge_collision.intersection_pos + nudge * .01f;
+ }
+ }
+ return curr_pos;
+
+}
+
+glm::mat3 EllipsoidTriangleCollisionSystem::makeConversionMT(glm::vec3 initial_center_pos, glm::vec3 dimensions){
+ m_conversion_mt = std::make_shared<ModelTransform>();
+ m_conversion_mt->translate(-initial_center_pos);
+ m_conversion_mt->scale(dimensions);
+ m_scale_normals_mt = glm::transpose((glm::inverse(glm::mat3(m_conversion_mt->getModelMatrix()))));
+ m_scale_normals_mt = glm::mat4(1.f);
+ return m_scale_normals_mt;
+}
+
+// in sphere space
+std::pair<std::vector<CollisionData>, glm::vec3> EllipsoidTriangleCollisionSystem::mtvSlide(glm::vec3 initial_pos, glm::vec3 final_pos, glm::vec3 dimensions){
+ setEllipsoidDimensions(dimensions);
+ glm::mat3 normals_scale = makeConversionMT(initial_pos, dimensions);
+
+ std::vector<CollisionData> collisions;
+ glm::vec3 curr_pos = initial_pos;
+ glm::vec3 next_pos = final_pos;
+ int MAX_TRANSLATIONS = 3;
+ for (int i=0; i<MAX_TRANSLATIONS; i++){
+ CollisionData c = collideWithWorld(initial_pos, next_pos);
+
+ // if no collisions [0,1] found, then continue on regular path
+ if (c.t == INFINITY){
+ //std::cout << "--mtv-- " << next_pos.x << "," << next_pos.y << "," << next_pos.z << std::endl;
+ return std::pair<std::vector<CollisionData>, glm::vec3>(collisions, next_pos);
+ } else {
+ // nudge along the collision data
+ //std::cout << "COLLIDING......" << std::endl;
+ curr_pos = doNudge(curr_pos, c);
+ glm::vec3 d = next_pos - curr_pos;
+ glm::vec3 d_corrected = (d - glm::dot(d, normals_scale*c.triangle_n)) * (normals_scale*c.triangle_n);
+ next_pos = curr_pos + d_corrected;
+ collisions.push_back(c);
+ }
+
+ }
+
+ return std::pair<std::vector<CollisionData>, glm::vec3>(collisions, curr_pos);
+}
+
+
diff --git a/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h
new file mode 100644
index 0000000..8a7d102
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h
@@ -0,0 +1,69 @@
+#ifndef ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H
+#define ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H
+#include "Game/Components/CollisionComponents/BoundingEllipsoid.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/Systems/CollisionSystems/BVH/bvhtree.h"
+#include "glm/glm.hpp"
+#include <vector>
+
+struct CollisionData{
+ bool hasCollided = true; // only false when there is no collision data to return
+ bool isVertex = false;
+ float t = INFINITY;
+ glm::vec3 triangle_n; // normal of the triangle its colliding with
+ glm::vec3 intersection_pos;
+ glm::vec3 point_of_contact;
+};
+
+class EllipsoidTriangleCollisionSystem
+{
+public:
+ EllipsoidTriangleCollisionSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects);
+
+
+ std::pair<std::vector<CollisionData>, glm::vec3> mtvSlide(glm::vec3 initial_pos, glm::vec3 final_pos, glm::vec3 dimensions);
+
+private:
+ CollisionData collideWithWorld(const glm::vec3 &posA, const glm::vec3 &posB);
+ void setEllipsoidDimensions(const glm::vec3 &dimensions);
+ glm::vec3 doNudge(glm::vec3 curr_pos, CollisionData collision);
+ CollisionData revertDataToOriginalSpace(const CollisionData &sphere_datum, const glm::vec3 &ellip_R, const glm::vec3 orig_triangle_n);
+ CollisionData detectTriangleCollision(const Triangle &sphere_tri, const glm::vec3 &posA, const glm::vec3 &posB);
+ CollisionData getNearestCollision(const std::vector<CollisionData> &collisionData, const Triangle &sphere_tri);
+ glm::mat3 makeConversionMT(glm::vec3 initial_center_pos, glm::vec3 dimensions);
+
+
+ bool detectSphere_with_Vertex(const glm::vec3 &v, const glm::vec3 triangle_normal, const glm::vec3 &posA, const glm::vec3 &posB);
+ bool detectSphere_with_Edge(const glm::vec3 &v1, const glm::vec3 &v2,
+ const glm::vec3 &triangle_normal,
+ const glm::vec3 &posA, const glm::vec3 &posB);
+ void makeCollisionData(const float t, const glm::vec3 triangle_n, const glm::vec3 intersection_pos, const glm::vec3 point_of_contact, const bool isVertex);
+ bool detectSphere_with_Interior(const Triangle &triangle, const glm::vec3 posA, const glm::vec3 posB);
+
+
+ bool isSameDirection(const glm::vec3 edge1, const glm::vec3 edge2, const glm::vec3 n);
+ glm::vec3 getTriangleEdge(const glm::vec3 v1, const glm::vec3 v2);
+ float raycastSphere(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const glm::vec3 posA, const glm::vec3 posB);
+ float raycastTriangle(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const Triangle &triangle);
+ float solveQuadratic(float a, float b, float c);
+ glm::vec3 getIntersectionPt(const glm::vec3 &ray_p, const glm::vec3 &ray_d, const float t);
+ Triangle convertTriangleToSphereSpace(const glm::vec3 &orig_R, const Triangle &orig_triangle);
+
+ std::vector<CollisionData> m_collisionData;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+
+ glm::vec3 m_ellipsoid_dimensions = glm::vec3(1.0);
+
+ float ZERO = -.0001f;
+ float ONE = 1.0001f;
+
+ std::shared_ptr<ModelTransform> m_conversion_mt;
+ glm::mat3 m_scale_normals_mt = glm::mat3(1.f);
+
+ std::vector<std::shared_ptr<GameObject>> m_candidate_obstacles;
+ std::unique_ptr<BVHTree> m_bvh_system;
+
+};
+
+#endif // ELLIPSOIDTRIANGLECOLLISIONSYSTEM_H
diff --git a/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp
new file mode 100644
index 0000000..3470dd8
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.cpp
@@ -0,0 +1,93 @@
+#include "environmentcollisiondetectionsystem.h"
+#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include <utility>
+
+EnvironmentCollisionDetectionSystem::EnvironmentCollisionDetectionSystem(
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables,
+ std::map<std::string, BlackboardData>& global_blackboard) :
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_ellipsoid_triangle_collision_system(std::make_unique<EllipsoidTriangleCollisionSystem>(rigid_gameobjects)),
+ m_global_blackboard(global_blackboard),
+ m_lootables(lootables)
+{
+
+}
+
+TransformComponent* EnvironmentCollisionDetectionSystem::getTransform(std::shared_ptr<GameObject> &go){
+ return go->getComponent<TransformComponent>();
+
+}
+
+CollisionComponent* EnvironmentCollisionDetectionSystem::getCollisionComp(std::shared_ptr<GameObject> &go){
+ return go->getComponent<CollisionComponent>();
+}
+
+void EnvironmentCollisionDetectionSystem::detectCollisionWithEnvironment(double deltaTime){
+ for (auto &go : m_dynamic_gameobjects){
+ collideDynamic(go.first, go.second);
+
+ }
+}
+
+
+void EnvironmentCollisionDetectionSystem::collideDynamic(std::string go_name, std::shared_ptr<GameObject> go){
+ if (!go->hasComponent<CollisionComponent>()){
+ return;
+ }
+
+ std::pair<std::vector<CollisionData>, glm::vec3> pair =
+ m_ellipsoid_triangle_collision_system->mtvSlide(getTransform(go)->old_pos,
+ //getTransform(go.second)->estimated_final_pos,
+ m_global_blackboard[go_name].locationData.setToPos,
+ getCollisionComp(go)->getCollisionShape<BoundingDynamicMesh>()->getEllipsoidDimensions());
+
+ // assume not on ground first; then determine if we are touching ground
+ getTransform(go)->onGround = false;
+ m_global_blackboard[go_name].conditionData["onGround"].conditionTrue = false;
+ for (const CollisionData &collision : pair.first){
+ if (glm::dot(glm::vec3(0,1,0), collision.triangle_n) > 0.f){
+ getTransform(go)->onGround = true;
+ m_global_blackboard[go_name].conditionData["onGround"].conditionTrue = true;
+
+ }
+ }
+
+ if (getTransform(go)->onGround){
+ if (getTransform(go)->yVelocity < 0){
+ getTransform(go)->yVelocity = 0.f;
+ getTransform(go)->gravity = 0.f;
+ }
+ }
+
+ if (!getTransform(go)->onGround){
+ getTransform(go)->gravity = -25.f;
+ }
+
+
+ if (!getTransform(go)->movingLaterally &&
+ getTransform(go)->onGround){
+ getTransform(go)->setPos(getTransform(go)->old_pos);
+ } else {
+ getTransform(go)->setPos(pair.second);
+ }
+
+ getCollisionComp(go)->getCollisionShape<BoundingDynamicMesh>()->updateCenterPos(getTransform(go)->getPos());
+}
+
+
+void EnvironmentCollisionDetectionSystem::update(double deltaTime){
+ detectCollisionWithEnvironment(deltaTime);
+}
+
+void EnvironmentCollisionDetectionSystem::draw(){}
+void EnvironmentCollisionDetectionSystem::scrollEvent(double distance){}
+void EnvironmentCollisionDetectionSystem::mousePosEvent(double xpos, double ypos){}
+
+
+
diff --git a/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h
new file mode 100644
index 0000000..8beca39
--- /dev/null
+++ b/engine-ocean/Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h
@@ -0,0 +1,43 @@
+#ifndef ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H
+#define ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H
+
+
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include <memory>
+#include "Game/Systems/system.h"
+
+class EnvironmentCollisionDetectionSystem /*: public System*/
+{
+public:
+ EnvironmentCollisionDetectionSystem(
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables,
+ std::map<std::string, BlackboardData>& global_blackboard);
+ void draw() ;
+ void update(double deltaTime);
+ void scrollEvent(double distance);
+ void mousePosEvent(double xpos, double ypos) ;
+
+
+private:
+ void detectCollisionWithEnvironment(double deltaTime);
+ CollisionComponent* getCollisionComp(std::shared_ptr<GameObject> &go);
+ TransformComponent* getTransform(std::shared_ptr<GameObject> &go);
+
+ void collideDynamic(std::string go_name, std::shared_ptr<GameObject> go);
+
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::unique_ptr<EllipsoidTriangleCollisionSystem> m_ellipsoid_triangle_collision_system;
+ //std::unique_ptr<BVHTree> m_bvh_system;
+ std::vector<std::shared_ptr<GameObject>> all_rigid_go;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables;
+
+};
+
+#endif // ENVIRONMENTCOLLISIONDETECTIONSYSTEM_H
diff --git a/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp b/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp
new file mode 100644
index 0000000..44f20ef
--- /dev/null
+++ b/engine-ocean/Game/Systems/Inventory/inventoryitem.cpp
@@ -0,0 +1,33 @@
+#include "inventoryitem.h"
+
+InventoryItem::InventoryItem(const char* worldLabelFile, const char* inventoryLabelFile,
+ glm::vec2 worldLabelScale,
+ glm::vec2 inventoryLabelScale,
+ std::set<std::string>& m_shownScreens)
+{
+ TextureData worldLabelTex = Global::graphics.loadTextureFromFile(worldLabelFile);
+ TextureData inventoryLabelTex = Global::graphics.loadTextureFromFile(inventoryLabelFile);
+
+ m_world_label = std::make_shared<UIDisplay>(worldLabelTex, glm::vec2(0.f), worldLabelScale, m_shownScreens, AspectRatio::LAND_FIT);
+ m_inventory_label = std::make_shared<UIDisplay>(inventoryLabelTex, glm::vec2(0.f), inventoryLabelScale, m_shownScreens, AspectRatio::LAND_FIT);
+}
+
+void InventoryItem::updateWorldLabelPos(glm::vec2 pos){
+ m_world_label->setPos(pos);
+}
+
+glm::mat4 InventoryItem::getWorldLabelTransformationMat(){
+ return m_world_label->getTransformationMat();
+}
+
+GLuint InventoryItem::getWorldLabelTexID(){
+ return m_world_label->getTexID();
+}
+
+float InventoryItem::getWorldLabelTexAspect(){
+ return m_world_label->getTextureScaleAspect();
+}
+
+std::shared_ptr<UIDisplay> InventoryItem::getUIDisplay(){
+ return m_world_label;
+}
diff --git a/engine-ocean/Game/Systems/Inventory/inventoryitem.h b/engine-ocean/Game/Systems/Inventory/inventoryitem.h
new file mode 100644
index 0000000..efa093b
--- /dev/null
+++ b/engine-ocean/Game/Systems/Inventory/inventoryitem.h
@@ -0,0 +1,31 @@
+#ifndef INVENTORYITEM_H
+#define INVENTORYITEM_H
+
+
+#include "Game/Systems/UI/UITextures/uidisplay.h"
+class InventoryItem
+{
+public:
+ InventoryItem(const char* worldLabelFile, const char* inventoryLabelFile,
+ glm::vec2 worldLabelScale,
+ glm::vec2 inventoryLabelScale,
+ std::set<std::string>& m_shownScreens);
+ void updateWorldLabelPos(glm::vec2 pos);
+ glm::mat4 getWorldLabelTransformationMat();
+ GLuint getWorldLabelTexID();
+ float getWorldLabelTexAspect();
+ std::shared_ptr<UIDisplay> getUIDisplay();
+
+
+
+
+
+private:
+ std::shared_ptr<UIDisplay> m_world_label;
+ std::shared_ptr<UIDisplay> m_inventory_label;
+
+ int m_inventoryCount = 0;
+
+};
+
+#endif // INVENTORYITEM_H
diff --git a/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp b/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp
new file mode 100644
index 0000000..46f5558
--- /dev/null
+++ b/engine-ocean/Game/Systems/Inventory/inventorysystem.cpp
@@ -0,0 +1,206 @@
+#include "inventorysystem.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/drawcomponent.h"
+#include "Game/Components/transformcomponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/GameWorld.h"
+#include <memory>
+
+InventorySystem::InventorySystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& all_gameobjects,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables,
+ std::map<int, Input>& input_map,
+ std::shared_ptr<Camera>& camera,
+ std::set<std::string>& m_shownScreens):
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_input_map(input_map),
+ m_camera(camera),
+ m_lootables(lootables),
+ m_shownScreens(m_shownScreens),
+ m_all_gameobjects(all_gameobjects)
+{
+ int m_bamboo_count = 0;
+ m_screenVAO = Global::graphics.makeVAO(m_quadPos);
+
+ //m_texID = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/enterbutton.png").textureID;
+
+
+ initializeInventory("mushroom",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mushroom_loot.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mushroom_loot.png");
+ initializeInventory("amantia",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/amantia_loot.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/amantia_loot.png");
+
+ TextureData sparkle = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/sparkle.png");
+ m_sparkle = std::make_shared<UIDisplay>(sparkle, glm::vec2(0.f), glm::vec2(.05f), m_shownScreens, AspectRatio::LAND_FIT);
+
+}
+
+InventorySystem::~InventorySystem(){
+ glDeleteVertexArrays(1, &m_screenVAO);
+}
+
+void InventorySystem::initializeInventory(std::string itemName, const char* label_filename, const char* inventory_filename){
+ std::shared_ptr<InventoryItem> inventoryItem = std::make_shared<InventoryItem>(label_filename, inventory_filename, glm::vec2(.2f), glm::vec2(.5f), m_shownScreens);
+ m_inventoryItems.insert({itemName, inventoryItem});
+}
+
+
+void InventorySystem::addToInventory(std::shared_ptr<GameObject> &go){
+ // if G is pressed down, remove go from screen and add it to the inventory
+ if (m_input_map.at(GLFW_KEY_P).isActive){
+ if (go->hasComponent<DrawComponent>()){
+ go->removeComponent<DrawComponent>();
+ go->removeComponent<CollisionComponent>();
+ m_bamboo_count += 1;
+ }
+ }
+}
+
+bool InventorySystem::withinPlayerReach(const std::shared_ptr<GameObject> &go){
+ glm::vec3 player_pos = m_dynamic_gameobjects.at("player")->getComponent<TransformComponent>()->getPos();
+
+ // be careful --> the below line will crash if its attempting to get an object with multiple
+ // transforms, like the ground!
+ glm::vec3 go_pos = go->getComponent<TransformComponent>()->getPos();
+
+ float vicinity = 3.f;
+ // is player and game object are close in either x or z dir
+ if ((abs(player_pos.x - go_pos.x) < vicinity)
+ && (abs(player_pos.z - go_pos.z) < vicinity)
+ && (abs(player_pos.y - go_pos.y) < vicinity)){
+ return true;
+ }
+ return false;
+}
+
+void InventorySystem::drawUIText(){
+ Global::graphics.drawUIText(Global::graphics.getFont("opensans"), std::to_string(m_bamboo_count) + " bamboo collected.", glm::ivec2(20, 90), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1));
+ Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Collect 20 bamboos to clear the game.", glm::ivec2(20, 110), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1));
+
+ if (m_bamboo_count >= 20){
+ Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "You Won! Press 'R' to restart.", glm::ivec2(200, 300), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.4f, 0.4f, glm::vec3(1, 1, 1));
+ }
+}
+
+
+
+
+void InventorySystem::draw(){
+ // bind shader
+ Global::graphics.bindShader("inventory");
+
+ // for window resizing
+ Global::graphics.setCameraData(m_camera);
+
+ // enable alpha blending
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // disable depth testing
+ glDisable(GL_DEPTH_TEST);
+
+ // for every item in inventory, compute screen coordinates and draw if near player and on the screen
+ glm::mat4 proj = m_camera->getProjection();
+ glm::mat4 view = m_camera->getView();
+
+ // if home page is rendered
+ if (m_shownScreens.contains("home")){
+ glBindVertexArray(m_screenVAO);
+ glEnableVertexAttribArray(0);
+
+ for (auto &lootID : m_lootables){
+ for (auto &lootObject : lootID.second){
+ glm::vec3 pos = lootObject->getComponent<TransformComponent>()->getMT()->getPos();
+ glm::vec4 projected = proj*view*glm::vec4(pos, 1.f);
+ glm::vec2 screen = glm::vec2(projected.x/projected.w, projected.y/projected.w);
+
+ // if visible on screen
+ if ((-1.f < screen.x && screen.x < 1.f) && (-1.f < screen.y && screen.y < 1.f)){
+
+
+
+ // update texture pos, and draw associated texture
+ if (withinPlayerReach(lootObject)){
+ // update pos
+ m_inventoryItems[lootID.first]->updateWorldLabelPos(screen + m_offset);
+
+ // get uniforms
+ glm::mat4 transMat = m_inventoryItems[lootID.first]->getWorldLabelTransformationMat();
+ GLuint texID = m_inventoryItems[lootID.first]->getWorldLabelTexID();
+ float texAspect = m_inventoryItems[lootID.first]->getWorldLabelTexAspect();
+
+ glActiveTexture(GL_TEXTURE6);
+ glBindTexture(GL_TEXTURE_2D, texID);
+ glm::vec2 texScale = glm::vec2(1.f, texAspect);
+ glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "textureScale"), texScale.x, texScale.y);
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0]));
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ }
+ // draw sparkle
+ else {
+ // update pos
+ m_sparkle->setPos(screen);
+
+ // get uniforms
+ glm::mat4 transMat = m_sparkle->getTransformationMat();
+ GLuint texID = m_sparkle->getTexID();
+ float texAspect = m_sparkle->getTextureScaleAspect();
+
+ glActiveTexture(GL_TEXTURE6);
+ glBindTexture(GL_TEXTURE_2D, texID);
+ glm::vec2 texScale = glm::vec2(1.f/texAspect, 1.f);
+ glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "textureScale"), texScale.x, texScale.y);
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("inventory"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0]));
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ }
+ }
+
+ }
+
+ }
+
+ glDisableVertexAttribArray(0);
+ glBindVertexArray(0);
+ }
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+void InventorySystem::update(double deltaTime){
+
+ // remove from m_lootables to remove labels and drawing
+ for (auto &lootGroup : m_lootables){
+ for (auto itr = lootGroup.second.begin(); itr != lootGroup.second.end();){
+ auto& loot = *itr;
+ if (withinPlayerReach(loot) && m_input_map.at(GLFW_KEY_P).isActive){
+ loot->removeComponent<DrawComponent>();
+ itr = lootGroup.second.erase(itr);
+ } else {
+ ++itr;
+ }
+ }
+ }
+
+ // remove game object entirely based on if its not drawn
+// for(auto it = m_all_gameobjects.begin(); it != m_all_gameobjects.end();){
+// if (!it->second->hasComponent<DrawComponent>()){
+// it = m_all_gameobjects.erase(it);
+// }
+// }
+}
+
+void InventorySystem::onWindowResize(int width, int height){
+ for (auto &lootID : m_lootables){
+ m_inventoryItems[lootID.first]->getUIDisplay()->setWindowPos(width, height);
+
+ }
+}
+
+void InventorySystem::scrollEvent(double distance){}
+void InventorySystem::mousePosEvent(double xpos, double ypos){}
+
diff --git a/engine-ocean/Game/Systems/Inventory/inventorysystem.h b/engine-ocean/Game/Systems/Inventory/inventorysystem.h
new file mode 100644
index 0000000..4305f68
--- /dev/null
+++ b/engine-ocean/Game/Systems/Inventory/inventorysystem.h
@@ -0,0 +1,78 @@
+#ifndef INVENTORYSYSTEM_H
+#define INVENTORYSYSTEM_H
+
+
+#include "Game/GameWorld.h"
+#include <map>
+#include "inventoryitem.h"
+
+//struct InventoryItem{
+// TextureData lootLabelUI;
+// TextureData lootInventoryUI;
+// int inventoryCount = 0;
+
+// InventoryItem(TextureData label, TextureData inventory):
+// lootLabelUI(label),
+// lootInventoryUI(inventory)
+// {}
+//};
+
+class InventorySystem : public System
+{
+public:
+ InventorySystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& all_gameobjects,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables,
+ std::map<int, Input>& input_map,
+ std::shared_ptr<Camera>& camera,
+ std::set<std::string>& m_shownScreens);
+ ~InventorySystem();
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+ void drawUIText();
+ void onWindowResize(int width, int height);
+
+
+
+private:
+ void addToInventory(std::shared_ptr<GameObject> &go);
+ bool withinPlayerReach(const std::shared_ptr<GameObject> &go);
+ void initializeInventory(std::string itemName, const char* label_filename, const char* inventory_filename);
+
+
+
+
+
+ int m_bamboo_count = 0;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+
+ // maps loot id to game objects/associated textures
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables; // holds position
+ std::map<std::string, std::shared_ptr<InventoryItem>> m_inventoryItems;
+
+ std::map<int, Input>& m_input_map;
+ std::shared_ptr<Camera>& m_camera;
+
+ //std::set<std::string> m_inventoryScreens; // stores ids of all scenes in which inventory is rendered
+ std::set<std::string>& m_shownScreens;
+
+ std::vector<float> m_quadPos = {
+ -1.0f, 1.0f,
+ -1.0f, -1.0f,
+ 1.0f, 1.0f,
+ 1.0f, -1.0f
+ };
+
+ GLuint m_screenVAO;
+ GLuint m_texID;
+
+ glm::vec2 m_offset = glm::vec2(.2f);
+
+ std::shared_ptr<UIDisplay> m_sparkle;
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_all_gameobjects;
+};
+
+#endif // INVENTORYSYSTEM_H
diff --git a/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp
new file mode 100644
index 0000000..8abbec8
--- /dev/null
+++ b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.cpp
@@ -0,0 +1,35 @@
+#include "aimovementsystem.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/Components/PathfindComponent.h"
+#include "Game/Systems/AI/aibehaviorcomponent.h"
+
+AIMovementSystem::AIMovementSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects) :
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_rigid_gameobjects(rigid_gameobjects)
+
+{
+ // m_path = m_rigid_gameobjects.at("navmesh")->getComponent<PathfindComponent>()->getPath(glm::vec3(-0.58249, 0, -0.0210782), glm::vec3(19.5371, 0, 1.39167));
+
+}
+
+TransformComponent* AIMovementSystem::getTransform(std::shared_ptr<GameObject> &go){
+ return go->getComponent<TransformComponent>();
+}
+
+
+void AIMovementSystem::update(double deltaTime){
+ for (auto &go : m_dynamic_gameobjects){
+ if (go.second->hasComponent<AIBehaviorComponent>()){
+ go.second->getComponent<AIBehaviorComponent>()->update(deltaTime);
+ }
+ }
+}
+
+
+
+
+void AIMovementSystem::draw(){}
+void AIMovementSystem::scrollEvent(double distance){}
+void AIMovementSystem::mousePosEvent(double xpos, double ypos){}
+
diff --git a/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h
new file mode 100644
index 0000000..e880e44
--- /dev/null
+++ b/engine-ocean/Game/Systems/Pathfinding/aimovementsystem.h
@@ -0,0 +1,34 @@
+#ifndef AIMOVEMENTSYSTEM_H
+#define AIMOVEMENTSYSTEM_H
+#include "Game/Components/TransformComponent.h"
+#include "Game/Systems/Pathfinding/pathfinder.h"
+#include "Game/Systems/system.h"
+
+
+class AIMovementSystem : public System
+{
+public:
+ AIMovementSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+private:
+ float gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity);
+ TransformComponent* getTransform(std::shared_ptr<GameObject> &go);
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+
+
+ float horiz_velocity = .005f;
+ float snapshot_time = 0.f;
+
+ std::vector<glm::vec3> m_path;
+
+ //std::shared_ptr<Pathfinder> m_pathfinder;
+};
+
+#endif // AIMOVEMENTSYSTEM_H
diff --git a/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp b/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp
new file mode 100644
index 0000000..35d67d2
--- /dev/null
+++ b/engine-ocean/Game/Systems/Pathfinding/pathfinder.cpp
@@ -0,0 +1,321 @@
+#include "pathfinder.h"
+#include "glm/glm.hpp"
+#include "glm/gtx/hash.hpp"
+
+#include <iostream>
+#include <set>
+#include <vector>
+
+// there can be multiple pathfinders for multiple environemnt meshes
+// pathfinding/environment component for an environment mesh?
+Pathfinder::Pathfinder(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles):
+ m_vertices(vertices),
+ m_triangles(triangles)
+{
+ initializeEdges();
+}
+
+// for entire scene, generate data structure that holds nav mesh
+void Pathfinder::initializeEdges(){
+
+ std::map<std::pair<int,int>, TriangleEdge> temp_data;
+
+ // indices of vertex pairs
+ std::vector<std::pair<int,int>> range = {std::make_pair(0, 1),
+ std::make_pair(1, 2),
+ std::make_pair(2, 0)};
+
+ // make edges for all triangles and populate temp_data map
+ for (glm::vec3 triangle : m_triangles){
+ std::vector<std::pair<int,int>> keys;
+ for (auto index_pair : range ){
+ // make ordered pair of the index of vertex held by triangle , for all edges
+ std::pair<int, int> key = makeOrderedPair(triangle[index_pair.first], triangle[index_pair.second]);
+ keys.push_back(key);
+
+ if (temp_data.count(key) != 0){
+ temp_data.at(key).count ++;
+ } else {
+ // make a new entry that populates the midpoint
+ TriangleEdge edge = {m_vertices[key.first], m_vertices[key.second]};
+ temp_data.insert(std::make_pair(key, edge));
+ }
+ }
+
+ for (auto key : keys){
+ // add the two neighbors for each key
+ for (auto neighbor_id : keys){
+ if (key != neighbor_id){
+ temp_data.at(key).adjacentEdges.insert(neighbor_id);
+ }
+ }
+ }
+ }
+
+ std::set<std::pair<int,int>> interiorEdges;
+
+ // remove exterior edges from adjacent lists
+ for (auto &entry : temp_data){
+ // make new adjacency list
+ std::set<std::pair<int,int>> edited_adj_list;
+
+ for (const auto adjNode : entry.second.adjacentEdges){
+ // if adjacent node is an interior node, add to new adj list
+ if (temp_data.at(adjNode).count > 1){
+ edited_adj_list.insert(adjNode);
+ }
+ }
+
+ // reassign adj list
+ entry.second.adjacentEdges.swap(edited_adj_list);
+ }
+
+ // add interior edges
+ for (const auto &entry : temp_data){
+ if (entry.second.count > 1){
+ ANode node;
+ node.adjacentNodes = entry.second.adjacentEdges;
+ node.pos = entry.second.midpoint;
+ m_navdata.insert(std::make_pair(entry.first, node));
+ }
+ }
+
+
+}
+
+
+std::pair<int, int> Pathfinder::makeOrderedPair(int i, int j){
+ std::pair<int, int> pair = std::pair(std::min(i,j), std::max(i,j));
+ return pair;
+}
+
+// traverse navmeshgraph
+// A --> start ; B --> destination
+std::vector<glm::vec3> Pathfinder::findPath(const glm::vec3 A, const glm::vec3 B){
+ // start and end indices are double pair because no existing edge has two of the same vertices
+ m_startNodePos = A;
+ m_endNodePos = B;
+
+ // initialize empty path
+ std::vector<glm::vec3> empty;
+ empty.push_back(glm::vec3(0.f));
+
+ // initialize start and ending node
+ ANode startNode, endNode;
+ startNode.pos = m_startNodePos;
+ endNode.pos = m_endNodePos;
+ startNode.Gcost = 0;
+ m_navdata.insert(std::pair(startNodeID, startNode));
+ m_navdata.insert(std::pair(endNodeID, endNode));
+
+
+ // calculate distance to end point for each item in map
+ for (auto &node : m_navdata){
+ node.second.Hcost = getDistance(node.second.pos, B);
+ updateFCost(node.first);
+ }
+
+ // determine if one or both start/end points are in navmesh or not
+ std::pair<bool, std::set<std::pair<int, int>>> validStartPoint = findEnclosingTriangle(A);
+ std::pair<bool, std::set<std::pair<int, int>>> validEndPoint = findEnclosingTriangle(B);
+
+ // if neither or both points can be found in navmesh, end early
+ if (!validStartPoint.first || !validEndPoint.first){
+ std::cout << "-- a point is not in navmesh" << std::endl;
+ return empty;
+ }
+
+ // if both points are on same triangle, then return only the destination
+ if (validStartPoint.second == validEndPoint.second){
+ std::vector<glm::vec3> destination;
+ destination.push_back(B);
+ std::cout << "-- SAME TRIANGLE" << std::endl;
+ return destination;
+ }
+
+ std::set<std::pair<int,int>> open;
+ std::set<std::pair<int,int>> closed;
+
+ // initialize open list
+ // check if id is a valid interior node
+ for (const auto &id : validStartPoint.second){
+ if (m_navdata.contains(id)){
+ m_navdata[id].previousV = startNodeID;
+ m_navdata[id].Gcost = getDistance(m_navdata[id].pos, m_startNodePos);
+ updateFCost(id);
+ open.insert(id);
+ }
+ }
+
+ // calculate paths with Astar
+ bool reachable = traverseAStar(startNodeID, validEndPoint.second, open, closed);
+
+ if (reachable){
+ std::cout << "reachable!" << std::endl;
+ return getNavigablePath(startNodeID, endNodeID);
+ }
+
+ // otherwise, return glm::vec3(0) so that entity doesnt move
+ std::cout << "not reachable" << std::endl;
+ return empty;
+}
+
+void Pathfinder::updateFCost(const std::pair<int,int> &node){
+ m_navdata[node].Fcost = m_navdata[node].Gcost + m_navdata[node].Hcost;
+
+}
+
+bool Pathfinder::traverseAStar(const std::pair<int,int> &currNodeID, const std::set<std::pair<int,int>> &endpointNodeIDs,
+ std::set<std::pair<int,int>> &open, std::set<std::pair<int,int>> &closed){
+
+ glm::vec3 currNodePos = m_navdata.at(currNodeID).pos;
+
+ // base case: if looking at nodes that are way too far from entity start pos, then just end
+ if (getDistance(currNodePos, m_startNodePos) > m_maxDistance){
+ std::cout << "-- DISTANCE TOO FAR" << std::endl;
+ return false;
+ }
+
+ float lowestF = INFINITY;
+ float lowestH = INFINITY;
+ std::pair<int,int> C; // where C is the next node to visit
+
+ for (const std::pair<int,int> &nodeID : open){
+ // calculate G, which also populates F
+ // --------------- do i also need to check if the previous f cost was less than the updated f cost?
+ float new_Gcost = getDistance(m_navdata[nodeID].pos, currNodePos) + m_navdata[currNodeID].Gcost;
+ m_navdata[nodeID].Gcost = new_Gcost;
+ updateFCost(nodeID);
+
+ if (m_navdata[nodeID].Fcost == lowestF){
+ // go by lowest H if F costs are equal
+ if (m_navdata[nodeID].Hcost < lowestH){
+ C = nodeID;
+ lowestF = m_navdata[nodeID].Fcost;
+ lowestH = m_navdata[nodeID].Hcost;
+ }
+ }
+
+ if (m_navdata[nodeID].Fcost < lowestF){
+ C = nodeID;
+ lowestF = m_navdata[nodeID].Fcost;
+ lowestH = m_navdata[nodeID].Hcost;
+ }
+ }
+
+ // move C from open to closed list
+ open.erase(C);
+ closed.insert(C);
+
+ //if C is equal to any of the endpoint indices, then path is found
+ for (const std::pair<int,int> &id : endpointNodeIDs){
+ if (C == id){
+ m_navdata[endNodeID].previousV = C;
+ return true;
+ }
+ }
+
+ // for neighbor N of C
+ for (const std::pair<int,int> &N: m_navdata[C].adjacentNodes){
+ if (closed.contains(N)) continue;
+
+ // calculate potential F cost of C-->N
+ float new_Gcost = getDistance(m_navdata[N].pos, m_navdata[C].pos) + m_navdata[C].Gcost;
+ float new_Fcost = new_Gcost + m_navdata[N].Hcost;
+
+ if (new_Fcost < m_navdata[N].Fcost || !open.contains(N)){
+ // update N's G and F cost
+ m_navdata[N].Gcost = new_Gcost;
+ updateFCost(N);
+ // set previous node of N to be C
+ m_navdata[N].previousV = C;
+
+ // add N to open if its not already in it
+ open.insert(N);
+ }
+ }
+
+ // if there are still open nodes, visit the next one (recurse)
+ if (!open.empty()){
+ traverseAStar(C, endpointNodeIDs, open, closed);
+ }
+
+ // otherwise no more open nodes, thus a* has finished
+ return true;
+}
+
+
+// distance is the un-squarerooted distance between two points
+float Pathfinder::getDistance(glm::vec3 a, glm::vec3 b){
+ return pow(a.x-b.x, 2) + pow(a.y-b.y, 2) + pow(a.z-b.z, 2);
+}
+
+
+// referenced from https://blackpawn.com/texts/pointinpoly/default.html
+bool Pathfinder::sameSide(glm::vec3 p1, glm::vec3 p2, glm::vec3 a, glm::vec3 b){
+ glm::vec3 cp1 = glm::cross(b-a, p1-a);
+ glm::vec3 cp2 = glm::cross(b-a, p2-a);
+
+ glm::vec3 a1 = glm::vec3(cp1.x, cp1.y + .001, cp1.z);
+ glm::vec3 a2 = glm::vec3(cp1.x, cp1.y - .001, cp1.z);
+
+ glm::vec3 b1 = glm::vec3(cp2.x, cp2.y + .001, cp2.z);
+ glm::vec3 b2 = glm::vec3(cp2.x, cp2.y - .001, cp2.z);
+
+
+ if (glm::dot(a1, b1) >= 0 || glm::dot(a2, b2) >= 0
+ || glm::dot(a1, b2) >= 0 || glm::dot(a2, b1) >= 0) return true;
+ return false;
+}
+
+bool Pathfinder::pointInTriangle(glm::vec3 p, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3){
+ if (sameSide(p,v1, v2,v3) && sameSide(p,v2, v1,v3) && sameSide(p,v3, v1,v2)) return true;
+ return false;
+}
+
+std::pair<bool, std::set<std::pair<int, int>>> Pathfinder::findEnclosingTriangle(glm::vec3 point){
+
+ // for each triangle in navmesh, get its vertices
+ for (glm::vec3 vertex_triple : m_triangles){
+ // if point is in any navmesh triangle, then return the 3 nodes associated with that tri
+ if (pointInTriangle(point, m_vertices[vertex_triple[0]], m_vertices[vertex_triple[1]], m_vertices[vertex_triple[2]])){
+ return std::make_pair(true, getEnclosingTriangleEdges(vertex_triple));
+ }
+ }
+
+ // if no triangles contained the point, return false
+ return std::make_pair(false, getEnclosingTriangleEdges(glm::vec3(0.f)));
+}
+
+// gets node indices
+std::set<std::pair<int, int>> Pathfinder::getEnclosingTriangleEdges(glm::vec3 indices){
+ std::set<std::pair<int, int>> ids;
+ ids.insert(makeOrderedPair(indices[0], indices[1]));
+ ids.insert(makeOrderedPair(indices[1], indices[2]));
+ ids.insert(makeOrderedPair(indices[2], indices[0]));
+
+ return ids;
+}
+
+std::vector<glm::vec3> Pathfinder::getNavigablePath(const std::pair<int,int> &start, const std::pair<int,int> &end){
+ // start at B, and use previousV pointers to get back to A
+ std::vector<glm::vec3> path;
+ path.push_back(m_navdata[end].pos);
+
+ std::pair<int,int> currV = end;
+
+ while (currV != start){
+ // add current point to path
+ glm::vec3 pos = m_navdata[m_navdata[currV].previousV].pos;
+ path.push_back(pos);
+
+ // reassign variable to where currV points, and enter loop again
+ currV = m_navdata[currV].previousV;
+ }
+
+ // path where the very last entry is the start point, and the very first entry is the end point
+ return path;
+
+}
+
+
diff --git a/engine-ocean/Game/Systems/Pathfinding/pathfinder.h b/engine-ocean/Game/Systems/Pathfinding/pathfinder.h
new file mode 100644
index 0000000..d9abbd6
--- /dev/null
+++ b/engine-ocean/Game/Systems/Pathfinding/pathfinder.h
@@ -0,0 +1,83 @@
+#ifndef PATHFINDER_H
+#define PATHFINDER_H
+
+#include "glm/fwd.hpp"
+#include "glm/gtx/hash.hpp"
+
+
+#include <map>
+#include <set>
+#include <vector>
+
+struct ANode{
+ glm::vec3 pos;
+ // A* related:
+ float Hcost = 0; // distance to destination
+ float Gcost = 0; // distance from start to current node (accumulative G)
+ float Fcost = Gcost+Hcost;
+ std::pair<int,int> previousV;
+ std::set<std::pair<int,int>> adjacentNodes;
+};
+
+struct TriangleEdge{
+ glm::vec3 midpoint;
+ std::set<std::pair<int,int>> adjacentEdges;
+
+ TriangleEdge(glm::vec3 v1, glm::vec3 v2):
+ midpoint(.5f*(v2+v1))
+ {}
+ // num of times it appears in the navgraph
+ int count = 1;
+};
+
+class Pathfinder
+{
+public:
+ Pathfinder(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles);
+ std::vector<glm::vec3> findPath(const glm::vec3 A, const glm::vec3 B);
+
+
+
+private:
+
+ void updateFCost(const std::pair<int,int> &node);
+
+
+
+
+ bool traverseAStar(const std::pair<int,int> &currNodeID, const std::set<std::pair<int,int>> &endpointNodeIDs,
+ std::set<std::pair<int,int>> &open, std::set<std::pair<int,int>> &closed);
+
+ std::set<std::pair<int, int>> getEnclosingTriangleEdges(glm::vec3 indices);
+
+ void initializeEdges();
+ float getDistance(glm::vec3 a, glm::vec3 b);
+ std::vector<glm::vec3> getNavigablePath(const std::pair<int,int> &start, const std::pair<int,int> &end);
+ std::pair<bool, std::set<std::pair<int, int>>> findEnclosingTriangle(glm::vec3 point);
+ bool pointInTriangle(glm::vec3 p, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3);
+ bool sameSide(glm::vec3 p1, glm::vec3 p2, glm::vec3 a, glm::vec3 b);
+
+ std::set<std::vector<float>> getAdjacentNodes(const std::set<std::pair<int,int>> &id_pairs, std::map<std::pair<int,int>, TriangleEdge> &temp_data);
+
+
+ std::pair<int, int> makeOrderedPair(int i, int j);
+
+ // maps pos (midpoint of a edge) to node
+ std::map<std::pair<int,int>, ANode> m_navdata;
+ std::vector<glm::vec3> m_vertices;
+ std::vector<glm::ivec3> m_triangles;
+ glm::vec3 m_startNodePos;
+ glm::vec3 m_endNodePos;
+
+ std::pair<int,int> startNodeID = std::make_pair(0,0);
+ std::pair<int,int> endNodeID = std::make_pair(1,1);
+
+
+ float m_maxDistance = 500; // 20 meters max distance that an ai can pathfind
+
+
+
+
+};
+
+#endif // PATHFINDER_H
diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp
new file mode 100644
index 0000000..c7314f6
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.cpp
@@ -0,0 +1,6 @@
+#include "buttonaction.h"
+
+ButtonAction::ButtonAction()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h
new file mode 100644
index 0000000..d6c1674
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/ButtonAction/buttonaction.h
@@ -0,0 +1,13 @@
+#ifndef BUTTONACTION_H
+#define BUTTONACTION_H
+
+
+class ButtonAction
+{
+public:
+ ButtonAction();
+ virtual void activate() = 0;
+ virtual void deactivate() = 0;
+};
+
+#endif // BUTTONACTION_H
diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp
new file mode 100644
index 0000000..e6b9797
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.cpp
@@ -0,0 +1,33 @@
+#include "showwindowaction.h"
+#include "Game/Systems/UI/uisystem.h"
+#include <map>
+
+ShowWindowAction::ShowWindowAction(std::map<std::string, std::shared_ptr<UIScreen>>& all_screens,
+ std::set<std::string>& shownScreens,
+ const std::string screenName):
+ m_screens(all_screens),
+ m_shownScreens(shownScreens)
+{
+ m_screenName = screenName;
+}
+
+
+
+void ShowWindowAction::activate(){
+ std::cout << "activated window show!!!" << std::endl;
+
+ // add screen to be rendered, and also set it be the only one active
+ //m_screens[m_screenName] = m_screen;
+// for (auto &screen : m_screens){
+// screen.second->isActive = false;
+// }
+
+// m_screens[m_screenName]->isActive = true;
+ m_shownScreens.insert(m_screenName);
+ m_screens[m_screenName]->isActive = true;
+
+}
+
+void ShowWindowAction::deactivate(){
+ m_shownScreens.erase(m_screenName);
+}
diff --git a/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h
new file mode 100644
index 0000000..781f093
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/ButtonAction/showwindowaction.h
@@ -0,0 +1,21 @@
+#ifndef SHOWWINDOWACTION_H
+#define SHOWWINDOWACTION_H
+#include "Game/Systems/UI/uisystem.h"
+#include <map>
+#include "buttonaction.h"
+
+class ShowWindowAction : public ButtonAction
+{
+public:
+ ShowWindowAction(std::map<std::string, std::shared_ptr<UIScreen>>& screens,
+ std::set<std::string>& shownScreens,
+ const std::string screenName);
+ void activate() override;
+ void deactivate() override;
+private:
+ std::set<std::string>& m_shownScreens;
+ std::string m_screenName;
+ std::map<std::string, std::shared_ptr<UIScreen>>& m_screens;
+};
+
+#endif // SHOWWINDOWACTION_H
diff --git a/engine-ocean/Game/Systems/UI/UITextures/UIButton.h b/engine-ocean/Game/Systems/UI/UITextures/UIButton.h
new file mode 100644
index 0000000..8cf02ee
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/UIButton.h
@@ -0,0 +1,94 @@
+#ifndef UIBUTTON_H
+#define UIBUTTON_H
+#include "Game/Systems/UI/ButtonAction/buttonaction.h"
+#include "Game/Systems/UI/UITextures/uidisplay.h"
+#include "Graphics/global.h"
+#include <GLFW/glfw3.h>
+#include <set>
+#include "uitexture.h"
+
+enum CornerPosition {
+ TOPLEFT,
+ TOPRIGHT,
+ BOTTOMLEFT,
+ BOTTOMRIGHT,
+ NONE
+};
+
+class UIButton : public UITexture
+{
+public:
+ UIButton(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens,
+ bool isCloseButton = false, CornerPosition corner = NONE, AspectRatio ratio = LAND_FIT);
+ ~UIButton();
+ void draw() override;
+ GLuint getTexID() override;
+ glm::vec2 getPos() override;
+ glm::vec2 getScale() override;
+ float getTextureRatio() override;
+ AspectRatio getAspectRatio();
+
+
+
+ void setWindowPos(int width, int height) override;
+ glm::vec2 getWindowPos();
+
+ int getHeight() override;
+ int getWidth() override;
+ Bounds2f getBounds() override;
+ float getTextureScaleAspect() override;
+
+ void addButtonAction(std::shared_ptr<ButtonAction> &action);
+ bool onButtonPress();
+ void setWindowToClose(std::string windowID);
+
+ void setParentDisplay(std::string parent);
+ std::string getParentDisplay();
+
+ CornerPosition getCornerPos();
+ bool hasCornerPos = false;
+ void setToCorner(const CornerPosition corner, int width, int height);
+
+ void setTransformationMat(glm::vec2 translation, glm::vec2 scale);
+ glm::mat4 getTransformationMat();
+
+
+
+private:
+ glm::mat4 getScaleMatrix(glm::vec2 scale);
+ int getScreenHeight();
+ int getScreenWidth();
+ void setTexID(GLuint &newTexID);
+
+
+ TextureData m_tex;
+ glm::vec2 m_pos;
+ glm::vec2 m_scale;
+ Bounds2f m_bounds;
+ glm::vec2 m_windowPos; // width, height
+ float m_windowHeight = 480.f;
+ float m_windowWidth = 640.f;
+ float m_toScreenScale = 1.f;
+
+ int m_screenImageHeight;
+ int m_screenImageWidth;
+ float m_tex_aspectRatio = 1.f;
+ bool m_isCloseButton = false;
+ std::string m_attachedWindow;
+
+ std::vector<std::shared_ptr<ButtonAction>> m_actions;
+ std::set<std::string>& m_shownScreens;
+
+ CornerPosition m_cornerPos;
+ std::string m_parentDisplay;
+
+ glm::mat4 m_transformationMat;
+ float m_textureAspect = 1.f;
+
+ AspectRatio m_aspectRatio;
+
+
+
+};
+
+#endif // UIButton_H
diff --git a/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp b/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp
new file mode 100644
index 0000000..031be2f
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/uibutton.cpp
@@ -0,0 +1,202 @@
+#include "UIButton.h"
+#include "Game/Systems/UI/UITextures/UIDisplay.h"
+#include <set>
+
+UIButton::UIButton(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens,
+ bool isCloseButton, CornerPosition corner, AspectRatio ratio):
+ m_tex(tex),
+ m_shownScreens(shownScreens),
+ m_aspectRatio(ratio)
+{
+
+ // set variables
+ m_isCloseButton = isCloseButton;
+ m_pos = pos;
+ m_scale = scale;
+ m_tex_aspectRatio = static_cast<float>(m_tex.height)/static_cast<float>(m_tex.width);
+
+ setToCorner(corner, 640, 480);
+ setWindowPos(640, 480);
+ setTransformationMat(m_pos, scale);
+
+}
+UIButton::~UIButton(){
+ glDeleteTextures(1, &m_tex.textureID);
+}
+
+
+AspectRatio UIButton::getAspectRatio(){
+ return m_aspectRatio;
+}
+
+glm::mat4 UIButton::getScaleMatrix(glm::vec2 scale) {
+ glm::mat4 M = glm::mat4(1.f);
+ M[0][0] = scale.x; //* (m_screenImageHeight/m_screenImageWidth);
+ M[1][1] = scale.y; //* (m_tex_aspectRatio);
+ M[2][2] = 1.f;
+ return M;
+}
+
+void UIButton::setTransformationMat(glm::vec2 translation, glm::vec2 scale){
+ glm::mat4 transMat = glm::mat4(1.f);
+ transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f);
+ glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale));
+ m_transformationMat = transMat*scaleMat;
+}
+
+glm::mat4 UIButton::getTransformationMat(){
+ return m_transformationMat;
+}
+
+float UIButton::getTextureRatio(){
+ return m_tex_aspectRatio;
+}
+
+
+void UIButton::draw(){}
+
+GLuint UIButton::getTexID(){
+ return m_tex.textureID;
+}
+
+glm::vec2 UIButton::getPos(){
+ return m_pos;
+}
+
+glm::vec2 UIButton::getScale(){
+ return m_scale;
+}
+
+//void UIButton::setTexID(GLuint &newTexID){
+// m_tex.textureID = newTexID;
+//}
+
+void UIButton::setWindowPos(int width, int height){
+ m_windowHeight = static_cast<float>(height);
+ m_windowWidth = static_cast<float>(width);
+
+ // find where on window it is, for bound checking
+ float xpos = .5f*(m_pos.x + 1.f)*m_windowWidth;
+ float ypos = (1.f-.5f*(m_pos.y + 1.f))*m_windowHeight;
+ m_windowPos = glm::vec2(xpos, ypos);
+
+ // set everything according to window dimensions -- this is for bound checking
+ m_toScreenScale = m_windowHeight*m_scale.y;
+ m_screenImageHeight = m_toScreenScale;
+ m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio;
+
+ float windowRatio = m_windowHeight/m_windowWidth;
+ m_textureAspect = windowRatio / m_tex_aspectRatio;
+
+ // calculate window bounds
+ glm::vec2 halfDimensions = glm::vec2(m_screenImageWidth, m_screenImageHeight)*.5f;
+ m_bounds.max = glm::vec2(m_windowPos.x + halfDimensions.x, m_windowPos.y - halfDimensions.y);
+ m_bounds.min = glm::vec2(m_windowPos.x - halfDimensions.x, m_windowPos.y + halfDimensions.y);
+}
+
+float UIButton::getTextureScaleAspect(){
+ return m_textureAspect;
+}
+
+void UIButton::setParentDisplay(std::string parent){
+ m_parentDisplay = parent;
+
+}
+
+std::string UIButton::getParentDisplay(){
+ return m_parentDisplay;
+
+}
+
+CornerPosition UIButton::getCornerPos(){
+ return m_cornerPos;
+
+}
+
+void UIButton::setToCorner(const CornerPosition corner, int width, int height){
+
+ m_toScreenScale = static_cast<float>(height)*m_scale.y;
+ m_screenImageHeight = m_toScreenScale;
+ m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio;
+
+ // in texture space
+ float xtrans = m_screenImageWidth/(.5f*static_cast<float>(width));
+ float ytrans = m_screenImageHeight/(.5f*static_cast<float>(height));
+
+ // find where window pos should be
+ switch(corner){
+ case TOPLEFT:
+ m_pos = glm::vec2(-1+xtrans, 1-ytrans);
+
+ break;
+ case TOPRIGHT:
+ m_pos = glm::vec2(1-xtrans, 1-ytrans);
+
+ break;
+ case BOTTOMLEFT:
+ m_pos = glm::vec2(-1+xtrans, -1+ytrans);
+
+ break;
+ case BOTTOMRIGHT:
+ m_pos = glm::vec2(1-xtrans, -1+ytrans);
+ break;
+ default:
+ break;
+ }
+}
+
+glm::vec2 UIButton::getWindowPos(){
+ return m_windowPos;
+}
+
+int UIButton::getHeight(){
+ return m_tex.height;
+}
+int UIButton::getWidth(){
+ return m_tex.width;
+}
+
+int UIButton::getScreenHeight(){
+ return m_screenImageHeight;
+}
+int UIButton::getScreenWidth(){
+ return m_screenImageWidth;
+}
+
+// remember that origin is top left corner!!
+Bounds2f UIButton::getBounds(){
+
+ return m_bounds;
+}
+
+void UIButton::addButtonAction(std::shared_ptr<ButtonAction> &action){
+ m_actions.push_back(action);
+}
+
+//////*/ for close button only
+void UIButton::setWindowToClose(std::string windowID){
+ if (m_isCloseButton){
+ m_attachedWindow = windowID;
+ }
+
+}
+
+bool UIButton::onButtonPress(){
+ // if button is a close button, then deactivate everything
+ if (m_isCloseButton){
+ std::cout << "shownWindowSize: " << m_shownScreens.size() << std::endl;
+ //m_shownScreens.erase(m_attachedWindow);
+ std::cout << "new shownWindowSize: " << m_shownScreens.size() << std::endl;
+ std::cout << "CLOSE WINDOW: " << m_attachedWindow << std::endl;
+ return true;
+
+
+ } else {
+ for (auto &action : m_actions){
+ action->activate();
+ }
+ return false;
+ }
+
+}
+
diff --git a/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp
new file mode 100644
index 0000000..2ddaf62
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.cpp
@@ -0,0 +1,130 @@
+#include "uidisplay.h"
+#include <set>
+
+UIDisplay::UIDisplay(TextureData tex, glm::vec2 pos, glm::vec2 scale,
+ std::set<std::string>& shownScreens,
+ AspectRatio ratio):
+ m_tex(tex),
+ m_shownScreens(shownScreens),
+ m_aspectRatio(ratio)
+{
+
+ m_pos = (pos);
+ m_scale = (scale);
+ m_tex_aspectRatio = static_cast<float>(m_tex.height)/static_cast<float>(m_tex.width);
+ setTransformationMat(pos, scale);
+// std::cout << "tex aspect ratio:" << m_tex_aspectRatio << std::endl;
+
+// std::cout << "aspect ratio w: " << m_tex.width << std::endl;
+// std::cout << "aspect ratio h: " << m_tex.height << std::endl;
+
+
+ setWindowPos(640, 480);
+// std::cout << "screen image height: " << m_screenImageHeight << std::endl;
+// std::cout << "screen image width: " << m_screenImageWidth << std::endl;
+
+}
+
+UIDisplay::~UIDisplay(){
+ glDeleteTextures(1, &m_tex.textureID);
+}
+
+void UIDisplay::draw(){}
+
+GLuint UIDisplay::getTexID(){
+ return m_tex.textureID;
+}
+
+glm::vec2 UIDisplay::getPos(){
+ return m_pos;
+}
+
+glm::vec2 UIDisplay::getScale(){
+ return m_scale;
+}
+
+AspectRatio UIDisplay::getAspectRatio(){
+ return m_aspectRatio;
+}
+
+void UIDisplay::setWindowPos(int width, int height){
+ float xpos = .5f*(m_pos.x + 1.f)*static_cast<float>(width);
+ float ypos = (1.f-.5f*(m_pos.y + 1.f))*static_cast<float>(height);
+ m_windowPos = glm::vec2(xpos, ypos);
+
+ // set everything according to window dimensions
+ m_toScreenScale = static_cast<float>(height)*m_scale.y;
+ m_screenImageHeight = m_toScreenScale;
+ m_screenImageWidth = m_toScreenScale * m_tex_aspectRatio;
+
+ float windowRatio = static_cast<float>(height)/static_cast<float>(width);
+ m_textureAspect = windowRatio / m_tex_aspectRatio;
+}
+
+void UIDisplay::setPos(glm::vec2 pos){
+ m_pos = pos;
+ setTransformationMat(m_pos, m_scale);
+}
+void UIDisplay::setScale(glm::vec2 scale){
+ m_scale = scale;
+ setTransformationMat(m_pos, m_scale);
+}
+
+float UIDisplay::getTextureScaleAspect(){
+ return m_textureAspect;
+}
+
+glm::vec2 UIDisplay::getWindowPos(){
+ return m_windowPos;
+}
+
+int UIDisplay::getHeight(){
+ return m_tex.height;
+}
+int UIDisplay::getWidth(){
+ return m_tex.width;
+}
+
+int UIDisplay::getScreenHeight(){
+ return m_screenImageHeight;
+}
+int UIDisplay::getScreenWidth(){
+ return m_screenImageWidth;
+}
+
+glm::mat4 UIDisplay::getScaleMatrix(glm::vec2 scale) {
+ glm::mat4 M = glm::mat4(1.f);
+ M[0][0] = scale.x;//* (m_screenImageHeight/m_screenImageWidth);
+ M[1][1] = scale.y; //* (m_tex_aspectRatio);
+ M[2][2] = 1.f;
+ return M;
+}
+
+void UIDisplay::setTransformationMat(glm::vec2 translation, glm::vec2 scale){
+ glm::mat4 transMat = glm::mat4(1.f);
+ transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f);
+
+ glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale));
+
+ m_transformationMat = transMat*scaleMat;
+}
+
+glm::mat4 UIDisplay::getTransformationMat(){
+ return m_transformationMat;
+}
+
+// remember that origin is top left corner!!
+Bounds2f UIDisplay::getBounds(){
+ glm::vec2 halfDimensions = glm::vec2(m_screenImageWidth, m_screenImageHeight)*.5f;
+ m_bounds.max = glm::vec2(m_windowPos.x + halfDimensions.x, m_windowPos.y - halfDimensions.y);
+ m_bounds.min = glm::vec2(m_windowPos.x - halfDimensions.x, m_windowPos.y + halfDimensions.y);
+ return m_bounds;
+}
+
+float UIDisplay::getTextureRatio(){
+ return m_tex_aspectRatio;
+}
+
+
+
+
diff --git a/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h
new file mode 100644
index 0000000..4b739cc
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/uidisplay.h
@@ -0,0 +1,67 @@
+#ifndef UIDISPLAY_H
+#define UIDISPLAY_H
+#include "uitexture.h"
+#include <set>
+
+
+
+class UIDisplay : public UITexture
+{
+public:
+ UIDisplay(TextureData tex, glm::vec2 pos, glm::vec2 scale, std::set<std::string>& shownScreens,
+ AspectRatio ratio = FIT_SCREEN);
+ ~UIDisplay();
+ void draw() override;
+ GLuint getTexID() override;
+ glm::vec2 getPos() override;
+ glm::vec2 getScale() override;
+
+ void setWindowPos(int width, int height) override;
+ glm::vec2 getWindowPos();
+
+ int getHeight() override;
+ int getWidth() override;
+ Bounds2f getBounds() override;
+ float getTextureRatio() override;
+ float getTextureScaleAspect() override;
+ void setPos(glm::vec2 pos);
+ void setScale(glm::vec2 scale);
+
+ AspectRatio getAspectRatio();
+
+
+ // glm::vec2 getCornerPos(CornerPosition corner, glm::vec2 elementDimensions);
+ void setTransformationMat(glm::vec2 translation, glm::vec2 scale);
+ glm::mat4 getTransformationMat();
+
+private:
+ int getScreenHeight();
+ int getScreenWidth();
+ void setTexID(GLuint &newTexID);
+ glm::mat4 getScaleMatrix(glm::vec2 scale);
+
+
+
+ TextureData m_tex;
+ glm::vec2 m_pos;
+ glm::vec2 m_scale;
+ Bounds2f m_bounds;
+ glm::vec2 m_windowPos; // width, height
+ int m_windowHeight = 480.f;
+ int m_windowWidth = 640.f;
+ float m_toScreenScale = 1.f;
+
+ int m_screenImageHeight;
+ int m_screenImageWidth;
+ float m_tex_aspectRatio = 1.f;
+ bool m_isCloseButton = false;
+ std::string m_attachedWindow;
+
+ std::set<std::string>& m_shownScreens;
+ glm::mat4 m_transformationMat;
+ float m_textureAspect = 1.f;
+
+ AspectRatio m_aspectRatio;
+};
+
+#endif // UIDISPLAY_H
diff --git a/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp b/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp
new file mode 100644
index 0000000..8680baf
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/uitexture.cpp
@@ -0,0 +1,6 @@
+#include "uitexture.h"
+
+UITexture::UITexture()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/UI/UITextures/uitexture.h b/engine-ocean/Game/Systems/UI/UITextures/uitexture.h
new file mode 100644
index 0000000..53e429d
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/UITextures/uitexture.h
@@ -0,0 +1,39 @@
+#ifndef UITEXTURE_H
+#define UITEXTURE_H
+#include "Graphics/global.h"
+#include <GLFW/glfw3.h>
+
+struct Bounds2f{
+ glm::vec2 min;
+ glm::vec2 max;
+};
+
+enum AspectRatio {
+ LAND_FIT,
+ LAND_FILL,
+ PORTRAIT_FIT,
+ PORTRAIT_FILL,
+ FIT_SCREEN
+};
+
+class UITexture
+{
+public:
+ UITexture();
+ virtual void draw() = 0;
+ virtual GLuint getTexID() = 0;
+ virtual glm::vec2 getPos() = 0;
+ virtual glm::vec2 getScale() = 0;
+ virtual int getHeight() = 0;
+ virtual int getWidth() = 0;
+ virtual Bounds2f getBounds() = 0;
+ virtual void setWindowPos(int width, int height) = 0;
+ virtual float getTextureRatio() = 0;
+ virtual float getTextureScaleAspect() = 0;
+
+
+
+
+};
+
+#endif // UITEXTURE_H
diff --git a/engine-ocean/Game/Systems/UI/uielement.cpp b/engine-ocean/Game/Systems/UI/uielement.cpp
new file mode 100644
index 0000000..bb7d91f
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/uielement.cpp
@@ -0,0 +1,6 @@
+#include "uielement.h"
+
+UIElement::UIElement()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/UI/uielement.h b/engine-ocean/Game/Systems/UI/uielement.h
new file mode 100644
index 0000000..c2c3a2e
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/uielement.h
@@ -0,0 +1,40 @@
+#ifndef UIELEMENT_H
+#define UIELEMENT_H
+
+
+#include "Game/Systems/UI/UITextures/uitexture.h"
+#include "Game/TypeMap.h"
+#include <memory>
+class UIElement
+{
+public:
+ UIElement();
+
+ template <typename T>
+ void addComponent(std::unique_ptr<T> &&component){
+ m_components.put<T>(std::forward<std::unique_ptr<T>>(component));
+ }
+
+ template <typename T>
+ bool hasComponent(){
+ return m_components.contains<T>();
+ }
+
+ template <class T>
+ T* getComponent(){
+ auto comp = m_components.find<T>();
+ assert(comp != m_components.end());
+ return static_cast<T*>(comp->second.get());
+ }
+
+ template <class T>
+ void removeComponent(){
+ m_components.remove<T>();
+ }
+
+private:
+
+ TypeMap<std::unique_ptr<UITexture>> m_components;
+};
+
+#endif // UIELEMENT_H
diff --git a/engine-ocean/Game/Systems/UI/uisystem.cpp b/engine-ocean/Game/Systems/UI/uisystem.cpp
new file mode 100644
index 0000000..09aff49
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/uisystem.cpp
@@ -0,0 +1,383 @@
+#include "uisystem.h"
+#include "Game/GameWorld.h"
+#include "Game/Systems/UI/ButtonAction/showwindowaction.h"
+#include "Game/Systems/UI/UITextures/UIButton.h"
+#include "Game/Systems/UI/UITextures/uidisplay.h"
+#define GLFW_POINTING_HAND_CURSOR
+
+UISystem::UISystem(std::shared_ptr<Camera> camera,
+ std::map<int, Input>& input_map,
+ std::set<std::string>& shownScreens):
+ m_camera(camera),
+ m_input_map(input_map),
+ m_shownScreens(shownScreens)
+{
+
+
+ initializeStartScreen();
+ initializeScreenMap();
+ //m_pointerCursor = glfwCreateStandardCursor(GLFW_POINTING_HAND_CURSOR);
+
+}
+
+UISystem::~UISystem(){
+ for (auto &screenID : m_all_screens){
+ glDeleteVertexArrays(1, &screenID.second->screenVAOID);
+ }
+}
+
+void UISystem::initializeScreenMap(){
+ initializeProfileScreen();
+ initializeInventory();
+ initializeScreen();
+
+ m_shownScreens.insert("home");
+
+}
+
+void UISystem::initializeScreen(){
+ std::shared_ptr<UIScreen> home = std::make_shared<UIScreen>();
+ home->isActive = true;
+ home->screenVAOID = Global::graphics.makeVAO(m_quadPos);
+ m_quad_numVertices = 4;
+
+ float topLevel = .85f;
+
+ makeButtonElement(home, "profileButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/profileicon.png", glm::vec2(.85f,topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL);
+ std::shared_ptr<ButtonAction> showProfile = std::make_shared<ShowWindowAction>(m_all_screens, m_shownScreens, "profile");
+ home->screenElements.at("profileButton")->getComponent<UIButton>()->addButtonAction(showProfile);
+
+ makeButtonElement(home, "inventoryButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventoryicon.png", glm::vec2(.75f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL);
+ std::shared_ptr<ButtonAction> showInv = std::make_shared<ShowWindowAction>(m_all_screens, m_shownScreens, "inventory");
+ home->screenElements.at("inventoryButton")->getComponent<UIButton>()->addButtonAction(showInv);
+
+ makeButtonElement(home, "questsButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/questicon.png", glm::vec2(.65f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL);
+ makeButtonElement(home, "settingsButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/settings_icon.png", glm::vec2(-.85f, topLevel), glm::vec2(.05f), AspectRatio::LAND_FILL);
+ makeDisplayElement(home, "healthbar", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/healthbar.png", glm::vec2(0.f, -.5f), glm::vec2(.4f), AspectRatio::LAND_FIT);
+
+// TextureData reflectTex;
+// reflectTex.textureID = Global::graphics.getReflectionTexture();
+// reflectTex.width = Global::graphics.REFLECTION_W;
+// reflectTex.height = Global::graphics.REFLECTION_H;
+// makeDisplayElement(home, "reflection", reflectTex, glm::vec2(.5f, -.5f), glm::vec2(.3f), AspectRatio::LAND_FIT);
+
+// TextureData refractTex;
+// refractTex.textureID = Global::graphics.getRefractionTexture();
+// refractTex.width = Global::graphics.REFRACTION_W;
+// refractTex.height = Global::graphics.REFRACTION_H;
+// makeDisplayElement(home, "refract", refractTex, glm::vec2(-.5f, -.5f), glm::vec2(.3f), AspectRatio::LAND_FIT);
+
+
+
+
+ home->elementsDepthOrder.push_back("profileButton");
+ home->elementsDepthOrder.push_back("inventoryButton");
+ home->elementsDepthOrder.push_back("questsButton");
+ home->elementsDepthOrder.push_back("settingsButton");
+ home->elementsDepthOrder.push_back("healthbar");
+ // home->elementsDepthOrder.push_back("reflection");
+ // home->elementsDepthOrder.push_back("refract");
+
+
+
+ m_all_screens.insert({"home", home});
+}
+
+void UISystem::initializeProfileScreen(){
+
+ std::shared_ptr<UIScreen> profile = std::make_shared<UIScreen>();
+ profile->isActive = false;
+ profile->screenVAOID = Global::graphics.makeVAO(m_quadPos);
+ m_quad_numVertices = 4;
+
+ float topLevel = .85f;
+
+ // eventually should be display, not button
+ makeDisplayElement(profile, "bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_bg.png", glm::vec2(0.f), glm::vec2(1.0f));
+ makeDisplayElement(profile, "profileDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse_profile.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT);
+ makeButtonElement(profile, "closeButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/close_icon.png", glm::vec2(0.f), glm::vec2(.05f), AspectRatio::LAND_FILL, true, CornerPosition::TOPRIGHT);
+ profile->screenElements.at("closeButton")->getComponent<UIButton>()->setWindowToClose("profile");
+
+ profile->elementsDepthOrder.push_back("bg");
+ profile->elementsDepthOrder.push_back("profileDisplay");
+ profile->elementsDepthOrder.push_back("closeButton");
+
+ m_all_screens.insert({"profile", profile});
+}
+
+void UISystem::initializeInventory(){
+ std::shared_ptr<UIScreen> inv = std::make_shared<UIScreen>();
+ inv->isActive = false;
+ inv->screenVAOID = Global::graphics.makeVAO(m_quadPos);
+ m_quad_numVertices = 4;
+
+ makeDisplayElement(inv, "bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_bg.png", glm::vec2(0.f), glm::vec2(1.0f));
+ makeDisplayElement(inv, "inventoryDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/inventory_page.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT);
+ makeButtonElement(inv, "closeButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/close_icon.png", glm::vec2(0.f), glm::vec2(.05f), AspectRatio::LAND_FILL, true, CornerPosition::TOPRIGHT);
+ inv->screenElements.at("closeButton")->getComponent<UIButton>()->setWindowToClose("inventory");
+ inv->elementsDepthOrder.push_back("bg");
+ inv->elementsDepthOrder.push_back("inventoryDisplay");
+ inv->elementsDepthOrder.push_back("closeButton");
+
+ m_all_screens.insert({"inventory", inv});
+}
+
+void UISystem::initializeStartScreen(){
+
+ std::shared_ptr<UIScreen> start = std::make_shared<UIScreen>();
+ start->isActive = true;
+ start->screenVAOID = Global::graphics.makeVAO(m_quadPos);
+
+ float topLevel = .85f;
+
+ // eventually should be display, not button
+ makeDisplayElement(start, "startDisplay", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/title.png", glm::vec2(0.f), glm::vec2(1.0f), AspectRatio::LAND_FIT);
+ makeButtonElement(start, "startButton", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/enterbutton.png", glm::vec2(0.f, -.57f), glm::vec2(.19f), AspectRatio::LAND_FIT, true);
+ start->screenElements.at("startButton")->getComponent<UIButton>()->setWindowToClose("start");
+
+ start->elementsDepthOrder.push_back("startDisplay");
+ start->elementsDepthOrder.push_back("startButton");
+
+ m_all_screens.insert({"start", start});
+ m_shownScreens.insert("start");
+}
+
+glm::vec2 UISystem::drawAspect(AspectRatio aspectType, float textureAspect){
+ switch(aspectType){
+ case FIT_SCREEN:
+ return glm::vec2(1.f);
+ break;
+ case LAND_FIT:case PORTRAIT_FILL:
+ return glm::vec2(1.f, textureAspect);
+ break;
+ case LAND_FILL: case PORTRAIT_FIT:
+ return glm::vec2(1.f/textureAspect, 1.f);
+ break;
+ }
+}
+
+
+
+void UISystem::makeButtonElement(std::shared_ptr<UIScreen> &screen,
+ std::string elementName, const char* filename,
+ const glm::vec2 pos, const glm::vec2 scale,
+ AspectRatio aspectRatio,
+ bool isCloseButton,
+ CornerPosition corner){
+ TextureData tex = Global::graphics.loadTextureFromFile(filename);
+
+ std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>();
+
+ uiElement->addComponent<UIButton>(std::make_unique<UIButton>(tex, pos, scale, m_shownScreens, isCloseButton, corner, aspectRatio));
+ screen->screenElements.insert({elementName, uiElement});
+}
+
+void UISystem::makeDisplayElement(std::shared_ptr<UIScreen> &screen,
+ std::string elementName, const char* filename,
+ const glm::vec2 pos, const glm::vec2 scale,
+ AspectRatio aspectRatio){
+ TextureData tex = Global::graphics.loadTextureFromFile(filename);
+
+ std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>();
+ uiElement->addComponent<UIDisplay>(std::make_unique<UIDisplay>(tex, pos, scale, m_shownScreens, aspectRatio));
+ screen->screenElements.insert({elementName, uiElement});
+}
+
+void UISystem::makeDisplayElement(std::shared_ptr<UIScreen> &screen,
+ std::string elementName, TextureData &tex,
+ const glm::vec2 pos, const glm::vec2 scale,
+ AspectRatio aspectRatio){
+
+ std::shared_ptr<UIElement> uiElement = std::make_shared<UIElement>();
+ uiElement->addComponent<UIDisplay>(std::make_unique<UIDisplay>(tex, pos, scale, m_shownScreens, aspectRatio));
+ screen->screenElements.insert({elementName, uiElement});
+}
+
+void UISystem::renderScreen(){
+ // bind shader
+ Global::graphics.bindShader("ui");
+
+ // for window resizing
+ Global::graphics.setCameraData(m_camera);
+
+ // enable alpha blending
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // disable depth testing
+ glDisable(GL_DEPTH_TEST);
+
+ for (auto &screenID : m_shownScreens){
+ // bind quad
+ glBindVertexArray(m_all_screens[screenID]->screenVAOID);
+ glEnableVertexAttribArray(0);
+
+ // loop through inventory ui elements
+
+ // loop through ui elements
+ for (auto &gui: m_all_screens[screenID]->elementsDepthOrder){
+ if (m_all_screens[screenID]->screenElements[gui]->hasComponent<UIDisplay>()){
+ GLuint texID;
+ if (gui == "reflection"){
+ //std::cout << "rendering reflection" << std::endl;
+ texID = Global::graphics.getReflectionTexture();
+ } else if (gui == "refract"){
+ texID = Global::graphics.getRefractionTexture();
+ } else {
+ texID = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTexID();
+ }
+ glm::mat4 transMat = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTransformationMat();
+ float texAspect = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getTextureScaleAspect();
+ AspectRatio ratio = m_all_screens[screenID]->screenElements[gui]->getComponent<UIDisplay>()->getAspectRatio();
+
+ glActiveTexture(GL_TEXTURE5);
+ glBindTexture(GL_TEXTURE_2D, texID);
+
+ glm::vec2 texScale = drawAspect(ratio, texAspect);
+
+ glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("ui"), "textureScale"), texScale.x, texScale.y);
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("ui"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0]));
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, m_quad_numVertices);
+ }
+ if (m_all_screens[screenID]->screenElements[gui]->hasComponent<UIButton>()){
+ GLuint texID = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTexID();
+ glm::mat4 transMat = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTransformationMat();
+ float texAspect = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getTextureScaleAspect();
+ AspectRatio ratio = m_all_screens[screenID]->screenElements[gui]->getComponent<UIButton>()->getAspectRatio();
+
+ glActiveTexture(GL_TEXTURE5);
+ glBindTexture(GL_TEXTURE_2D, texID);
+
+ glm::vec2 texScale = drawAspect(ratio, texAspect);
+
+ glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("ui"), "textureScale"), texScale.x, texScale.y);
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("ui"), "transform"), 1, GL_FALSE, glm::value_ptr(transMat[0]));
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, m_quad_numVertices);
+
+
+ }
+
+ }
+ glDisableVertexAttribArray(0);
+ glBindVertexArray(0);
+ }
+ glDisable(GL_BLEND);
+ glEnable(GL_DEPTH_TEST);
+}
+
+
+
+void UISystem::draw(){
+ renderScreen();
+}
+
+glm::mat4 UISystem::getScaleMatrix(glm::vec2 scale) {
+ glm::mat4 M = glm::mat4(1.f);
+ M[0][0] = scale.x * (m_aspectRatio);
+ M[1][1] = scale.y;
+ M[2][2] = 0.f;
+ return M;
+}
+
+glm::mat4 UISystem::makeTransformationMat(glm::vec2 translation, glm::vec2 scale){
+ glm::mat4 transMat = glm::mat4(1.f);
+ transMat[3] = glm::vec4(translation.x, translation.y, 0.f, 1.f);
+
+ glm::mat4 scaleMat = getScaleMatrix(glm::vec2(scale));
+
+ return transMat*scaleMat;
+}
+
+void UISystem::update(double deltaTime){
+ // allow for one more update cycle before deactivating click
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isClicked){
+ // check if clicked inside gui
+ // only act on the front-most gui being clicked
+ std::set<std::string>::iterator it = m_shownScreens.begin();
+ while(it != m_shownScreens.end()) {
+ std::set<std::string>::iterator current = it++;
+ std::string screenID = *current;
+ // render all active screens
+ if (m_all_screens[screenID]->isActive){
+ // loop through ui elements
+ for (auto &gui: m_all_screens[screenID]->screenElements){
+ if (gui.second->hasComponent<UIButton>()){
+ bool isInside = false;
+ Bounds2f buttonBounds = gui.second->getComponent<UIButton>()->getBounds();
+ isInside = checkInsideGUI(m_mousepos, buttonBounds);
+ if (isInside){
+ bool toClose = gui.second->getComponent<UIButton>()->onButtonPress();
+ if (toClose){
+ m_shownScreens.erase(current);
+
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].checkClickTime > 1){
+ m_input_map[GLFW_MOUSE_BUTTON_LEFT].isClicked = false;
+ } else {
+ m_input_map[GLFW_MOUSE_BUTTON_LEFT].checkClickTime ++;
+ }
+ }
+}
+
+bool UISystem::checkInsideGUI(glm::vec2 mouseClickPos, Bounds2f guiBounds){
+ if (mouseClickPos.x < guiBounds.max.x
+ && mouseClickPos.x > guiBounds.min.x
+ && mouseClickPos.y > guiBounds.max.y
+ && mouseClickPos.y < guiBounds.min.y){
+ return true;
+ }
+
+ return false;
+}
+
+
+void UISystem::scrollEvent(double distance){}
+
+void UISystem::mousePosEvent(double xpos, double ypos){
+ m_mousepos = glm::vec2(xpos, ypos);
+
+ for (auto &screenID : m_shownScreens){
+ Global::graphics.bindShader("ui");
+ //glUniform1i(glGetUniformLocation(Global::graphics.getShaderID("ui"), "hovering"), false);
+ // render all active screens
+ if (m_all_screens[screenID]->isActive){
+ // loop through ui elements
+ for (auto &gui: m_all_screens[screenID]->screenElements){
+ if (gui.second->hasComponent<UIButton>()){
+ bool isInside;
+ Bounds2f buttonBounds = gui.second->getComponent<UIButton>()->getBounds();
+ isInside = checkInsideGUI(m_mousepos, buttonBounds);
+ if (isInside){
+ //glfwSetCursor(window, m_pointerCursor);
+ // hover effect
+ //glUniform1i(glGetUniformLocation(Global::graphics.getShaderID("ui"), "hovering"), true);
+ }
+ }
+ }
+ }
+ }
+}
+
+void UISystem::onWindowResize(int width, int height){
+ m_windowWidth = width;
+ m_windowHeight = height;
+ m_aspectRatio = static_cast<float>(m_windowHeight)/static_cast<float>(m_windowWidth);
+
+ for (auto &screen : m_all_screens){
+ // loop through ui elements
+ for (auto &gui: screen.second->screenElements){
+ if (gui.second->hasComponent<UIButton>()){
+ gui.second->getComponent<UIButton>()->setWindowPos(width, height);
+ }
+ if (gui.second->hasComponent<UIDisplay>()){
+ gui.second->getComponent<UIDisplay>()->setWindowPos(width, height);
+ }
+ }
+ }
+}
diff --git a/engine-ocean/Game/Systems/UI/uisystem.h b/engine-ocean/Game/Systems/UI/uisystem.h
new file mode 100644
index 0000000..1094861
--- /dev/null
+++ b/engine-ocean/Game/Systems/UI/uisystem.h
@@ -0,0 +1,89 @@
+#ifndef UISYSTEM_H
+#define UISYSTEM_H
+#include "Game/GameWorld.h"
+#include "Game/Systems/UI/UITextures/UIButton.h"
+#include "Game/Systems/UI/UITextures/uitexture.h"
+#include "Game/Systems/UI/uielement.h"
+#include "Graphics/global.h"
+#include <GLFW/glfw3.h>
+#include "Game/Systems/system.h"
+
+struct UIScreen{
+ bool isActive = false;
+ GLuint screenVAOID;
+ std::map<std::string, std::shared_ptr<UIElement>> screenElements;
+ std::vector<std::string> elementsDepthOrder;
+};
+
+
+class UISystem : public System
+{
+public:
+ UISystem(std::shared_ptr<Camera> camera,
+ std::map<int, Input>& input_map,
+ std::set<std::string>& shownScreens);
+ ~UISystem();
+
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+ void onWindowResize(int width, int height);
+ GLuint makeVAO(std::vector<float> positions);
+
+private:
+
+ int m_quad_numVertices = 4;
+
+ void initializeScreenMap();
+ void initializeScreen();
+ void initializeStartScreen();
+ void initializeInventory();
+
+
+ void renderScreen();
+ glm::mat4 makeTransformationMat(glm::vec2 translation, glm::vec2 scale);
+ glm::mat4 getScaleMatrix(glm::vec2 scale);
+ bool checkInsideGUI(glm::vec2 mouseClickPos, Bounds2f guiBounds);
+ void initializeProfileScreen();
+
+
+ void makeButtonElement(std::shared_ptr<UIScreen> &screen, std::string elementName, const char* filename, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio, bool isCloseButton = false, CornerPosition corner = NONE);
+ void makeDisplayElement(std::shared_ptr<UIScreen> &screen, std::string elementName, const char* filename, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio = FIT_SCREEN);
+ void makeDisplayElement(std::shared_ptr<UIScreen> &screen, std::string elementName, TextureData &tex, const glm::vec2 pos, const glm::vec2 scale, AspectRatio aspectRatio = FIT_SCREEN);
+
+
+
+ std::shared_ptr<Camera> m_camera;
+ float m_windowWidth = 640;
+ float m_windowHeight = 480;
+ float m_aspectRatio = 480.f/640.f;
+
+ glm::vec2 m_mousepos = glm::vec2(0.f);
+ std::map<int, Input>& m_input_map;
+
+ std::map<std::string, std::shared_ptr<UIScreen>> m_all_screens;
+
+ GLFWcursor* m_pointerCursor;
+
+ std::shared_ptr<ButtonAction> showProfileAction;
+
+ std::set<std::string>& m_shownScreens;
+ float m_showStartScreen = true;
+
+
+ float dim = 1.0f;
+ std::vector<float> m_quadPos = {
+ -1.0f, 1.0f,
+ -1.0f, -1.0f,
+ 1.0f, 1.0f,
+ 1.0f, -1.0f
+ };
+
+ glm::vec2 drawAspect(AspectRatio aspectType, float textureAspect);
+
+
+
+};
+
+#endif // UISYSTEM_H
diff --git a/engine-ocean/Game/Systems/aisystem.cpp b/engine-ocean/Game/Systems/aisystem.cpp
new file mode 100644
index 0000000..e3328ed
--- /dev/null
+++ b/engine-ocean/Game/Systems/aisystem.cpp
@@ -0,0 +1,6 @@
+#include "aisystem.h"
+
+AISystem::AISystem()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/aisystem.h b/engine-ocean/Game/Systems/aisystem.h
new file mode 100644
index 0000000..fe0b958
--- /dev/null
+++ b/engine-ocean/Game/Systems/aisystem.h
@@ -0,0 +1,36 @@
+#ifndef AISYSTEM_H
+#define AISYSTEM_H
+
+
+// where is player?
+#include "Game/GameObjects/GameObject.h"
+#include <map>
+#include <memory>
+#include <glm/glm.hpp>
+
+
+struct PosData{
+ glm::vec3 currPos;
+ glm::vec3 setToPos;
+};
+
+// did player jump? did player slash?
+struct ConditionData{
+ bool conditionTrue = false;
+};
+
+// BLACKBOARD
+struct BlackboardData{
+ PosData locationData;
+ std::map<std::string, ConditionData> conditionData;
+ std::shared_ptr<GameObject> environment;
+};
+
+
+class AISystem
+{
+public:
+ AISystem();
+};
+
+#endif // AISYSTEM_H
diff --git a/engine-ocean/Game/Systems/camerasystem.cpp b/engine-ocean/Game/Systems/camerasystem.cpp
new file mode 100644
index 0000000..7951e35
--- /dev/null
+++ b/engine-ocean/Game/Systems/camerasystem.cpp
@@ -0,0 +1,210 @@
+#include "camerasystem.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameWorld.h"
+#include <memory>
+#include <math.h>
+
+
+CameraSystem::CameraSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::shared_ptr<Camera>& camera,
+ std::map<int, Input>& input_map):
+ m_gameobjects(gameobjects),
+ m_camera(camera),
+ m_input_map(input_map),
+ first_person(false),
+ third_person(true),
+ m_player(m_gameobjects["player"])
+{
+ camera->setPos(glm::vec3(0.f, 15.f, 0.f));
+ camera->setLook(glm::vec3(-28.6761,5.40863,46.5823));
+
+
+}
+
+glm::vec3 CameraSystem::calculateIdealOffset(glm::vec3 initial){
+ //glm::quat playerRotation = glm::quat(
+// float y_rotate = m_player->getComponent<TransformComponent>()->getYRotationAngle();
+// glm::quat playerRot = glm::angleAxis(y_rotate, glm::vec3(0.f, 1.f, 0.f));
+ glm::vec4 idealOffset = glm::vec4(initial, 0.f);
+
+ glm::vec4 rotatedOffset = m_player->getComponent<TransformComponent>()->getMT()->getRotation() * idealOffset * .2f;
+ glm::vec3 rotated = glm::vec3(rotatedOffset) + m_player->getComponent<TransformComponent>()->getPos();
+
+ return rotated;
+}
+
+void CameraSystem::update(double deltaTime){
+ if (m_gameobjects["player"]->getComponent<TransformComponent>()->movingLaterally){
+ glm::vec3 player_pos = m_gameobjects["player"]->getComponent<TransformComponent>()->getPos();
+
+
+ glm::vec4 movement = m_distance*glm::vec4(1.f,0.f,0.f, 0.f);
+ glm::vec4 transl = m_gameobjects["player"]->getComponent<TransformComponent>()->getMT()->getRotation()*movement;
+ transl.y = 0.f;
+
+ glm::vec3 offset = glm::vec3(0.f, 5.f, 0.f);
+ glm::vec3 newPos = player_pos + glm::vec3(transl) + offset;
+
+ // arcballRotation(newPos.x, newPos.z);
+ m_camera->setPos(newPos);
+
+ if (glm::cross(m_camera->getUp(), player_pos) != glm::vec3(0.f)){
+ m_camera->setLook(player_pos);
+ }
+ }
+}
+
+
+void CameraSystem::draw(){
+ Global::graphics.bindShader("phong");
+ Global::graphics.setCameraData(m_camera);
+}
+
+void CameraSystem::firstPersonMode(){
+ first_person = true;
+ third_person = false;
+ m_camera->setPos(m_gameobjects["player"]->getComponent<TransformComponent>()->getPos());
+}
+
+void CameraSystem::thirdPersonMode(glm::vec3 curr_cam_pos){
+ first_person = false;
+ third_person = true;
+ //camera->setPos(curr_cam_pos);
+}
+
+void CameraSystem::scrollEvent(double distance){
+ // calculateZoom(distance);
+// m_distance += distance;
+// if (m_distance < 5.f) m_distance = 5.f;
+// if (m_distance > 40.f) m_distance = 40.f;
+}
+
+void CameraSystem::mousePosEvent(double xpos, double ypos){
+
+ // if right mouse button is pressed, calculate change of the new input x and y pos
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){
+ float deltaX = xpos - prev_mouse_pos.x;
+ float deltaY = ypos - prev_mouse_pos.y;
+
+ // upate prev mouse pos
+ prev_mouse_pos = glm::vec2(xpos, ypos);
+
+ arcballRotation(deltaX, deltaY);
+
+ }
+}
+
+void CameraSystem::calculateZoom(float scrollDistance){
+ float zoomLevel = scrollDistance*.1f;
+ m_distanceFromPlayer -= zoomLevel;
+}
+
+void CameraSystem::calculatePitch(double deltaY){
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){
+ float pitchChange = deltaY*.1f;
+ m_pitch -= pitchChange;
+ }
+}
+
+void CameraSystem::calculateAngleAroundPlayer(double deltaX){
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld){
+ float angleChange = deltaX*.3f;
+ m_angleAroundPlayer -= angleChange;
+ }
+}
+
+void CameraSystem::arcballRotation(float deltaX, float deltaY){
+ glm::vec4 cam_pos = glm::vec4(m_camera->getPos(), 1.f);
+ glm::vec4 pivot = glm::vec4(m_player->getComponent<TransformComponent>()->getPos(), 1.f);
+
+ // calculate rotation amount given mouse movement
+ float deltaAngleX = (2*M_PI / static_cast<float>(m_camera->getWidth()));
+ float deltaAngleY = (M_PI / static_cast<float>(m_camera->getHeight()));
+
+ float xAngle = deltaX * deltaAngleX;
+ float yAngle = deltaY * deltaAngleY;
+
+ // handles when camera dir is same as up vector
+ float cosAngle = glm::dot(m_camera->getViewDirection(), m_camera->getUp());
+ float sign = 1.f;
+ if (yAngle < 0) sign = -1.f;
+ if (cosAngle * sign > .99f) yAngle = 0;
+
+ // rotate camera around pivtor point
+ glm::mat4 rotX(1.f);
+ rotX = glm::rotate(rotX, xAngle, m_camera->getUp());
+ cam_pos = (rotX * (cam_pos - pivot)) + pivot;
+
+ glm::mat4 rotY(1.f);
+ rotY = glm::rotate(rotY, yAngle, m_camera->getRight());
+ glm::vec3 final_pos = (rotY * (cam_pos - pivot)) + pivot;
+
+ // update camera view
+ m_camera->setPos(final_pos);
+
+}
+
+void CameraSystem::setCameraPos(){
+// float horiz_distance = m_distanceFromPlayer*glm::cos(glm::radians(m_pitch));
+// float vert_distance = m_distanceFromPlayer*glm::sin(glm::radians(m_pitch));
+
+// glm::vec3 player_pos = m_gameobjects["player"]->getComponent<TransformComponent>()->getPos();
+// float y_camPos = player_pos.y + vert_distance;
+
+// float theta = glm::radians(m_angleAroundPlayer);
+// float offsetX = horiz_distance*glm::cos((theta));
+// float offsetZ = horiz_distance*glm::sin((theta));
+
+// glm::vec3 camPos = glm::vec3(player_pos.x - offsetX, y_camPos, player_pos.z - offsetZ);
+
+ // m_yaw = glm::radians(180-theta);
+
+// glm::vec3 lookVector = camPos +
+// glm::vec3(glm::cos(pitch)*glm::sin(m_yaw), glm::sin(pitch), glm::cos(pitch)*glm::cos(m_yaw));
+
+
+// glm::vec4 distanceCamToPlayer = glm::vec4(camPos - player_pos, 0.f);
+// glm::vec4 look = m_gameobjects["player"]->getComponent<TransformComponent>()->getMT()->getRotation() * distanceCamToPlayer;
+
+// //glm::vec3 idealOffset = (glm::vec3(-7.f, 5.f, -10.f)) + m_player->getComponent<TransformComponent>()->getPos();
+// glm::vec3 idealLookat = calculateIdealOffset(glm::vec3(0.f, -2.f, 40.f));
+
+// m_currPos = idealOffset;
+// m_currLook = idealLookat;
+
+// glm::vec3 direction;
+// direction.x = cos(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
+// direction.y = sin(glm::radians(m_pitch));
+// direction.z = sin(glm::radians(m_yaw)) * cos(glm::radians(m_pitch));
+
+// // calculate look
+// glm::vec4 rotatedPlayerPoint = m_player->getComponent<TransformComponent>()->getMT()->getRotation()* glm::vec4(player_pos, 1.f);
+// float distanceX = glm::distance(rotatedPlayerPoint.x, player_pos.x);
+// float distanceY = glm::distance(rotatedPlayerPoint.y, player_pos.y);
+// float distanceZ = glm::distance(rotatedPlayerPoint.z, player_pos.z);
+
+
+
+ //camPos = camPos + glm::vec3(distanceX, distanceY, distanceZ);
+ //glm::vec3 newLook = camPos - player_pos;
+
+
+
+ // glm::vec4 lookToPlayer = glm::vec4(camPos - player_pos, 0.f);
+ // glm::vec4 rotatedLook = m_player->getComponent<TransformComponent>()->getMT()->getRotation() * lookToPlayer;
+ // float distLookToPlayer = glm::distance(glm::vec3(rotatedLook), player_pos);
+
+
+ // m_camera->setPos(camPos);
+ //m_camera->translate(m_currPos);
+ //m_camera->rotate(m_yaw, glm::vec3(0.f, 1.f, 0.f));
+ //m_camera->setLook(newLook);
+
+
+ // m_camera->setPos(glm::vec3(x_camPos, y_camPos, z_camPos));
+
+
+
+
+}
+
diff --git a/engine-ocean/Game/Systems/camerasystem.h b/engine-ocean/Game/Systems/camerasystem.h
new file mode 100644
index 0000000..3ee6928
--- /dev/null
+++ b/engine-ocean/Game/Systems/camerasystem.h
@@ -0,0 +1,74 @@
+#ifndef CAMERASYSTEM_H
+#define CAMERASYSTEM_H
+
+
+#include "Game/GameWorld.h"
+#include "Graphics/camera.h"
+#include <memory>
+#include "system.h"
+
+class CameraSystem : public System
+{
+public:
+ CameraSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::shared_ptr<Camera>& camera,
+ std::map<int, Input>& input_map);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+private:
+ void firstPersonMode();
+ void thirdPersonMode(glm::vec3 curr_cam_pos);
+
+ void setCameraPos();
+ void calculateAngleAroundPlayer(double deltaX);
+ void calculatePitch(double deltaY);
+ void calculateZoom(float scrollDistance);
+
+ glm::vec3 calculateIdealOffset(glm::vec3 initial);
+ void arcballRotation(float deltaX, float deltaY);
+ float m_distance = -10.f;
+
+
+
+
+
+
+
+
+
+
+ std::shared_ptr<Camera>& m_camera;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects;
+ std::map<int, Input>& m_input_map;
+ bool first_person = false;
+ bool third_person = true;
+ float first_person_offset = 0.01f;
+ glm::vec2 prev_mouse_pos = glm::vec2(0.f);
+ float horiz_velocity = .005f;
+
+ std::shared_ptr<GameObject> m_player;
+ float m_distanceFromPlayer = 50.f;
+ float m_angleAroundPlayer = 0.f;
+ float m_pitch = 20.f;
+ float m_yaw = 0.f;
+
+ bool m_isInverted = false;
+ float m_angle = 0.f;
+ float m_height = 0.f;
+ int m_invertY = 1;
+
+ glm::vec3 m_currPos;
+ glm::vec3 m_currLook;
+
+ float m_currentTurnSpeed = 0.f;
+
+ float TURN_SPEED = 2.f;
+ float snapshot_time = 0.f;
+
+
+};
+
+#endif // CAMERASYSTEM_H
diff --git a/engine-ocean/Game/Systems/charactercontrollersystem.cpp b/engine-ocean/Game/Systems/charactercontrollersystem.cpp
new file mode 100644
index 0000000..c5e7174
--- /dev/null
+++ b/engine-ocean/Game/Systems/charactercontrollersystem.cpp
@@ -0,0 +1,132 @@
+#include "charactercontrollersystem.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include <glm/gtx/quaternion.hpp>
+
+CharacterControllerSystem::CharacterControllerSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::shared_ptr<Camera>& camera_param,
+ std::map<int, Input>& input_map,
+ std::map<std::string, BlackboardData>& global_blackboard):
+ m_gameobjects(gameobjects),
+ camera(camera_param),
+ m_input_map(input_map),
+ m_global_blackboard(global_blackboard)
+{
+}
+
+void CharacterControllerSystem::draw(){
+}
+
+TransformComponent* CharacterControllerSystem::getPlayerTransform(){
+ return m_gameobjects.at("player")->getComponent<TransformComponent>();
+}
+
+glm::vec3 CharacterControllerSystem::getPlayerPos(){
+ return m_gameobjects.at("player")->getComponent<TransformComponent>()->getPos();
+}
+
+
+float CharacterControllerSystem::jumpPlayer(float &initial_v, double deltaTime, float snapshot_time, float gravity){
+ float t = deltaTime-snapshot_time;
+ float delta_y = initial_v*t + (.5f)*gravity*t*t;
+ return delta_y;
+}
+
+bool CharacterControllerSystem::movePlayerLaterally(glm::vec3 dir, glm::vec3 perp, glm::vec3 &m_pos, float dt){
+ glm::vec3 translationDir;
+ bool moving_laterally = false;
+ std::shared_ptr<ModelTransform> temp_mt = getPlayerTransform()->getMT();
+
+ if (m_input_map[GLFW_KEY_W].isActive){
+ m_currentSpeed = RUN_SPEED;
+ moving_laterally = true;
+ } else if (m_input_map[GLFW_KEY_S].isActive){
+ m_currentSpeed = -RUN_SPEED;
+ moving_laterally = true;
+ } else {
+ m_currentSpeed = 0.f;
+ }
+
+
+ glm::mat4 rot = glm::mat4(1.f);
+ // player turning
+ if (m_input_map[GLFW_KEY_D].isActive){
+ m_currentTurnSpeed = -TURN_SPEED;
+ moving_laterally = true;
+ } else if (m_input_map[GLFW_KEY_A].isActive){
+ m_currentTurnSpeed = TURN_SPEED;
+ moving_laterally = true;
+ } else {
+ m_currentTurnSpeed = 0.f;
+ }
+
+ // rotate player
+ getPlayerTransform()->getMT()->rotate(m_currentTurnSpeed*dt, glm::vec3(0.f, 1.f, 0.f));
+
+
+ //translate player based on rotation
+ float distance = m_currentSpeed*dt;
+ glm::vec4 movement = distance*glm::vec4(1.f,0.f,0.f, 0.f);
+ glm::vec4 transl = getPlayerTransform()->getMT()->getRotation()*movement;
+
+ translationDir = glm::vec3(transl.x, 0.f, transl.z);
+ temp_mt->translate(translationDir);
+ glm::vec3 potential_pos = temp_mt->getPos();
+ m_pos = potential_pos;
+
+
+ return moving_laterally;
+}
+
+void CharacterControllerSystem::handlePlayerMovement(double deltaTime){
+ // timing
+ float dt = deltaTime - snapshot_time;
+ snapshot_time = deltaTime;
+
+ // get player positions
+ m_pos = getPlayerPos();
+ getPlayerTransform()->old_pos = m_pos;
+
+ // movement
+ getPlayerTransform()->movingLaterally = false;
+ float speedFactor = horiz_velocity * deltaTime;
+ glm::vec3 look = camera->getLook();
+ glm::vec3 dir = glm::normalize(glm::vec3(look.x, 0.f, look.z)) * speedFactor;
+ glm::vec3 perp = glm::vec3(look.z, 0.f, -look.x) * speedFactor;
+
+ // updates m_pos
+ if (movePlayerLaterally(dir, perp, m_pos, dt)){
+ getPlayerTransform()->movingLaterally = true;
+ }
+
+ if (m_input_map[GLFW_KEY_SPACE].isActive && (getPlayerTransform()->onGround)){
+ getPlayerTransform()->gravity = -25.f;
+ getPlayerTransform()->yVelocity = 20.f;
+ getPlayerTransform()->onGround = false;
+ //if (!gravity) gravity = true;
+ m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = true;
+ } else if (!m_input_map[GLFW_KEY_SPACE].isActive && getPlayerTransform()->onGround){
+ m_global_blackboard["player"].conditionData["isJumping"].conditionTrue = false;
+ }
+
+ // PLAYER-SPECIFIC GRAVITY (comment these two lines to keep player still)
+ //if (gravity){
+ m_pos.y += jumpPlayer(getPlayerTransform()->yVelocity, dt, 0, getPlayerTransform()->gravity);
+ getPlayerTransform()->yVelocity = getPlayerTransform()->yVelocity + getPlayerTransform()->gravity*(dt);
+ //}
+
+ // store m_pos as estimated final_pos
+ m_global_blackboard["player"].locationData.setToPos = m_pos;
+
+ getPlayerTransform()->estimated_final_pos = m_pos;
+}
+
+
+void CharacterControllerSystem::update(double deltaTime){
+ handlePlayerMovement(deltaTime);
+}
+
+void CharacterControllerSystem::scrollEvent(double distance){}
+void CharacterControllerSystem::mousePosEvent(double xpos, double ypos){}
diff --git a/engine-ocean/Game/Systems/charactercontrollersystem.h b/engine-ocean/Game/Systems/charactercontrollersystem.h
new file mode 100644
index 0000000..04dd02f
--- /dev/null
+++ b/engine-ocean/Game/Systems/charactercontrollersystem.h
@@ -0,0 +1,62 @@
+#ifndef CHARACTERCONTROLLERSYSTEM_H
+#define CHARACTERCONTROLLERSYSTEM_H
+
+
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Game/GameWorld.h"
+#include "Game/Systems/CollisionSystems/ellipsoidtrianglecollisionsystem.h"
+#include <map>
+
+
+
+class CharacterControllerSystem : public System
+{
+public:
+ CharacterControllerSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::shared_ptr<Camera>& camera_param,
+ std::map<int, Input>& input_map,
+ std::map<std::string, BlackboardData>& global_blackboard);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+private:
+ bool movePlayerLaterally(glm::vec3 dir, glm::vec3 perp, glm::vec3 &m_pos, float dt);
+ void handlePlayerMovement(double deltaTime);
+ TransformComponent* getPlayerTransform();
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects;
+ std::shared_ptr<Camera>& camera;
+ std::map<int, Input>& m_input_map;
+
+ void movePlayer(glm::vec3 direction, int key);
+ void setPlayerPos(glm::vec3 new_pos);
+ glm::vec3 getPlayerPos();
+ float jumpPlayer(float &initial_v, double deltaTime, float snapshot_time, float gravity);
+
+
+ glm::vec3 m_pos = glm::vec3(0.f);
+ float horiz_velocity = .005f;
+ float snapshot_time = 0.f;
+
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+
+ float m_currentSpeed = 0.f;
+ float m_currentTurnSpeed = 0.f;
+
+ float RUN_SPEED = 8.f;
+ float TURN_SPEED = 2.f;
+
+ glm::quat m_quat;
+ glm::vec3 m_axis;
+
+ float HALFPI = 0.78539f;
+ bool gravity = false;
+
+
+
+};
+
+#endif // CHARACTERCONTROLLERSYSTEM_H
diff --git a/engine-ocean/Game/Systems/drawsystem.cpp b/engine-ocean/Game/Systems/drawsystem.cpp
new file mode 100644
index 0000000..ad6e17b
--- /dev/null
+++ b/engine-ocean/Game/Systems/drawsystem.cpp
@@ -0,0 +1,60 @@
+#include "drawsystem.h"
+#include "Game/Components/DrawComponent.h"
+#include "Game/Components/TransformComponent.h"
+
+DrawSystem::DrawSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects):
+ m_gameobjects(gameobjects)
+{
+
+
+}
+
+void DrawSystem::update(double deltaTime){}
+// store all game objects and get draw components, draw
+
+void DrawSystem::draw(){
+ Global::graphics.bindShader("phong");
+ //std::cout << "IN DRAW SYSTEM" << std::endl;
+
+ for (auto &pair: m_gameobjects){
+ if (pair.second->hasComponent<DrawComponent>()){
+
+ DrawComponent *draw_comp = pair.second->getComponent<DrawComponent>();
+ TransformComponent *transform_comp = pair.second->getComponent<TransformComponent>();
+ if (transform_comp->hasMultipleMT()){
+ if (draw_comp->objHasMaterial()){
+ for (const std::shared_ptr<ModelTransform> &mt : transform_comp->getAllMT()){
+ Global::graphics.drawShape(draw_comp->getShape(), mt, draw_comp->getMaterial());
+ }
+ } else {
+ for (const std::shared_ptr<ModelTransform> &mt : transform_comp->getAllMT()){
+ Global::graphics.drawShape(draw_comp->getShape(), mt);
+ }
+ }
+ } else {
+ // case: object is seperated by material
+ if (draw_comp->objHasMultipleShapes()){
+ for (auto &shape : draw_comp->getShapesWithMaterials()){
+ if (shape->hasMaterial()){
+ Global::graphics.drawShape(shape, transform_comp->getMT(), shape->getShapeMaterial());
+ } else {
+ Global::graphics.drawShape(shape, transform_comp->getMT());
+ }
+ }
+
+ } else {
+ if (draw_comp->objHasMaterial()){
+ Global::graphics.drawShape(draw_comp->getShape(), transform_comp->getMT(), draw_comp->getMaterial());
+ } else {
+ //std::cout << "draw shape: " << pair.first << std::endl;
+ Global::graphics.drawShape(draw_comp->getShape(), transform_comp->getMT());
+ }
+ }
+ }
+ }
+ }
+
+}
+
+void DrawSystem::scrollEvent(double distance){}
+void DrawSystem::mousePosEvent(double xpos, double ypos){}
diff --git a/engine-ocean/Game/Systems/drawsystem.h b/engine-ocean/Game/Systems/drawsystem.h
new file mode 100644
index 0000000..d1c8eb9
--- /dev/null
+++ b/engine-ocean/Game/Systems/drawsystem.h
@@ -0,0 +1,23 @@
+#ifndef DRAWSYSTEM_H
+#define DRAWSYSTEM_H
+
+
+#include "Game/GameObjects/GameObject.h"
+#include <vector>
+#include "system.h"
+
+class DrawSystem : public System
+{
+public:
+ DrawSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+
+private:
+ std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects;
+};
+
+#endif // DRAWSYSTEM_H
diff --git a/engine-ocean/Game/Systems/objectcreationsystem.cpp b/engine-ocean/Game/Systems/objectcreationsystem.cpp
new file mode 100644
index 0000000..85241fe
--- /dev/null
+++ b/engine-ocean/Game/Systems/objectcreationsystem.cpp
@@ -0,0 +1,161 @@
+#include "objectcreationsystem.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/CollisionComponents/boundingtriangle.h"
+#include "Game/Components/DrawComponent.h"
+#include "Game/Components/PathfindComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/Ocean/ocean.h"
+
+#include <random>
+
+ObjectCreationSystem::ObjectCreationSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables):
+ m_gameobjects(gameobjects),
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_rigid_gameobjects(rigid_gameobjects),
+ m_global_blackboard(global_blackboard),
+ m_lootables(lootables)
+
+{
+ initializeAllObjects();
+}
+
+void ObjectCreationSystem::initializeAllObjects(){
+
+ m_ground_level = -.5f;
+ initializePlayerObject();
+ // initializeSlopedGround();
+// initializeGround();
+// initializeBackground();
+ initOcean();
+
+ addLight();
+}
+
+void ObjectCreationSystem::initializeSlopedGround(){
+ std::shared_ptr<GameObject> sloped_ground = std::make_shared<GameObject>();
+ std::vector<glm::vec3> obj_data = Global::graphics.addShape("sloped_ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/floor.obj");
+
+ std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>();
+ mt->setScale(1.f);
+ mt->setPos(glm::vec3(0.f));
+
+ sloped_ground->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShape("sloped_ground")));
+ sloped_ground->getComponent<DrawComponent>()->addMaterial("grass_tedxxx", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mossyground.png");
+ sloped_ground->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "sloped_ground", m_global_blackboard));
+ sloped_ground->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt));
+
+ insertRigidObject("sloped_ground", sloped_ground);
+}
+
+void ObjectCreationSystem::insertAnyObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){
+ m_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj));
+}
+
+void ObjectCreationSystem::insertRigidObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){
+ m_rigid_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj));
+ insertAnyObject(name, game_obj);
+}
+
+void ObjectCreationSystem::insertDynamicObject(const std::string name, const std::shared_ptr<GameObject> &game_obj){
+ m_dynamic_gameobjects.insert(std::pair<const std::string, std::shared_ptr<GameObject>>(name, game_obj));
+ insertAnyObject(name, game_obj);
+}
+
+void ObjectCreationSystem::initializePlayerObject(){
+ //std::shared_ptr<Shape> shape = Global::graphics.getShape("sphere");
+ std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/mouse2-4.obj",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/mouse2-4.mtl", true);
+ std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>();
+ mt->setScale(glm::vec3(.5f));
+ mt->setPos(glm::vec3(0.f));
+
+ std::shared_ptr<GameObject> player = std::make_shared<GameObject>();
+
+ player->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("mouse")));
+ player->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "player", m_global_blackboard, true));
+ player->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("dynamic_mesh", mt, mt->getPos(), obj_data));
+
+ insertDynamicObject("player", player);
+}
+
+void ObjectCreationSystem::initializeGround(){
+ std::shared_ptr<GameObject> ground = std::make_shared<GameObject>();
+ std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/meadow_ground.obj",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/meadow_ground.mtl", true);
+
+ //std::vector<glm::vec3> obj_data = Global::graphics.addShape("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/testplane.obj");
+ std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>();
+ mt->setPos(glm::vec3(0.f, 0.f, 0.f));
+ ground->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("ground")));
+ ground->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "ground", m_global_blackboard));
+ ground->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true));
+
+ insertRigidObject("ground", ground);
+}
+
+void ObjectCreationSystem::initializeBackground(){
+ std::shared_ptr<GameObject> bg = std::make_shared<GameObject>();
+
+ // "Snowy Mountain - Terrain" (https://skfb.ly/6RzJV) by artfromheath is licensed under Creative Commons Attribution (http://creativecommons.org/licenses/by/4.0/).
+ std::vector<glm::vec3> obj_data = Global::graphics.addShape_withMaterial("bg", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_background.obj",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_background.mtl", true);
+
+ //std::vector<glm::vec3> obj_data = Global::graphics.addShape("ground", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/testplane.obj");
+ std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>();
+ mt->setPos(glm::vec3(0.f, 0.f, 0.f));
+ bg->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShapeGroup("bg")));
+ bg->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "bg", m_global_blackboard));
+ bg->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true));
+
+ insertRigidObject("bg", bg);
+
+}
+
+void ObjectCreationSystem::initOcean(){
+ m_ocean_shape = std::make_shared<GameObject>();
+
+ std::vector<glm::vec3> obj_data = Global::graphics.addShape_manual("ocean", m_ocean.get_vertices(), m_ocean.get_faces(), true);
+
+
+ std::shared_ptr<ModelTransform> mt = std::make_shared<ModelTransform>();
+ mt->setScale(1.f);
+ mt->setPos(glm::vec3(0.f, 0.f, 0.f));
+ m_ocean_shape->addComponent<DrawComponent>(std::make_unique<DrawComponent>(Global::graphics.getShape("ocean")));
+ m_ocean_shape->getComponent<DrawComponent>()->addMaterial("grass_tedxxx", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mossyground.png");
+
+ m_ocean_shape->addComponent<TransformComponent>(std::make_unique<TransformComponent>(mt, "ocean", m_global_blackboard));
+ m_ocean_shape->addComponent<CollisionComponent>(std::make_unique<CollisionComponent>("obj", obj_data, mt, true));
+
+ insertRigidObject("ocean", m_ocean_shape);
+
+
+}
+
+
+void ObjectCreationSystem::addLight(){
+ std::shared_ptr<Light> light1 = std::make_shared<Light>(LightType::DIRECTIONAL, glm::vec3(0,20,6.5));
+ std::vector<std::shared_ptr<Light>> lights;
+ lights.push_back(light1);
+
+ Global::graphics.bindShader("phong");
+ Global::graphics.setLights(lights);
+}
+
+
+void ObjectCreationSystem::draw(){}
+void ObjectCreationSystem::update(double deltaTime){
+ std::cout << "update" << std::endl;
+ m_ocean.fft_prime(m_time);
+ Global::graphics.getShape("ocean")->updateVAO(m_ocean.get_vertices(), m_ocean.get_faces());
+ m_time += m_timestep;
+
+}
+void ObjectCreationSystem::scrollEvent(double distance){}
+void ObjectCreationSystem::mousePosEvent(double xpos, double ypos){}
+
+
+
diff --git a/engine-ocean/Game/Systems/objectcreationsystem.h b/engine-ocean/Game/Systems/objectcreationsystem.h
new file mode 100644
index 0000000..ce30cde
--- /dev/null
+++ b/engine-ocean/Game/Systems/objectcreationsystem.h
@@ -0,0 +1,82 @@
+#ifndef OBJECTCREATIONSYSTEM_H
+#define OBJECTCREATIONSYSTEM_H
+
+
+#include "Game/GameObjects/GameObject.h"
+#include "Game/Systems/aisystem.h"
+#include "Game/Ocean/ocean.h"
+
+#include "system.h"
+
+
+class ObjectCreationSystem : public System
+{
+public:
+ ObjectCreationSystem(std::map<std::string, std::shared_ptr<GameObject>>& gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+private:
+ void initializeAllObjects();
+ void initializePlayerObject();
+ void initializeGroundObject();
+ void initializeObstacle();
+ void generateBamboo();
+ void generateBall(glm::vec3 scale, glm::vec3 pos, int number);
+ void addObject_NoTransform(std::string shape_name, std::string obj_name, std::string filename);
+ void makeBVHDemo();
+ void initializeBackground();
+ void initOcean();
+
+
+
+ void makeLootable(std::string shapename, std::string filename, int count, glm::vec3 scale);
+
+
+
+
+
+ void initializeCeilingMesh();
+ void initializeSlopedGround();
+ void initializeGround();
+ void addLight();
+ void makeNavMesh();
+
+
+
+
+ void insertAnyObject(const std::string name, const std::shared_ptr<GameObject> &game_obj);
+ void insertDynamicObject(const std::string name, const std::shared_ptr<GameObject> &game_obj);
+ void insertRigidObject(const std::string name, const std::shared_ptr<GameObject> &game_obj);
+
+
+
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables;
+
+
+ float m_groundBounds = 0.f;
+ float m_ground_level = 0.f;
+
+
+ ocean m_ocean;
+ std::shared_ptr<GameObject> m_ocean_shape;
+ double m_time = 0.0;
+ double m_timestep = .01;
+
+
+};
+
+#endif // OBJECTCREATIONSYSTEM_H
diff --git a/engine-ocean/Game/Systems/physicssystem.cpp b/engine-ocean/Game/Systems/physicssystem.cpp
new file mode 100644
index 0000000..cd70933
--- /dev/null
+++ b/engine-ocean/Game/Systems/physicssystem.cpp
@@ -0,0 +1,72 @@
+#include "physicssystem.h"
+#include "Game/Components/TransformComponent.h"
+
+PhysicsSystem::PhysicsSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables) :
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_global_blackboard(global_blackboard),
+ m_lootables(lootables)
+
+{
+
+}
+
+TransformComponent* PhysicsSystem::getTransform(std::shared_ptr<GameObject> &go){
+ return go->getComponent<TransformComponent>();
+}
+
+float PhysicsSystem::gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity){
+ float t = deltaTime-snapshot_time;
+ float delta_y = initial_v*t + (.5f)*gravity*t*t;
+ return delta_y;
+}
+
+
+void PhysicsSystem::update(double deltaTime){
+ //std::cout << "physics" << std::endl;
+ float dt = deltaTime - snapshot_time;
+ snapshot_time = deltaTime;
+
+ for (auto &go : m_dynamic_gameobjects){
+ // player has its own physics
+ if (go.first != "player"){
+ // position
+ glm::vec3 m_pos = getTransform(go.second)->getPos();
+ getTransform(go.second)->old_pos = m_pos;
+
+ // effect it by gravity
+ m_pos.y += gravitySimulation(getTransform(go.second)->yVelocity, dt, 0, getTransform(go.second)->gravity);
+ getTransform(go.second)->yVelocity = getTransform(go.second)->yVelocity + getTransform(go.second)->gravity*(dt);
+
+ m_global_blackboard[go.first].locationData.setToPos = m_pos;
+ // store m_pos as estimated final_pos
+ getTransform(go.second)->estimated_final_pos = m_pos;
+ }
+ }
+
+// for (auto &lootGroup : m_lootables){
+// for (auto &loot : lootGroup.second){
+// // position
+// glm::vec3 m_pos = getTransform(loot)->getPos();
+// getTransform(loot)->old_pos = m_pos;
+
+// // effect it by gravity
+// m_pos.y += gravitySimulation(getTransform(loot)->yVelocity, dt, 0, getTransform(loot)->gravity);
+// getTransform(loot)->yVelocity = getTransform(loot)->yVelocity + getTransform(loot)->gravity*(dt);
+
+// // store m_pos as estimated final_pos
+// getTransform(loot)->estimated_final_pos = m_pos;
+// }
+
+// }
+
+}
+
+
+
+
+void PhysicsSystem::draw(){}
+void PhysicsSystem::scrollEvent(double distance){}
+void PhysicsSystem::mousePosEvent(double xpos, double ypos){}
+
diff --git a/engine-ocean/Game/Systems/physicssystem.h b/engine-ocean/Game/Systems/physicssystem.h
new file mode 100644
index 0000000..fc9abbb
--- /dev/null
+++ b/engine-ocean/Game/Systems/physicssystem.h
@@ -0,0 +1,30 @@
+#ifndef PHYSICSSYSTEM_H
+#define PHYSICSSYSTEM_H
+#include "Game/Components/TransformComponent.h"
+#include "system.h"
+
+
+class PhysicsSystem : public System
+{
+public:
+ PhysicsSystem(std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::map<std::string, BlackboardData>& global_blackboard,
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& lootables);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+
+private:
+ float gravitySimulation(float &initial_v, double deltaTime, float snapshot_time, float gravity);
+ TransformComponent* getTransform(std::shared_ptr<GameObject> &go);
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>>& m_lootables;
+
+ float horiz_velocity = .005f;
+ float snapshot_time = 0.f;
+};
+
+#endif // PHYSICSSYSTEM_H
diff --git a/engine-ocean/Game/Systems/system.cpp b/engine-ocean/Game/Systems/system.cpp
new file mode 100644
index 0000000..764114c
--- /dev/null
+++ b/engine-ocean/Game/Systems/system.cpp
@@ -0,0 +1,6 @@
+#include "system.h"
+
+System::System()
+{
+
+}
diff --git a/engine-ocean/Game/Systems/system.h b/engine-ocean/Game/Systems/system.h
new file mode 100644
index 0000000..4abca3b
--- /dev/null
+++ b/engine-ocean/Game/Systems/system.h
@@ -0,0 +1,17 @@
+#ifndef SYSTEM_H
+#define SYSTEM_H
+
+
+#include "Game/GameObjects/GameObject.h"
+#include <map>
+class System
+{
+public:
+ System();
+ virtual void draw() = 0;
+ virtual void update(double deltaTime) = 0;
+ virtual void scrollEvent(double distance) = 0;
+ virtual void mousePosEvent(double xpos, double ypos) = 0;
+};
+
+#endif // SYSTEM_H