summaryrefslogtreecommitdiff
path: root/engine-ocean/Game
diff options
context:
space:
mode:
Diffstat (limited to 'engine-ocean/Game')
-rw-r--r--engine-ocean/Game/Application.cpp101
-rw-r--r--engine-ocean/Game/Application.h40
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp88
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h32
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h21
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp6
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingShape.h15
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp200
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp47
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp47
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h37
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp6
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h68
-rw-r--r--engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h49
-rw-r--r--engine-ocean/Game/Components/Component.h13
-rw-r--r--engine-ocean/Game/Components/DrawComponent.cpp54
-rw-r--r--engine-ocean/Game/Components/PathfindComponent.h22
-rw-r--r--engine-ocean/Game/Components/TransformComponent.cpp92
-rw-r--r--engine-ocean/Game/Components/component.cpp6
-rw-r--r--engine-ocean/Game/Components/drawcomponent.h41
-rw-r--r--engine-ocean/Game/Components/pathfindcomponent.cpp16
-rw-r--r--engine-ocean/Game/Components/playercontrolcomponent.cpp6
-rw-r--r--engine-ocean/Game/Components/playercontrolcomponent.h11
-rw-r--r--engine-ocean/Game/Components/transformcomponent.h54
-rw-r--r--engine-ocean/Game/Environment/Environment.cpp6
-rw-r--r--engine-ocean/Game/Environment/Environment.h12
-rw-r--r--engine-ocean/Game/Environment/environmentsystem.cpp40
-rw-r--r--engine-ocean/Game/Environment/environmentsystem.h41
-rw-r--r--engine-ocean/Game/Environment/grassenvironment.cpp85
-rw-r--r--engine-ocean/Game/Environment/grassenvironment.h37
-rw-r--r--engine-ocean/Game/Environment/skyboxenvironment.cpp64
-rw-r--r--engine-ocean/Game/Environment/skyboxenvironment.h103
-rw-r--r--engine-ocean/Game/Environment/water.cpp48
-rw-r--r--engine-ocean/Game/Environment/water.h38
-rw-r--r--engine-ocean/Game/GameObjects/GameObject.cpp27
-rw-r--r--engine-ocean/Game/GameObjects/GameObject.h54
-rw-r--r--engine-ocean/Game/GameWorld.cpp224
-rw-r--r--engine-ocean/Game/GameWorld.h132
-rw-r--r--engine-ocean/Game/GameplayScreen.cpp44
-rw-r--r--engine-ocean/Game/GameplayScreen.h34
-rw-r--r--engine-ocean/Game/MenuScreen.cpp59
-rw-r--r--engine-ocean/Game/Ocean/ocean.cpp325
-rw-r--r--engine-ocean/Game/Ocean/ocean.h89
-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
-rw-r--r--engine-ocean/Game/TypeMap.h54
-rw-r--r--engine-ocean/Game/menuscreen.h27
-rw-r--r--engine-ocean/Game/screen.cpp6
-rw-r--r--engine-ocean/Game/screen.h20
111 files changed, 7357 insertions, 0 deletions
diff --git a/engine-ocean/Game/Application.cpp b/engine-ocean/Game/Application.cpp
new file mode 100644
index 0000000..8ebea3f
--- /dev/null
+++ b/engine-ocean/Game/Application.cpp
@@ -0,0 +1,101 @@
+#include "Application.h"
+#include "Game/menuscreen.h"
+
+Application::Application()
+{
+ game = std::make_shared<GameplayScreen>(m_input_map);//new GameplayScreen(m_input_map);
+ menu = std::make_shared<MenuScreen>(m_input_map);
+ activeScreen = game;
+
+ createKeyInput(GLFW_KEY_M);
+ createKeyInput(GLFW_KEY_B);
+ createKeyInput(GLFW_KEY_R);
+
+}
+
+
+
+void Application::createKeyInput(int inputVal){
+ Input input;
+ input.inputVal = inputVal;
+ m_input_map[inputVal] = input;
+}
+
+void Application::inactivateOtherKeys(int keyVal){
+ for (auto &keypair : m_input_map){
+ if (keypair.second.inputVal != keyVal){
+ m_input_map.at(keypair.first).isActive = false;
+ }
+ }
+}
+
+
+
+void Application::update(double deltaTime){
+ activeScreen->update(deltaTime);
+}
+
+void Application::draw(){
+ if (m_input_map.at(GLFW_KEY_M).isActive){
+ activeScreen = menu;
+ } else {
+ activeScreen = game;
+ }
+
+ activeScreen->draw();
+}
+
+void Application::keyEvent(int key, int action){
+ switch(key){
+ case GLFW_KEY_M:
+ if (action == GLFW_PRESS){
+ inactivateOtherKeys(key);
+ m_input_map.at(key).isActive = true;
+ }
+ break;
+ case GLFW_KEY_B:
+ if (action == GLFW_PRESS){
+ inactivateOtherKeys(key);
+ m_input_map.at(key).isActive = true;
+ }
+ break;
+ case GLFW_KEY_R:
+ if (action == GLFW_PRESS){
+ inactivateOtherKeys(key);
+ m_input_map.at(key).isActive = true;
+ game = std::make_shared<GameplayScreen>(m_input_map);//new GameplayScreen(m_input_map);
+ menu = std::make_shared<MenuScreen>(m_input_map);
+ activeScreen = game;
+ }
+ break;
+ default:
+ break;
+ }
+
+ activeScreen->keyEvent(key, action);
+
+}
+
+void Application::mousePosEvent(double xpos, double ypos){
+
+ activeScreen->mousePosEvent(xpos, ypos);
+
+}
+
+void Application::mouseButtonEvent(int button, int action){
+ activeScreen->mouseButtonEvent(button, action);
+
+}
+
+void Application::scrollEvent(double distance){
+ activeScreen->scrollEvent(distance);
+
+}
+
+void Application::framebufferResizeEvent(int width, int height){
+ activeScreen->framebufferResizeEvent(width, height);
+}
+
+void Application::windowResizeEvent(int width, int height){
+ activeScreen->windowResizeEvent(width, height);
+}
diff --git a/engine-ocean/Game/Application.h b/engine-ocean/Game/Application.h
new file mode 100644
index 0000000..da592ff
--- /dev/null
+++ b/engine-ocean/Game/Application.h
@@ -0,0 +1,40 @@
+#ifndef APPLICATION_H
+#define APPLICATION_H
+
+#include "Game/gameplayscreen.h"
+#include "Game/screen.h"
+#include "Graphics/global.h"
+
+#include <GLFW/glfw3.h>
+
+
+class Application
+{
+public:
+ Application();
+ void update(double deltaTime);
+ void draw();
+ void keyEvent(int key, int action);
+ void mousePosEvent(double xpos, double ypos);
+ void mouseButtonEvent(int button, int action);
+ void scrollEvent(double distance);
+ void windowResizeEvent(int width, int height);
+ void framebufferResizeEvent(int width, int height);
+
+private:
+
+ void createKeyInput(int inputVal);
+ void inactivateOtherKeys(int keyVal);
+
+// Screen activeScreen;
+// Screen *game;
+// Screen *menu;
+ std::shared_ptr<Screen> activeScreen;
+ std::shared_ptr<Screen> game;
+ std::shared_ptr<Screen> menu;
+
+ std::map<int, Input> m_input_map;
+};
+
+
+#endif // APPLICATION_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp
new file mode 100644
index 0000000..d39d118
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.cpp
@@ -0,0 +1,88 @@
+#include "boundingdynamicmesh.h"
+#include "Graphics/modeltransform.h"
+#include <vector>
+
+// without mesh obj data
+BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt,
+ const glm::vec3 &initial_pos) :
+ m_mt(mt)
+{
+ m_isMesh = false;
+ m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale());
+}
+
+// with mesh obj data
+BoundingDynamicMesh::BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt,
+ const glm::vec3 &initial_pos,
+ std::vector<glm::vec3> &obj_data) :
+ m_mt(mt),
+ m_obj_data(obj_data)
+{
+ m_isMesh = true;
+ m_bounding_cylinder = std::make_shared<CylinderCollider>(initial_pos, mt->getScale()*getMeshDimensions()*2.f);
+}
+
+
+glm::vec3 BoundingDynamicMesh::getCenterPos(){
+ return m_mt->getPos();
+}
+
+void BoundingDynamicMesh::updateCenterPos(glm::vec3 new_pos){
+ m_mt->setPos(new_pos);
+ m_bounding_cylinder->updateCollisionPos(new_pos);
+}
+
+
+
+glm::vec3 BoundingDynamicMesh::getMeshDimensions(){
+ float max_x = m_obj_data[0].x;
+ float min_x = m_obj_data[0].x;
+ float max_y = m_obj_data[0].y;
+ float min_y = m_obj_data[0].y;
+ float max_z = m_obj_data[0].z;
+ float min_z = m_obj_data[0].z;
+
+ for (const glm::vec3 &v : m_obj_data){
+ // check max
+ if (v.x > max_x){
+ max_x = v.x;
+ }
+ if (v.y > max_y){
+ max_y = v.y;
+ }
+ if (v.z > max_z){
+ max_z = v.z;
+ }
+
+ // check mins
+ if (v.x < min_x){
+ min_x = v.x;
+ }
+ if (v.y < min_y){
+ min_y = v.y;
+ }
+ if (v.z < min_z){
+ min_z = v.z;
+ }
+ }
+
+ float r_x = (max_x - min_x)/2.f;
+ float r_y = (max_y - min_y)/2.f;
+ float r_z = (max_z - min_z)/2.f;
+
+ return glm::vec3(r_x, r_y, r_z);
+}
+
+glm::vec3 BoundingDynamicMesh::getEllipsoidDimensions(){
+ if (m_isMesh){
+ return m_mt->getScale()*getMeshDimensions();
+ }
+
+ return m_mt->getScale()/2.f;
+}
+
+Cylinder BoundingDynamicMesh::getCylinder(){
+ return m_bounding_cylinder->getCylinder();
+}
+
+
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h
new file mode 100644
index 0000000..5d24ac8
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingDynamicMesh.h
@@ -0,0 +1,32 @@
+#ifndef BOUNDINGDYNAMICMESH_H
+#define BOUNDINGDYNAMICMESH_H
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include "Graphics/modeltransform.h"
+#include "glm/glm.hpp"
+#include <memory>
+#include <vector>
+
+
+class BoundingDynamicMesh : public BoundingShape
+{
+public:
+ BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt,
+ const glm::vec3 &initial_pos);
+ BoundingDynamicMesh(std::shared_ptr<ModelTransform> mt,
+ const glm::vec3 &initial_pos,
+ std::vector<glm::vec3> &obj_data);
+ glm::vec3 getCenterPos();
+ void updateCenterPos(glm::vec3 new_pos);
+ glm::vec3 getEllipsoidDimensions();
+ Cylinder getCylinder();
+
+private:
+ glm::vec3 getMeshDimensions();
+
+ bool m_isMesh = false;
+ std::shared_ptr<ModelTransform> m_mt;
+ std::vector<glm::vec3> m_obj_data;
+ std::shared_ptr<CylinderCollider> m_bounding_cylinder;
+};
+
+#endif // BOUNDINGDYNAMICMESH_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h
new file mode 100644
index 0000000..8dce7c3
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingEllipsoid.h
@@ -0,0 +1,21 @@
+#ifndef BOUNDINGELLIPSOID_H
+#define BOUNDINGELLIPSOID_H
+#include "glm/glm.hpp"
+#include "BoundingShape.h"
+
+struct Ellipsoid{
+ glm::vec3 R = glm::vec3(0.f); // holds Rx, Ry, Rz radii
+ glm::vec3 center_pos;
+};
+
+struct UnitSphere{
+ glm::vec3 center_pos;
+};
+
+class BoundingEllipsoid : public BoundingShape
+{
+public:
+ BoundingEllipsoid();
+};
+
+#endif // BOUNDINGELLIPSOID_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp
new file mode 100644
index 0000000..b3abba4
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.cpp
@@ -0,0 +1,6 @@
+#include "BoundingShape.h"
+
+BoundingShape::BoundingShape()
+{
+
+}
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h
new file mode 100644
index 0000000..1303628
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingShape.h
@@ -0,0 +1,15 @@
+#ifndef SHAPECOLLIDER_H
+#define SHAPECOLLIDER_H
+
+struct CollisionShape{
+
+};
+
+class BoundingShape
+{
+public:
+ BoundingShape();
+ //virtual CollisionShape getCollisionShape() = 0;
+};
+
+#endif // SHAPECOLLIDER_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp
new file mode 100644
index 0000000..519d9c7
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/BoundingTriangle.cpp
@@ -0,0 +1,200 @@
+#include "boundingtriangle.h"
+#include "Graphics/global.h"
+#include "Graphics/modeltransform.h"
+#include <iostream>
+#include "glm/gtx/hash.hpp"
+
+// ONLY FOR ENVIRONMENTS
+BoundingTriangle::BoundingTriangle(const std::vector<glm::vec3> &obj_data,
+ const std::shared_ptr<ModelTransform> &mt,
+ bool isGround) :
+ obj_mt(mt),
+ m_isGround(isGround)
+{
+ populateTriangleData(obj_data);
+ calculateBounds(obj_data);
+ //m_datasize = obj_data.size();
+}
+
+glm::vec3 BoundingTriangle::getRandomSurfacePos(){
+ int randomIndex = std::floor(Global::graphics.generateRandomNumbers(0, m_triangles.size()-1));
+ int randomVertex = std::floor(Global::graphics.generateRandomNumbers(0, 3));
+
+ Triangle randomTri = m_triangles[randomIndex];
+
+ if (glm::dot(glm::vec3(0,1,0), randomTri.normal) > 0.2f){
+ switch(randomVertex){
+ case 0:
+ return randomTri.vertexA;
+ break;
+ case 1:
+ return randomTri.vertexB;
+ break;
+ default:
+ return randomTri.vertexC;
+ break;
+ }
+ } else {
+ // do again until returning a surface triangle
+ getRandomSurfacePos();
+ }
+}
+
+
+void BoundingTriangle::addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC){
+ Triangle tri;
+ tri.vertexA = vertexA;
+ tri.vertexB = vertexB;
+ tri.vertexC = vertexC;
+
+ tri.edge1 = vertexB - vertexA; // edge ab
+ tri.edge2 = vertexC - vertexA; // edge bc
+ tri.normal = glm::normalize(glm::cross(tri.edge1, tri.edge2));
+ tri.bounds = calculateTriangleBounds(vertexA, vertexB, vertexC);
+
+ // if triangle is a ground triangle
+ if (m_isGround){
+ if (glm::dot(glm::vec3(0,1,0), tri.normal) > 0.2f){
+ //std::cout << "area: " << getArea(vertexA, vertexB, vertexC) << std::endl;
+ tesselateTriangle(vertexA, vertexB, vertexC);
+ }
+ }
+
+ m_triangles.push_back(tri);
+}
+
+float BoundingTriangle::getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){
+ glm::vec3 AB = B-A;
+ glm::vec3 AC = C-A;
+ return .5f*glm::length((glm::cross(AB,AC)));
+
+}
+
+glm::vec3 BoundingTriangle::getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){
+ return .333f*(A + B + C);
+}
+
+// tesselation into smaller triangles
+void BoundingTriangle::tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C){
+ float min_area = 1.5f;
+
+ // add centroid if area is small enough
+ if (getArea(A,B,C) <= min_area){
+ m_surface_points.push_back(getCentroid(A, B, C));
+ return;
+ }
+
+ // otherwise divide triangle in 4 (tesselate)
+
+ glm::vec3 ab_mid = .5f*(A+B);
+ glm::vec3 ac_mid = .5f*(A+C);
+ glm::vec3 bc_mid = .5f*(B+C);
+ m_surface_points.push_back(ab_mid);
+ m_surface_points.push_back(ac_mid);
+ m_surface_points.push_back(bc_mid);
+
+ tesselateTriangle(ab_mid, ac_mid, A);
+ tesselateTriangle(bc_mid, ab_mid, B);
+ tesselateTriangle(bc_mid, ac_mid, C);
+ tesselateTriangle(ab_mid, ac_mid, bc_mid);
+}
+
+
+void BoundingTriangle::populateTriangleData(const std::vector<glm::vec3> &obj_data){
+ for (int i=0; i<obj_data.size(); i += 3){
+ // convert to worldspace
+ glm::mat4 modelMat = obj_mt->getModelMatrix();
+ glm::vec3 v1 = modelMat*glm::vec4(obj_data[i],1.0);
+ glm::vec3 v2 = modelMat*glm::vec4(obj_data[i+1],1.0);
+ glm::vec3 v3 = modelMat*glm::vec4(obj_data[i+2],1.0);
+
+ // make triangle
+ addTriangle(v1, v2, v3);
+ }
+
+// m_surface_points.reserve(m_unique_surface_points.size());
+// std::copy(m_unique_surface_points.begin(), m_unique_surface_points.end(), m_surface_points.begin());
+}
+
+Bounds3f BoundingTriangle::calculateTriangleBounds(const glm::vec3 &vertexA,
+ const glm::vec3 &vertexB,
+ const glm::vec3 &vertexC){
+ Bounds3f bounds;
+
+ float max_x, min_x = vertexA.x;
+ float max_y, min_y = vertexA.y;
+ float max_z, min_z = vertexA.z;
+
+ if (vertexB.x > max_x) max_x = vertexB.x;
+ if (vertexB.y > max_y) max_y = vertexB.y;
+ if (vertexB.z > max_z) max_z = vertexB.z;
+
+ if (vertexC.x > max_x) max_x = vertexC.x;
+ if (vertexC.y > max_y) max_y = vertexC.y;
+ if (vertexC.z > max_z) max_z = vertexC.z;
+
+ if (vertexB.x < min_x) min_x = vertexB.x;
+ if (vertexB.y < min_y) min_y = vertexB.y;
+ if (vertexB.z < min_z) min_z = vertexB.z;
+
+ if (vertexC.x < min_x) min_x = vertexC.x;
+ if (vertexC.y < min_y) min_y = vertexC.y;
+ if (vertexC.z < min_z) min_z = vertexC.z;
+
+
+ bounds.max = glm::vec3(max_x, max_y, max_z);
+ bounds.min = glm::vec3(min_x, min_y, min_z);
+
+ return bounds;
+}
+
+void BoundingTriangle::calculateBounds(const std::vector<glm::vec3> &obj_data){
+ max_x = obj_data[0].x;
+ min_x = obj_data[0].x;
+ max_y = obj_data[0].y;
+ min_y = obj_data[0].y;
+ max_z = obj_data[0].z;
+ min_z = obj_data[0].z;
+
+ for (const glm::vec3 &v : obj_data){
+ // check max
+ if (v.x > max_x){
+ max_x = v.x;
+ }
+ if (v.y > max_y){
+ max_y = v.y;
+ }
+ if (v.z > max_z){
+ max_z = v.z;
+ }
+
+ // check mins
+ if (v.x < min_x){
+ min_x = v.x;
+ }
+ if (v.y < min_y){
+ min_y = v.y;
+ }
+ if (v.z < min_z){
+ min_z = v.z;
+ }
+ }
+}
+
+Bounds3f BoundingTriangle::getMeshBounds(){
+ Bounds3f bounds;
+ bounds.max = glm::vec3(max_x, max_y, max_z);
+ bounds.min = glm::vec3(min_x, min_y, min_z);
+ return bounds;
+}
+
+std::vector<glm::vec3> BoundingTriangle::getSurfacePoints(){
+ if (!m_isGround){
+ std::cout << "getting surface points of not-ground object!" << std::endl;
+ }
+ return m_surface_points;
+}
+
+std::vector<Triangle> BoundingTriangle::getTriangleData(){
+ return m_triangles;
+}
diff --git a/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp
new file mode 100644
index 0000000..bea3f9e
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/CollisionComponent.cpp
@@ -0,0 +1,47 @@
+#include "collisioncomponent.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/Components/CollisionComponents/CylinderCollider.h"
+#include "Game/Components/CollisionComponents/BoundingDynamicMesh.h"
+#include "Graphics/shape.h"
+#include <memory>
+
+// for dynamic objects
+CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos)
+{
+ if (shapeType == "dynamic_mesh"){
+ //addCollisionShape<CylinderCollider>(std::make_shared<CylinderCollider>(initial_pos, initial_scale));
+ addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos));
+ }
+}
+
+CollisionComponent::CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data)
+{
+ if (shapeType == "dynamic_mesh"){
+ addCollisionShape<BoundingDynamicMesh>(std::make_shared<BoundingDynamicMesh>(mt, initial_pos, obj_data));
+ }
+}
+
+// for rigid meshes / environment
+CollisionComponent::CollisionComponent(std::string shapeType,
+ const std::vector<glm::vec3> &obj_data,
+ const std::shared_ptr<ModelTransform> &mt,
+ bool isGround){
+ if (shapeType == "obj"){
+ addCollisionShape<BoundingTriangle>(std::make_shared<BoundingTriangle>(obj_data, mt, isGround));
+ }
+
+}
+
+
+
+bool CollisionComponent::isRigidBody(){
+ return m_isRigid;
+}
+
+float CollisionComponent::getReboundVel(){
+ return m_rebound_vel;
+}
+
+float CollisionComponent::getAcceleration(){
+ return m_acceleration;
+}
diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp
new file mode 100644
index 0000000..3dfded9
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.cpp
@@ -0,0 +1,47 @@
+#include "cylindercollider.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Graphics/modeltransform.h"
+
+CylinderCollider::CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale){
+ m_scale = initial_scale;
+
+ m_cyl.point = glm::vec2(initial_pos.x, initial_pos.z);
+ m_cyl.radius = .5f * glm::max(initial_scale.x, initial_scale.z);
+ m_cyl.height = 1.f * abs(initial_scale.y);
+ m_cyl.min = initial_pos.y - (initial_scale.y/2.f);
+ m_cyl.max = initial_pos.y + (initial_scale.y/2.f);
+
+ m_cyl.aabbDimensions = abs(glm::vec3(2*m_cyl.radius, m_cyl.height, 2*m_cyl.radius));
+ m_cyl.aabbCenterPos = initial_pos;
+
+ updateBounds();
+}
+
+void CylinderCollider::updateCollisionPos(glm::vec3 new_pos){
+ m_cyl.point = glm::vec2(new_pos.x, new_pos.z); // x and z loc
+ m_cyl.radius = .5f * m_scale.x; // x and z dim
+ m_cyl.height = 1.f * m_scale.y; // y dimensions
+ m_cyl.min = new_pos.y - (m_scale.y/2.f); // y coord
+ m_cyl.max = new_pos.y + (m_scale.y/2.f); // y coord
+ m_cyl.aabbCenterPos = new_pos;
+
+ updateBounds();
+}
+
+
+void CylinderCollider::updateBounds(){
+ Bounds3f bounds;
+ bounds.min = glm::vec3(m_cyl.aabbCenterPos-glm::vec3(m_cyl.aabbDimensions/2.f));
+ bounds.max = glm::vec3(m_cyl.aabbCenterPos+glm::vec3(m_cyl.aabbDimensions/2.f));
+
+ m_cyl.bounds = bounds;
+}
+
+
+Cylinder CylinderCollider::getCylinder(){
+ return m_cyl;
+}
+
+
+
+
diff --git a/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h
new file mode 100644
index 0000000..3363b84
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/CylinderCollider.h
@@ -0,0 +1,37 @@
+#ifndef CYLINDERCOLLIDER_H
+#define CYLINDERCOLLIDER_H
+
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Graphics/modeltransform.h"
+#include "glm/glm.hpp"
+#include "BoundingShape.h"
+#include <memory>
+
+
+struct Cylinder {
+ glm::vec2 point; // bottom Center
+ float radius;
+
+ // lines
+ float height;
+ float min;
+ float max;
+
+ glm::vec3 aabbDimensions;
+ glm::vec3 aabbCenterPos;
+ Bounds3f bounds;
+};
+
+class CylinderCollider
+{
+public:
+ CylinderCollider(glm::vec3 initial_pos, glm::vec3 initial_scale);
+ Cylinder getCylinder();// override;
+ void updateCollisionPos(glm::vec3 new_pos);
+ void updateBounds();
+private:
+ glm::vec3 m_scale;
+ Cylinder m_cyl;
+};
+
+#endif // CYLINDERCOLLIDER_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp
new file mode 100644
index 0000000..3f8ed07
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/boundingellipsoid.cpp
@@ -0,0 +1,6 @@
+#include "boundingellipsoid.h"
+
+BoundingEllipsoid::BoundingEllipsoid()
+{
+
+}
diff --git a/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h
new file mode 100644
index 0000000..0263007
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/boundingtriangle.h
@@ -0,0 +1,68 @@
+#ifndef BOUNDINGTRIANGLE_H
+#define BOUNDINGTRIANGLE_H
+#include "Graphics/modeltransform.h"
+#include "glm/glm.hpp"
+#include <set>
+#include <vector>
+#include "BoundingShape.h"
+
+struct Bounds3f {
+ glm::vec3 min;
+ glm::vec3 max;
+};
+
+struct Triangle{
+ glm::vec3 vertexA; // one vertex
+ glm::vec3 vertexB;
+ glm::vec3 vertexC;
+
+ glm::vec3 edge1; // two edges
+ glm::vec3 edge2;
+
+ glm::vec3 normal;// = glm::cross(edge1, edge2);
+ Bounds3f bounds;
+
+
+};
+
+class BoundingTriangle : public BoundingShape
+{
+public:
+ BoundingTriangle(const std::vector<glm::vec3> &obj_data,
+ const std::shared_ptr<ModelTransform> &mt,
+ bool isGround = false);
+ std::vector<Triangle> getTriangleData();
+
+ Bounds3f getMeshBounds();
+ std::vector<glm::vec3> getSurfacePoints();
+ glm::vec3 getRandomSurfacePos();
+
+
+
+private:
+ void addTriangle(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC);
+ void populateTriangleData(const std::vector<glm::vec3> &obj_data);
+ void calculateBounds(const std::vector<glm::vec3> &obj_data);
+ Bounds3f calculateTriangleBounds(const glm::vec3 &vertexA, const glm::vec3 &vertexB, const glm::vec3 &vertexC);
+
+ float getArea(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C);
+ glm::vec3 getCentroid(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C);
+ void tesselateTriangle(const glm::vec3 &A, const glm::vec3 &B, const glm::vec3 &C);
+
+
+ int m_datasize = 0;
+
+
+
+
+
+ std::vector<Triangle> m_triangles;
+ std::shared_ptr<ModelTransform> obj_mt;
+ std::set<glm::vec3> m_unique_surface_points;
+ std::vector<glm::vec3> m_surface_points;
+ bool m_isGround = false;
+
+ float min_x, min_y, min_z, max_x, max_y, max_z;
+};
+
+#endif // BOUNDINGTRIANGLE_H
diff --git a/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h
new file mode 100644
index 0000000..daef723
--- /dev/null
+++ b/engine-ocean/Game/Components/CollisionComponents/collisioncomponent.h
@@ -0,0 +1,49 @@
+#ifndef COLLISIONCOMPONENT_H
+#define COLLISIONCOMPONENT_H
+
+#include "Game/Components/CollisionComponents/BoundingShape.h"
+#include <map>
+#include <string>
+#include "Game/TypeMap.h"
+#include "Graphics/modeltransform.h"
+#include "glm/glm.hpp"
+#include "Game/Components/Component.h"
+
+
+class CollisionComponent : public Component
+{
+public:
+ template <typename T>
+ void addCollisionShape(std::shared_ptr<T> &&component){
+ m_collision_shapes.put<T>(std::forward<std::shared_ptr<T>>(component));
+ }
+
+ template <typename T>
+ bool hasCollisionShape(){
+ return m_collision_shapes.contains<T>();
+ }
+
+ template <class T>
+ T* getCollisionShape(){
+ auto comp = m_collision_shapes.find<T>();
+ assert(comp != m_collision_shapes.end());
+ return static_cast<T*>(comp->second.get());
+ }
+
+ CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos, std::vector<glm::vec3> &obj_data);
+ CollisionComponent(std::string shapeType, std::shared_ptr<ModelTransform> mt, const glm::vec3 &initial_pos);
+ CollisionComponent(std::string shapeType, const std::vector<glm::vec3> &obj_data, const std::shared_ptr<ModelTransform> &mt,
+ bool isGround = false);
+
+ bool isRigidBody();
+ float getReboundVel();
+ float getAcceleration();
+
+private:
+ TypeMap<std::shared_ptr<BoundingShape>> m_collision_shapes;
+ bool m_isRigid = true;
+ float m_rebound_vel = 0.f;
+ float m_acceleration = 0.f;
+};
+
+#endif // COLLISIONCOMPONENT_H
diff --git a/engine-ocean/Game/Components/Component.h b/engine-ocean/Game/Components/Component.h
new file mode 100644
index 0000000..fef4330
--- /dev/null
+++ b/engine-ocean/Game/Components/Component.h
@@ -0,0 +1,13 @@
+#ifndef COMPONENT_H
+#define COMPONENT_H
+
+
+class Component
+{
+public:
+ Component();
+
+
+};
+
+#endif // COMPONENT_H
diff --git a/engine-ocean/Game/Components/DrawComponent.cpp b/engine-ocean/Game/Components/DrawComponent.cpp
new file mode 100644
index 0000000..28640dd
--- /dev/null
+++ b/engine-ocean/Game/Components/DrawComponent.cpp
@@ -0,0 +1,54 @@
+#include "drawcomponent.h"
+#include <string>
+
+DrawComponent::DrawComponent(std::shared_ptr<Shape> shape, std::string shape_name)
+{
+ m_shape = shape;
+ m_shape_name = shape_name;
+}
+
+DrawComponent::DrawComponent(std::shared_ptr<Shape> shape)
+{
+ m_shape = shape;
+}
+
+DrawComponent::DrawComponent(std::vector<std::shared_ptr<Shape>> shapes)
+{
+ m_shapes = shapes;
+ hasMultipleShapes = true;
+}
+
+
+void DrawComponent::addMaterial(std::string material_name, std::string material_filepath){
+ Global::graphics.addMaterial(material_name, material_filepath);
+ m_material_name = material_name;
+ hasMaterial = true;
+}
+
+std::shared_ptr<Shape> DrawComponent::getShape(){
+ return m_shape;
+}
+
+std::vector<std::shared_ptr<Shape>> DrawComponent::getShapesWithMaterials(){
+ if (hasMultipleShapes){
+ return m_shapes;
+ }
+}
+
+std::string DrawComponent::getShapeName(){
+ return m_shape_name;
+}
+
+std::shared_ptr<Material> DrawComponent::getMaterial(){
+ return Global::graphics.getMaterial(m_material_name);
+}
+
+bool DrawComponent::objHasMaterial(){
+ return hasMaterial;
+}
+
+bool DrawComponent::objHasMultipleShapes(){
+ return hasMultipleShapes;
+}
+
+
diff --git a/engine-ocean/Game/Components/PathfindComponent.h b/engine-ocean/Game/Components/PathfindComponent.h
new file mode 100644
index 0000000..13f4e6d
--- /dev/null
+++ b/engine-ocean/Game/Components/PathfindComponent.h
@@ -0,0 +1,22 @@
+#ifndef PATHFINDCOMPONENT_H
+#define PATHFINDCOMPONENT_H
+
+
+#include "Game/Systems/Pathfinding/pathfinder.h"
+#include "glm/fwd.hpp"
+#include <vector>
+#include "Component.h"
+
+class PathfindComponent : public Component
+{
+public:
+ PathfindComponent(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles);
+ std::vector<glm::vec3> getPath(const glm::vec3 &A, const glm::vec3 &B);
+
+private:
+ std::vector<glm::vec3> m_vertices;
+ std::vector<glm::ivec3> m_triangles;
+ std::unique_ptr<Pathfinder> m_pathfinder;
+};
+
+#endif // PATHFINDCOMPONENT_H
diff --git a/engine-ocean/Game/Components/TransformComponent.cpp b/engine-ocean/Game/Components/TransformComponent.cpp
new file mode 100644
index 0000000..582b623
--- /dev/null
+++ b/engine-ocean/Game/Components/TransformComponent.cpp
@@ -0,0 +1,92 @@
+#include "transformcomponent.h"
+
+TransformComponent::TransformComponent(std::shared_ptr<ModelTransform> mt,
+ std::string entity_id,
+ std::map<std::string,
+ BlackboardData>& global_blackboard, bool isAI):
+ m_model_transform(mt),
+ m_global_blackboard(global_blackboard),
+ isAIObject(isAI)
+{
+ old_pos = mt->getPos();
+ estimated_final_pos = mt->getPos();
+ m_entity_id = entity_id;
+
+ // initialize blackboard data for entity
+ BlackboardData data;
+ m_global_blackboard.insert(std::pair<std::string, BlackboardData>(m_entity_id, data));
+ m_global_blackboard[m_entity_id].locationData.currPos = old_pos;
+}
+
+std::shared_ptr<ModelTransform> TransformComponent::getMT(){
+ return m_model_transform;
+}
+std::vector<std::shared_ptr<ModelTransform>> TransformComponent::getAllMT(){
+ return m_all_model_transforms;
+}
+
+bool TransformComponent::hasMultipleMT(){
+ return multipleMT;
+}
+
+void TransformComponent::translate(const glm::vec3 &delta){
+ m_model_transform->translate(delta);
+
+ // update old pos for collisions
+
+ old_pos = m_model_transform->getPos();
+
+ if (isAIObject){
+ m_global_blackboard[m_entity_id].locationData.currPos = old_pos;
+ }
+}
+
+void TransformComponent::setPos(const glm::vec3 &new_pos){
+ m_model_transform->setPos(new_pos);
+
+ // update old pos for collisions
+ old_pos = new_pos;
+
+ if (isAIObject){
+ m_global_blackboard[m_entity_id].locationData.currPos = old_pos;
+ }
+}
+
+glm::vec3 TransformComponent::getPos(){
+ return m_model_transform->getPos();
+}
+
+void TransformComponent::setScale(const glm::vec3 &scale){
+ m_model_transform->setScale(scale);
+}
+
+glm::vec3 TransformComponent::getScale(){
+ return m_model_transform->getScale();
+}
+
+float TransformComponent::getYRotationAngle(){
+ glm::mat4 rotMat = m_model_transform->getRotation();
+ float ry0 = rotMat[0][2];
+// float ry1 = rotMat[1][2];
+// float ry2 = rotMat[2][2];
+
+// float sign = 1.f;
+// if (ry1*ry2 < 0) sign = -1.f;
+
+// float angley = std::atan2(-ry0, sign*pow((pow(ry1,2) + pow(ry2,2)), .5));
+ float angley = -std::asin(ry0);
+ float angley2 = M_PI - angley;
+
+ //std::cout << "angle 1: " << angley << std::endl;
+ std::cout << "angle 2: " << angley2 << std::endl;
+
+ return angley;
+}
+
+void TransformComponent::setRotation(float angle, glm::vec3 axis){
+ m_model_transform->rotate(angle, axis);
+}
+
+
+
+
diff --git a/engine-ocean/Game/Components/component.cpp b/engine-ocean/Game/Components/component.cpp
new file mode 100644
index 0000000..f557273
--- /dev/null
+++ b/engine-ocean/Game/Components/component.cpp
@@ -0,0 +1,6 @@
+#include "component.h"
+
+Component::Component()
+{
+
+}
diff --git a/engine-ocean/Game/Components/drawcomponent.h b/engine-ocean/Game/Components/drawcomponent.h
new file mode 100644
index 0000000..94f4b21
--- /dev/null
+++ b/engine-ocean/Game/Components/drawcomponent.h
@@ -0,0 +1,41 @@
+#ifndef DRAWCOMPONENT_H
+#define DRAWCOMPONENT_H
+
+
+#include "Graphics/global.h"
+#include <string>
+#include "Component.h"
+
+class DrawComponent : public Component
+{
+public:
+ DrawComponent(std::shared_ptr<Shape> shape);
+ DrawComponent(std::shared_ptr<Shape> shape, std::string shape_name);
+
+ // for materials, with multiple shape parts
+ DrawComponent(std::vector<std::shared_ptr<Shape>> shapes);
+
+
+ void draw(const std::shared_ptr<ModelTransform> &entity_mt);
+ void addMaterial(std::string material_name, std::string material_filepath);
+ std::shared_ptr<Material> getMaterial();
+ std::shared_ptr<Shape> getShape();
+ std::vector<std::shared_ptr<Shape>> getShapesWithMaterials();
+ bool objHasMaterial();
+ bool objHasMultipleShapes();
+
+ std::string getShapeName();
+
+private:
+ std::shared_ptr<Shape> m_shape;
+ std::vector<std::shared_ptr<Shape>> m_shapes;
+
+ std::string m_material_name;
+ bool hasMaterial = false;
+ std::string m_shape_name = "empty";
+
+ bool hasMultipleShapes = false;
+
+};
+
+#endif // DRAWCOMPONENT_H
diff --git a/engine-ocean/Game/Components/pathfindcomponent.cpp b/engine-ocean/Game/Components/pathfindcomponent.cpp
new file mode 100644
index 0000000..ad87e23
--- /dev/null
+++ b/engine-ocean/Game/Components/pathfindcomponent.cpp
@@ -0,0 +1,16 @@
+#include "pathfindcomponent.h"
+#include "glm/glm.hpp"
+#include <vector>
+
+PathfindComponent::PathfindComponent(std::vector<glm::vec3> vertices, std::vector<glm::ivec3> triangles):
+ m_vertices(vertices),
+ m_triangles(triangles),
+ m_pathfinder(std::make_unique<Pathfinder>(vertices, triangles))
+{
+
+}
+
+
+std::vector<glm::vec3> PathfindComponent::getPath(const glm::vec3 &A, const glm::vec3 &B){
+ return m_pathfinder->findPath(A,B);
+}
diff --git a/engine-ocean/Game/Components/playercontrolcomponent.cpp b/engine-ocean/Game/Components/playercontrolcomponent.cpp
new file mode 100644
index 0000000..40062f1
--- /dev/null
+++ b/engine-ocean/Game/Components/playercontrolcomponent.cpp
@@ -0,0 +1,6 @@
+#include "playercontrolcomponent.h"
+
+PlayerControlComponent::PlayerControlComponent()
+{
+
+}
diff --git a/engine-ocean/Game/Components/playercontrolcomponent.h b/engine-ocean/Game/Components/playercontrolcomponent.h
new file mode 100644
index 0000000..2a3d91c
--- /dev/null
+++ b/engine-ocean/Game/Components/playercontrolcomponent.h
@@ -0,0 +1,11 @@
+#ifndef PLAYERCONTROLCOMPONENT_H
+#define PLAYERCONTROLCOMPONENT_H
+
+
+class PlayerControlComponent
+{
+public:
+ PlayerControlComponent();
+};
+
+#endif // PLAYERCONTROLCOMPONENT_H
diff --git a/engine-ocean/Game/Components/transformcomponent.h b/engine-ocean/Game/Components/transformcomponent.h
new file mode 100644
index 0000000..7b6a5c2
--- /dev/null
+++ b/engine-ocean/Game/Components/transformcomponent.h
@@ -0,0 +1,54 @@
+#ifndef TRANSFORMCOMPONENT_H
+#define TRANSFORMCOMPONENT_H
+
+#include "Game/Systems/aisystem.h"
+#include "Graphics/global.h"
+#include <memory>
+#include "Component.h"
+
+class TransformComponent : public Component
+{
+public:
+ TransformComponent(std::shared_ptr<ModelTransform> mt,
+ std::string entity_id,
+ std::map<std::string, BlackboardData>& m_global_blackboard,
+ bool isAI = false);
+
+ void translate(const glm::vec3 &delta);
+ void setPos(const glm::vec3 &new_pos);
+ void setScale(const glm::vec3 &scale);
+ std::shared_ptr<ModelTransform> getMT();
+ std::vector<std::shared_ptr<ModelTransform>> getAllMT();
+ glm::vec3 getScale();
+ //glm::vec3 getRotation();
+ void setRotation(float angle, glm::vec3 axis);
+ float getYRotationAngle();
+
+
+
+
+ bool hasMultipleMT();
+ glm::vec3 getPos();
+
+ // used for collisions
+ glm::vec3 old_pos;
+ glm::vec3 estimated_final_pos;
+ bool onGround = false;
+ bool movingLaterally = false;
+ float gravity = -25.f;
+ float yVelocity = 0.f;
+
+
+
+private:
+ std::shared_ptr<ModelTransform> m_model_transform;
+ std::vector<std::shared_ptr<ModelTransform>> m_all_model_transforms;
+ bool multipleMT = false;
+ std::map<std::string, BlackboardData>& m_global_blackboard;
+ std::string m_entity_id;
+ bool isAIObject = false;
+
+
+};
+
+#endif // TRANSFORMCOMPONENT_H
diff --git a/engine-ocean/Game/Environment/Environment.cpp b/engine-ocean/Game/Environment/Environment.cpp
new file mode 100644
index 0000000..2782194
--- /dev/null
+++ b/engine-ocean/Game/Environment/Environment.cpp
@@ -0,0 +1,6 @@
+#include "Environment.h"
+
+Environment::Environment()
+{
+
+}
diff --git a/engine-ocean/Game/Environment/Environment.h b/engine-ocean/Game/Environment/Environment.h
new file mode 100644
index 0000000..90a5409
--- /dev/null
+++ b/engine-ocean/Game/Environment/Environment.h
@@ -0,0 +1,12 @@
+#ifndef ENVIRONMENT_H
+#define ENVIRONMENT_H
+
+class Environment
+{
+public:
+ Environment();
+ virtual void draw() = 0;
+ virtual void update(double deltaTime) = 0;
+};
+
+#endif // ENVIRONMENT_H
diff --git a/engine-ocean/Game/Environment/environmentsystem.cpp b/engine-ocean/Game/Environment/environmentsystem.cpp
new file mode 100644
index 0000000..f94b804
--- /dev/null
+++ b/engine-ocean/Game/Environment/environmentsystem.cpp
@@ -0,0 +1,40 @@
+#include "environmentsystem.h"
+#include "Game/Environment/grassenvironment.h"
+#include "Game/Environment/skyboxenvironment.h"
+#include "Game/Environment/water.h"
+
+EnvironmentSystem::EnvironmentSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::shared_ptr<Camera> camera)
+{
+ addEnviron<GrassEnvironment>(std::make_shared<GrassEnvironment>(rigid_gameobjects, dynamic_gameobjects, camera));
+ addEnviron<SkyboxEnvironment>(std::make_shared<SkyboxEnvironment>(camera));
+ addEnviron<Water>(std::make_shared<Water>(camera));
+
+
+
+}
+
+void EnvironmentSystem::draw(){
+ for (auto &environ : m_environs){
+ environ.second->draw();
+ }
+
+}
+
+void EnvironmentSystem::drawNonWater(){
+ getEnviron<GrassEnvironment>()->draw();
+ getEnviron<SkyboxEnvironment>()->draw();
+
+
+}
+
+void EnvironmentSystem::update(double deltaTime){
+ for (auto &environ : m_environs){
+ environ.second->update(deltaTime);
+ }
+
+}
+
+void EnvironmentSystem::scrollEvent(double distance){}
+void EnvironmentSystem::mousePosEvent(double xpos, double ypos) {}
diff --git a/engine-ocean/Game/Environment/environmentsystem.h b/engine-ocean/Game/Environment/environmentsystem.h
new file mode 100644
index 0000000..240ecb7
--- /dev/null
+++ b/engine-ocean/Game/Environment/environmentsystem.h
@@ -0,0 +1,41 @@
+#ifndef ENVIRONMENTSYSTEM_H
+#define ENVIRONMENTSYSTEM_H
+#include "Game/Environment/Environment.h"
+#include "Game/Systems/system.h"
+
+class EnvironmentSystem : public System
+{
+public:
+ EnvironmentSystem(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::shared_ptr<Camera> camera);
+ void draw() override;
+ void update(double deltaTime) override;
+ void scrollEvent(double distance) override;
+ void mousePosEvent(double xpos, double ypos) override;
+ void drawNonWater();
+
+
+ template <typename T>
+ void addEnviron(std::shared_ptr<T> &&environ){
+ m_environs.put<T>(std::forward<std::shared_ptr<T>>(environ));
+ }
+
+
+ template <class T>
+ T* getEnviron(){
+ auto comp = m_environs.find<T>();
+ assert(comp != m_environs.end());
+ return static_cast<T*>(comp->second.get());
+ }
+
+ template <class T>
+ void removeEnviron(){
+ m_environs.remove<T>();
+ }
+private:
+ TypeMap<std::shared_ptr<Environment>> m_environs;
+
+};
+
+#endif // ENVIRONMENTSYSTEM_H
diff --git a/engine-ocean/Game/Environment/grassenvironment.cpp b/engine-ocean/Game/Environment/grassenvironment.cpp
new file mode 100644
index 0000000..1d1ed9b
--- /dev/null
+++ b/engine-ocean/Game/Environment/grassenvironment.cpp
@@ -0,0 +1,85 @@
+#include "grassenvironment.h"
+#include "Game/Components/CollisionComponents/BoundingTriangle.h"
+#include "Game/Components/CollisionComponents/CollisionComponent.h"
+#include "Game/Components/TransformComponent.h"
+#include "Game/GameObjects/GameObject.h"
+#include "Graphics/global.h"
+
+GrassEnvironment::GrassEnvironment(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::shared_ptr<Camera> camera):
+ m_rigid_gameobjects(rigid_gameobjects),
+ m_dynamic_gameobjects(dynamic_gameobjects),
+ m_camera(camera)
+{
+
+ initializeGrassVBO();
+}
+
+void GrassEnvironment::initializeGrassVBO(){
+// grass_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/meadow_texture_atlas.png").textureID;
+// wind_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/wind_flowmap1.png").textureID;
+// meadow_tex = Global::graphics.loadTextureFromFile("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/meadow_flower_map.png").textureID;
+
+
+// std::vector<glm::vec3> surface_points = m_rigid_gameobjects["ground"]->getComponent<CollisionComponent>()->getCollisionShape<BoundingTriangle>()->getSurfacePoints();
+// positions.insert(std::end(positions), std::begin(surface_points), std::end(surface_points));
+
+
+// glGenVertexArrays(1, &VAO);
+// glGenBuffers(1, &VBO);
+// glBindVertexArray(VAO);
+
+// glBindBuffer(GL_ARRAY_BUFFER, VBO);
+// glBufferData(GL_ARRAY_BUFFER, positions.size()*sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
+
+// glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
+
+// // unbind
+// glEnableVertexAttribArray(0);
+// glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+glm::vec2 GrassEnvironment::getRandomOffset(int ub, int numRows){
+ int index = floor(Global::graphics.generateRandomNumbers(0, ub));
+ int column = index % numRows;
+ float xoffset = static_cast<float>(column)/static_cast<float>(numRows);
+
+ int row = floor(index/numRows);
+ float yOffset = static_cast<float>(row)/static_cast<float>(numRows);
+ return glm::vec2(xoffset, yOffset);
+}
+
+void GrassEnvironment::draw(){
+ // draw grass
+ glPointSize(8.f);
+ Global::graphics.bindShader("grass");
+
+ // activate texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, grass_tex);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, wind_tex);
+
+ glActiveTexture(GL_TEXTURE7);
+ glBindTexture(GL_TEXTURE_2D, meadow_tex);
+
+ // update time
+ glUniform1f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "u_time"), glfwGetTime()*.1f);
+ // update player pos
+ glm::vec3 playerPos = m_dynamic_gameobjects.at("player")->getComponent<TransformComponent>()->getPos();
+ glUniform3f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "playerPos"), playerPos.x, playerPos.y, playerPos.z);
+
+ //glm::vec2 offset = getRandomOffset(4, 2);
+ // update offset
+ //glUniform2f(glGetUniformLocation(Global::graphics.getShaderID("grass"), "atlas_offset"), offset.x, offset.y);
+
+
+ Global::graphics.setCameraData(m_camera);
+ Global::graphics.setGlobalData(glm::vec3(.5f));
+ glBindVertexArray(VAO);
+ glDrawArrays(GL_POINTS, 0, positions.size());
+};
+
+void GrassEnvironment::update(double deltaTime){};
diff --git a/engine-ocean/Game/Environment/grassenvironment.h b/engine-ocean/Game/Environment/grassenvironment.h
new file mode 100644
index 0000000..f92b6c3
--- /dev/null
+++ b/engine-ocean/Game/Environment/grassenvironment.h
@@ -0,0 +1,37 @@
+#ifndef GRASSENVIRONMENT_H
+#define GRASSENVIRONMENT_H
+#include "Game/GameObjects/GameObject.h"
+#include "Graphics/global.h"
+#include "Graphics/camera.h"
+#include <GLFW/glfw3.h>
+#include "Environment.h"
+
+class GrassEnvironment : public Environment
+{
+public:
+ GrassEnvironment(std::map<std::string, std::shared_ptr<GameObject>>& rigid_gameobjects,
+ std::map<std::string, std::shared_ptr<GameObject>>& dynamic_gameobjects,
+ std::shared_ptr<Camera> camera);
+
+ void draw() override;
+ void update(double deltaTime) override;
+private:
+ GLuint VAO, VBO;
+ GLuint grass_tex, wind_tex, meadow_tex;
+ std::vector<glm::vec3> positions;
+
+
+
+ std::map<std::string, std::shared_ptr<GameObject>>& m_rigid_gameobjects;
+ std::map<std::string, std::shared_ptr<GameObject>>& m_dynamic_gameobjects;
+ std::shared_ptr<Camera> m_camera;
+
+
+ void initializeGrassVBO();
+ glm::vec2 getRandomOffset(int ub, int numRows);
+
+
+
+};
+
+#endif // GRASSENVIRONMENT_H
diff --git a/engine-ocean/Game/Environment/skyboxenvironment.cpp b/engine-ocean/Game/Environment/skyboxenvironment.cpp
new file mode 100644
index 0000000..f0ad41f
--- /dev/null
+++ b/engine-ocean/Game/Environment/skyboxenvironment.cpp
@@ -0,0 +1,64 @@
+#include "skyboxenvironment.h"
+#include "Graphics/global.h"
+
+
+SkyboxEnvironment::SkyboxEnvironment(std::shared_ptr<Camera> camera):
+ m_camera(camera),
+ m_rotation_mat(std::make_shared<ModelTransform>())
+{
+ initializeVAO();
+}
+
+void SkyboxEnvironment::initializeVAO(){
+ skybox_tex = Global::graphics.loadCubeMap(m_skyboxTextureFiles);
+
+ glGenVertexArrays(1, &VAO);
+ glGenBuffers(1, &VBO);
+ glBindVertexArray(VAO);
+
+ glBindBuffer(GL_ARRAY_BUFFER, VBO);
+ glBufferData(GL_ARRAY_BUFFER, m_vertices.size()*sizeof(float), m_vertices.data(), GL_STATIC_DRAW);
+
+ glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3*sizeof(float), (void*)0);
+
+ // unbind
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+
+void SkyboxEnvironment::draw(){
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_CULL_FACE);
+
+ Global::graphics.bindShader("skybox");
+ //Global::graphics.setCameraData(m_camera);
+
+ // activate texture
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, skybox_tex);
+
+ // manually set view and projection, for non-translating view
+ glm::mat4 projection = m_camera->getProjection();
+ glm::mat4 view = m_camera->getView();
+ view[3] = glm::vec4(0.f);
+
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "view"), 1, GL_FALSE, glm::value_ptr(view[0]));
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "projection"), 1, GL_FALSE, glm::value_ptr(projection[0]));
+
+ // apply rotation matrix
+ glUniformMatrix4fv(glGetUniformLocation(Global::graphics.getShaderID("skybox"), "rotation"), 1, GL_FALSE, glm::value_ptr(m_rotation_mat->getRotation()[0]));
+
+ //Global::graphics.setGlobalData(glm::vec3(.5f));
+ glBindVertexArray(VAO);
+ glDrawArrays(GL_TRIANGLES, 0, m_vertices.size());
+
+ glDepthFunc(GL_LESS);
+}
+
+void SkyboxEnvironment::update(double deltaTime){
+ m_rotation += ROTATE_SPEED * deltaTime;
+ m_rotation_mat->rotate(glm::radians(ROTATE_SPEED), glm::vec3(0.f, 1.f, 0.f));
+
+
+}
diff --git a/engine-ocean/Game/Environment/skyboxenvironment.h b/engine-ocean/Game/Environment/skyboxenvironment.h
new file mode 100644
index 0000000..aa86c0c
--- /dev/null
+++ b/engine-ocean/Game/Environment/skyboxenvironment.h
@@ -0,0 +1,103 @@
+#ifndef SKYBOXENVIRONMENT_H
+#define SKYBOXENVIRONMENT_H
+#include "Graphics/global.h"
+#include "Graphics/camera.h"
+#include <GLFW/glfw3.h>
+#include "Environment.h"
+
+
+class SkyboxEnvironment : public Environment
+{
+public:
+ SkyboxEnvironment(std::shared_ptr<Camera> camera);
+ void draw() override;
+ void update(double deltaTime) override;
+private:
+ void initializeVAO();
+
+ GLuint VAO;
+ GLuint VBO;
+ GLuint EBO;
+ GLuint skybox_tex;
+ std::shared_ptr<Camera> m_camera;
+
+ float SIZE = 500.f;
+
+ std::vector<int> m_vertex_indices = {
+ // Right
+ 1, 2, 6,
+ 6, 5, 1,
+ // Left
+ 0, 4, 7,
+ 7, 3, 0,
+ // Top
+ 4, 5, 6,
+ 6, 7, 4,
+ // Bottom
+ 0, 3, 2,
+ 2, 1, 0,
+ // Back
+ 0, 1, 5,
+ 5, 4, 0,
+ // Front
+ 3, 7, 6,
+ 6, 2, 3
+ };
+ std::vector<GLfloat> m_vertices = {
+ -SIZE, SIZE, -SIZE,
+ -SIZE, -SIZE, -SIZE,
+ SIZE, -SIZE, -SIZE,
+ SIZE, -SIZE, -SIZE,
+ SIZE, SIZE, -SIZE,
+ -SIZE, SIZE, -SIZE,
+
+ -SIZE, -SIZE, SIZE,
+ -SIZE, -SIZE, -SIZE,
+ -SIZE, SIZE, -SIZE,
+ -SIZE, SIZE, -SIZE,
+ -SIZE, SIZE, SIZE,
+ -SIZE, -SIZE, SIZE,
+
+ SIZE, -SIZE, -SIZE,
+ SIZE, -SIZE, SIZE,
+ SIZE, SIZE, SIZE,
+ SIZE, SIZE, SIZE,
+ SIZE, SIZE, -SIZE,
+ SIZE, -SIZE, -SIZE,
+
+ -SIZE, -SIZE, SIZE,
+ -SIZE, SIZE, SIZE,
+ SIZE, SIZE, SIZE,
+ SIZE, SIZE, SIZE,
+ SIZE, -SIZE, SIZE,
+ -SIZE, -SIZE, SIZE,
+
+ -SIZE, SIZE, -SIZE,
+ SIZE, SIZE, -SIZE,
+ SIZE, SIZE, SIZE,
+ SIZE, SIZE, SIZE,
+ -SIZE, SIZE, SIZE,
+ -SIZE, SIZE, -SIZE,
+
+ -SIZE, -SIZE, -SIZE,
+ -SIZE, -SIZE, SIZE,
+ SIZE, -SIZE, -SIZE,
+ SIZE, -SIZE, -SIZE,
+ -SIZE, -SIZE, SIZE,
+ SIZE, -SIZE, SIZE
+ };
+
+ std::vector<const char*> m_skyboxTextureFiles = {"/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/right.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/left.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/up.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/bottom.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/back.png",
+ "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/skybox/hills2/front.png"};
+
+ float ROTATE_SPEED = .1f; // 1 degree per sec
+ float m_rotation = 0.f;
+ std::shared_ptr<ModelTransform> m_rotation_mat;
+
+};
+
+#endif // SKYBOXENVIRONMENT_H
diff --git a/engine-ocean/Game/Environment/water.cpp b/engine-ocean/Game/Environment/water.cpp
new file mode 100644
index 0000000..537bfbd
--- /dev/null
+++ b/engine-ocean/Game/Environment/water.cpp
@@ -0,0 +1,48 @@
+#include "water.h"
+#include "GLFW/glfw3.h"
+
+Water::Water(std::shared_ptr<Camera> camera):
+ m_camera(camera)
+{
+
+ initializeQuad();
+
+}
+
+
+void Water::initializeQuad(){
+ m_waterPlane = Global::graphics.addShape("water", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Meshes/howl_field_water.obj");
+ m_waterMT = std::make_shared<ModelTransform>();
+ m_waterMT->setScale(glm::vec3(1.f));
+ m_waterMT->setPos(glm::vec3(0.f));
+ Global::graphics.setWaterHeight(m_waterMT->getPos().y);
+
+ du_dv_map = Global::graphics.loadTextureFromFile_Repeat("/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/waterDUDV.png").textureID;
+
+
+}
+
+void Water::draw(){
+ Global::graphics.bindShader("water");
+
+ glActiveTexture(GL_TEXTURE8);
+ glBindTexture(GL_TEXTURE_2D, Global::graphics.getReflectionTexture());
+ glActiveTexture(GL_TEXTURE9);
+ glBindTexture(GL_TEXTURE_2D, Global::graphics.getRefractionTexture());
+ glActiveTexture(GL_TEXTURE10);
+ glBindTexture(GL_TEXTURE_2D, du_dv_map);
+ glUniform1f(glGetUniformLocation(Global::graphics.getShaderID("water"), "moveFactor"), m_moveFactor);
+
+ Global::graphics.setCameraData(m_camera);
+
+ Global::graphics.drawShape(Global::graphics.getShape("water"), m_waterMT);
+
+}
+
+void Water::update(double deltaTime){
+ m_moveFactor += WAVE_SPEED*deltaTime*.01f;
+ // loop back to 0 if it gets to one
+ if (m_moveFactor == 1) m_moveFactor = 0;
+}
+
+
diff --git a/engine-ocean/Game/Environment/water.h b/engine-ocean/Game/Environment/water.h
new file mode 100644
index 0000000..c0df0da
--- /dev/null
+++ b/engine-ocean/Game/Environment/water.h
@@ -0,0 +1,38 @@
+#ifndef WATER_H
+#define WATER_H
+#include "Graphics/global.h"
+
+
+#include "Environment.h"
+
+class Water : public Environment
+{
+public:
+ Water(std::shared_ptr<Camera> camera);
+ void draw() override;
+ void update(double deltaTime) override;
+
+
+
+private:
+
+ GLuint du_dv_map;
+ void initializeQuad();
+
+
+
+
+
+ std::shared_ptr<Camera> m_camera;
+ std::vector<glm::vec3> m_waterPlane;
+ std::shared_ptr<ModelTransform> m_waterMT;
+
+ const float WAVE_SPEED = .008f;
+ float m_moveFactor = 0.f;
+
+
+
+
+};
+
+#endif // WATER_H
diff --git a/engine-ocean/Game/GameObjects/GameObject.cpp b/engine-ocean/Game/GameObjects/GameObject.cpp
new file mode 100644
index 0000000..0c7bce8
--- /dev/null
+++ b/engine-ocean/Game/GameObjects/GameObject.cpp
@@ -0,0 +1,27 @@
+#include "gameobject.h"
+#include "Game/Components/DrawComponent.h"
+
+//GameObject::GameObject(std::shared_ptr<Shape> object, std::shared_ptr<ModelTransform> object_mt)
+//{
+// m_object = object;
+// m_object_mt = object_mt;
+//}
+
+GameObject::GameObject(){
+
+}
+
+//GameObject::~GameObject(){
+
+//}
+
+//void GameObject::addMaterial(std::string material_name, std::string material_filepath){
+// getComponent<DrawComponent>()->addMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse.png");
+//}
+
+//void GameObject::addComps(){
+// addComponent<DrawComponent>(m_object);
+// getComponent<DrawComponent>()->addMaterial("mouse", "/Users/jesswan/Desktop/cs1950u/cs1950u-jjesswan/Resources/Images/mouse.png");
+//}
+
+
diff --git a/engine-ocean/Game/GameObjects/GameObject.h b/engine-ocean/Game/GameObjects/GameObject.h
new file mode 100644
index 0000000..a9ddbd7
--- /dev/null
+++ b/engine-ocean/Game/GameObjects/GameObject.h
@@ -0,0 +1,54 @@
+#ifndef GAMEOBJECT_H
+#define GAMEOBJECT_H
+
+
+#include "Game/Components/Component.h"
+#include "Game/TypeMap.h"
+#include <memory>
+#include "Graphics/global.h"
+
+class GameObject
+{
+public:
+ GameObject();
+ ~GameObject(){
+ std::cout << "deleting" << std::endl;
+ }
+
+ 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(){
+// auto comp = m_components.find<T>();
+// assert(comp != m_components.end());
+ m_components.remove<T>();
+ }
+
+
+
+private:
+ void setPlayerPos();
+ void makePlayer();
+
+ TypeMap<std::unique_ptr<Component>> m_components;
+ std::shared_ptr<Shape> m_object;
+ std::shared_ptr<ModelTransform> m_object_mt;
+
+};
+
+#endif // GAMEOBJECT_H
diff --git a/engine-ocean/Game/GameWorld.cpp b/engine-ocean/Game/GameWorld.cpp
new file mode 100644
index 0000000..a274ea7
--- /dev/null
+++ b/engine-ocean/Game/GameWorld.cpp
@@ -0,0 +1,224 @@
+#include "GameWorld.h"
+#include "Game/Environment/environmentsystem.h"
+#include "Game/Systems/Inventory/inventorysystem.h"
+#include "Game/Systems/Pathfinding/aimovementsystem.h"
+#include "Game/Systems/camerasystem.h"
+#include "Game/Systems/charactercontrollersystem.h"
+#include "Game/Systems/CollisionSystems/collisionsystem.h"
+#include "Game/Systems/drawsystem.h"
+#include "Game/Systems/objectcreationsystem.h"
+#include "Game/Systems/physicssystem.h"
+#include "Game/Systems/UI/uisystem.h"
+
+
+
+GameWorld::GameWorld(std::map<int, Input>& input_map) :
+ camera(std::make_shared<Camera>()),
+ m_input_map(input_map)
+{
+
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_DEPTH_TEST);
+ m_game_object_names = std::vector<std::string>();
+ initializeInputMap();
+
+ addSystem<ObjectCreationSystem>(std::make_shared<ObjectCreationSystem>(m_gameobjects,
+ m_dynamic_gameobjects,
+ m_rigid_gameobjects,
+ m_global_blackboard,
+ m_lootables));
+ addSystem<DrawSystem>(std::make_shared<DrawSystem>(m_gameobjects));
+ addSystem<PhysicsSystem>(std::make_shared<PhysicsSystem>(m_dynamic_gameobjects, m_global_blackboard, m_lootables));
+ // addSystem<CharacterControllerSystem>(std::make_shared<CharacterControllerSystem>(m_gameobjects, camera, m_input_map, m_global_blackboard));
+
+// addSystem<CollisionSystem>(std::make_shared<CollisionSystem>(m_gameobjects,
+// m_dynamic_gameobjects,
+// m_rigid_gameobjects,
+// m_input_map,
+// m_global_blackboard));
+// addSystem<AIMovementSystem>(std::make_shared<AIMovementSystem>(m_dynamic_gameobjects,
+// m_rigid_gameobjects));
+ addSystem<CameraSystem>(std::make_shared<CameraSystem>(m_gameobjects, camera, m_input_map));
+
+
+ // seperate systems
+// collisionSystem = std::make_shared<EnvironmentCollisionDetectionSystem>(m_dynamic_gameobjects,
+// m_rigid_gameobjects,
+// m_lootables,
+// m_global_blackboard);
+ //environmentSystem = std::make_shared<EnvironmentSystem>(m_rigid_gameobjects, m_dynamic_gameobjects, camera);
+
+
+}
+
+
+void GameWorld::createKeyInput(int inputVal){
+ Input input;
+ input.inputVal = inputVal;
+ m_input_map[inputVal] = input;
+}
+
+void GameWorld::initializeInputMap(){
+ createKeyInput(GLFW_KEY_W);
+ createKeyInput(GLFW_KEY_A);
+ createKeyInput(GLFW_KEY_S);
+ createKeyInput(GLFW_KEY_D);
+ createKeyInput(GLFW_KEY_SPACE);
+ createKeyInput(GLFW_KEY_P);
+ //createKeyInput(GLFW_KEY_R);
+
+ Input mousePress;
+ mousePress.inputVal = GLFW_MOUSE_BUTTON_LEFT;
+ m_input_map[GLFW_MOUSE_BUTTON_LEFT] = mousePress;
+
+ Input scrollWheel;
+ scrollWheel.inputVal = 1;
+ m_input_map[1] = scrollWheel;
+}
+
+void GameWorld::mousePosEvent(double xpos, double ypos){
+// m_mousePos = glm::vec2(xpos, ypos);
+ if (m_mouseIsHeldTime <= 1 && m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){
+ m_mouseIsHeldTime ++;
+ }
+
+ if (m_mouseIsHeldTime > 1 && m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){
+ m_input_map[GLFW_MOUSE_BUTTON_LEFT].isHeld = true;
+ m_mouseIsHeldTime ++;
+ }
+
+ if (m_input_map[GLFW_MOUSE_BUTTON_LEFT].isActive){
+
+ }
+
+ for (auto &system : m_systems){
+ system.second->mousePosEvent(xpos, ypos);
+ }
+
+
+}
+
+void GameWorld::scrollEvent(double distance){
+ for (auto &system : m_systems){
+ system.second->scrollEvent(distance);
+ }
+}
+
+void GameWorld::update(double deltaTime){
+ for (auto &system : m_systems){
+ system.second->update(deltaTime);
+
+ // detect collision after everything
+ // collisionSystem->update(deltaTime);
+ }
+
+ // environmentSystem->update(deltaTime);
+
+
+}
+
+void GameWorld::draw(){
+
+ // then render normally
+ Global::graphics.setClearColor(glm::vec3(.77f, .85f, .99f));
+ Global::graphics.clearScreen(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ Global::graphics.bindShader("phong");
+ Global::graphics.setCameraData(camera);
+
+ Global::graphics.setGlobalData(glm::vec3(.5f));
+ Global::graphics.setClipPlane(glm::vec4(0, -1, 0, 100000));
+
+ for (auto &system : m_systems){
+ system.second->draw();
+ }
+
+ //Global::graphics.setCameraData(camera);
+ //environmentSystem->draw();
+
+}
+
+
+void GameWorld::mouseButtonEvent(int button, int action){
+ if (button == GLFW_MOUSE_BUTTON_LEFT){
+ if (action == GLFW_RELEASE){
+ if ( m_input_map[button].isActive && !m_input_map[button].isHeld){
+ // we know that button was released after one click (not hold), thus a click was made
+ m_input_map[button].isClicked = true;
+ }
+ m_input_map[button].isActive = false;
+ m_input_map[button].isHeld = false;
+ m_mouseIsHeldTime = 0;
+ m_input_map[button].checkClickTime = 0;
+ return;
+ }
+
+ if (action == GLFW_PRESS && !m_input_map[button].isHeld && !m_input_map[button].isActive){
+ m_input_map[button].isActive = true;
+ return;
+ }
+ }
+}
+
+void GameWorld::keyEvent(int key, int action){
+ switch(key){
+ case GLFW_KEY_W:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ case GLFW_KEY_A:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ case GLFW_KEY_S:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ case GLFW_KEY_D:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ case GLFW_KEY_SPACE:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ case GLFW_KEY_P:
+ if (action == GLFW_PRESS){
+ m_input_map.at(key).isActive = true;
+ }
+ if (action == GLFW_RELEASE){
+ m_input_map.at(key).isActive = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void GameWorld::framebufferResizeEvent(int width, int height){
+ Global::graphics.setFramebufferSize(glm::ivec2(width, height));
+}
+
+void GameWorld::windowResizeEvent(int width, int height){
+ Global::graphics.setWindowSize(glm::ivec2(width, height));
+ camera->resize(Global::graphics.getWindowSize().x, Global::graphics.getWindowSize().y);
+}
diff --git a/engine-ocean/Game/GameWorld.h b/engine-ocean/Game/GameWorld.h
new file mode 100644
index 0000000..8a99a9b
--- /dev/null
+++ b/engine-ocean/Game/GameWorld.h
@@ -0,0 +1,132 @@
+#ifndef GameWorld_H
+#define GameWorld_H
+#include "Game/Environment/environmentsystem.h"
+#include "Game/Systems/CollisionSystems/environmentcollisiondetectionsystem.h"
+#include "Game/Systems/aisystem.h"
+#include "Game/Systems/system.h"
+#include "Graphics/global.h"
+#include "Graphics/camera.h"
+#include <GLFW/glfw3.h>
+#include "screen.h"
+#include <set>
+
+struct Input {
+ // key presses
+ int inputVal = 0;
+
+ // mouse clicks
+ int xpos;
+ int ypos;
+
+ // mouse scrolls
+ double distance;
+
+ glm::vec3 translationDir = glm::vec3(0.f);
+
+ bool isActive = false;
+ bool isHeld = false;
+
+ bool isClicked = false;
+ int checkClickTime = 0;
+};
+
+
+class GameWorld
+{
+public:
+ GameWorld(std::map<int, Input>& input_map);
+
+
+ void update(double deltaTime);
+ void draw();
+ void keyEvent(int key, int action);
+ void mousePosEvent(double xpos, double ypos);
+ void mouseButtonEvent(int button, int action);
+ void scrollEvent(double distance);
+ void windowResizeEvent(int width, int height);
+ void framebufferResizeEvent(int width, int height);
+
+
+ template <typename T>
+ void addSystem(std::shared_ptr<T> &&component){
+ m_systems.put<T>(std::forward<std::shared_ptr<T>>(component));
+ }
+
+
+ template <class T>
+ T* getSystem(){
+ auto comp = m_systems.find<T>();
+ assert(comp != m_systems.end());
+ return static_cast<T*>(comp->second.get());
+ }
+
+ template <class T>
+ void removeSystem(){
+ m_external_systems.remove<T>();
+ }
+
+ template <typename T>
+ void addExternalSystem(std::shared_ptr<T> &&component){
+ m_external_systems.put<T>(std::forward<std::shared_ptr<T>>(component));
+ }
+
+
+ template <class T>
+ T* getExternalSystem(){
+ auto comp = m_external_systems.find<T>();
+ assert(comp != m_external_systems.end());
+ return static_cast<T*>(comp->second.get());
+ }
+
+ template <class T>
+ void removeExternalSystem(){
+ m_external_systems.remove<T>();
+ }
+
+
+
+private:
+// GLuint VAO, VBO;
+// GLuint grass_tex, wind_tex;
+// std::vector<glm::vec3> positions;
+
+ std::map<int, Input> m_input_map;
+
+ void createKeyInput(int inputVal);
+ void initializeInputMap();
+ void reset();
+
+
+ void initializeGrassVBO();
+
+ TypeMap<std::shared_ptr<System>> m_systems;
+ TypeMap<std::shared_ptr<System>> m_external_systems;
+
+ std::shared_ptr<Camera> camera;
+
+ std::map<std::string, std::shared_ptr<GameObject>> m_gameobjects;
+ std::vector<std::string> m_game_object_names;
+ std::map<std::string, std::shared_ptr<GameObject>> m_dynamic_gameobjects;
+ std::vector<std::string> m_dynamic_game_object_names;
+ std::map<std::string, std::shared_ptr<GameObject>> m_rigid_gameobjects;
+ std::vector<std::string> m_rigid_game_object_names;
+
+
+ std::shared_ptr<EnvironmentCollisionDetectionSystem> collisionSystem;
+ std::shared_ptr<EnvironmentSystem> environmentSystem;
+
+
+ // map that contains submaps of each data type
+ std::map<std::string, BlackboardData> m_global_blackboard;
+ bool m_checkingMouseClick = false;
+ int m_mouseIsHeldTime = 0;
+
+ glm::vec2 m_mousePos;
+
+ std::map<std::string, std::vector<std::shared_ptr<GameObject>>> m_lootables;
+ std::set<std::string> m_shownScreens;
+
+
+};
+
+#endif // GameWorld_H
diff --git a/engine-ocean/Game/GameplayScreen.cpp b/engine-ocean/Game/GameplayScreen.cpp
new file mode 100644
index 0000000..6d7acd7
--- /dev/null
+++ b/engine-ocean/Game/GameplayScreen.cpp
@@ -0,0 +1,44 @@
+#include "GameplayScreen.h"
+
+GameplayScreen::GameplayScreen(std::map<int, Input>& input_map):
+ m_input_map(input_map),
+ game(GameWorld(input_map))
+
+{
+ //game = GameWorld(m_input_map);
+}
+
+
+void GameplayScreen::mousePosEvent(double xpos, double ypos){
+ game.mousePosEvent(xpos, ypos);
+}
+
+void GameplayScreen::mouseButtonEvent(int button, int action){
+ game.mouseButtonEvent(button, action);
+}
+
+
+void GameplayScreen::scrollEvent(double distance){
+ game.scrollEvent(distance);
+}
+
+
+void GameplayScreen::update(double deltaTime){
+ game.update(deltaTime);
+}
+
+void GameplayScreen::draw(){
+ game.draw();
+}
+
+void GameplayScreen::keyEvent(int key, int action){
+ game.keyEvent(key, action);
+}
+
+void GameplayScreen::framebufferResizeEvent(int width, int height){
+ game.framebufferResizeEvent(width, height);
+}
+
+void GameplayScreen::windowResizeEvent(int width, int height){
+ game.windowResizeEvent(width, height);
+}
diff --git a/engine-ocean/Game/GameplayScreen.h b/engine-ocean/Game/GameplayScreen.h
new file mode 100644
index 0000000..d25d9ca
--- /dev/null
+++ b/engine-ocean/Game/GameplayScreen.h
@@ -0,0 +1,34 @@
+#ifndef GAMEPLAYSCREEN_H
+#define GAMEPLAYSCREEN_H
+#include "Game/GameWorld.h"
+#include "Graphics/global.h"
+#include "Graphics/camera.h"
+#include <GLFW/glfw3.h>
+#include "screen.h"
+
+
+
+class GameplayScreen: public Screen
+{
+public:
+ GameplayScreen(std::map<int, Input>& input_map);
+
+
+ void update(double deltaTime) override;
+ void draw() override;
+ void keyEvent(int key, int action) override;
+ void mousePosEvent(double xpos, double ypos) override;
+ void mouseButtonEvent(int button, int action) override;
+ void scrollEvent(double distance) override;
+ void windowResizeEvent(int width, int height) override;
+ void framebufferResizeEvent(int width, int height) override;
+
+private:
+ std::map<int, Input>& m_input_map;
+
+
+
+ GameWorld game;
+};
+
+#endif // GAMEPLAYSCREEN_H
diff --git a/engine-ocean/Game/MenuScreen.cpp b/engine-ocean/Game/MenuScreen.cpp
new file mode 100644
index 0000000..dcf2f2e
--- /dev/null
+++ b/engine-ocean/Game/MenuScreen.cpp
@@ -0,0 +1,59 @@
+#include "menuscreen.h"
+#include "Game/GameWorld.h"
+#include "Graphics/global.h"
+
+MenuScreen::MenuScreen(std::map<int, Input>& input_map):
+ m_input_map(input_map)
+{
+
+}
+
+MenuScreen::~MenuScreen(){
+
+}
+
+
+void MenuScreen::update(double deltaTime){
+
+
+}
+
+void MenuScreen::draw(){
+ Global::graphics.setClearColor(glm::vec3(0.f));
+ Global::graphics.clearScreen(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ Global::graphics.bindShader("text");
+ Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Game Menu", glm::ivec2(200, 200), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 1.f, 0.1f, glm::vec3(1, 1, 1));
+ Global::graphics.drawUIText(Global::graphics.getFont("opensans"), "Press 'B' to resume the game.", glm::ivec2(20, 70), AnchorPoint::TopLeft, Global::graphics.getFramebufferSize().x, 0.2f, 0.1f, glm::vec3(1, 1, 1));
+
+
+}
+
+void MenuScreen::keyEvent(int key, int action){
+
+}
+
+void MenuScreen::mousePosEvent(double xpos, double ypos){
+
+
+
+}
+
+void MenuScreen::mouseButtonEvent(int button, int action){
+
+
+}
+
+void MenuScreen::scrollEvent(double distance){
+
+
+}
+
+void MenuScreen::framebufferResizeEvent(int width, int height){
+ Global::graphics.setFramebufferSize(glm::ivec2(width, height));
+
+}
+
+void MenuScreen::windowResizeEvent(int width, int height){
+ Global::graphics.setWindowSize(glm::ivec2(width, height));
+
+}
diff --git a/engine-ocean/Game/Ocean/ocean.cpp b/engine-ocean/Game/Ocean/ocean.cpp
new file mode 100644
index 0000000..e8b88a8
--- /dev/null
+++ b/engine-ocean/Game/Ocean/ocean.cpp
@@ -0,0 +1,325 @@
+#include "ocean.h"
+#include <iostream>
+#include <Eigen/Dense>
+
+ocean::ocean()
+{
+ // to be used for efficiency during fft
+ init_wave_index_constants();
+
+}
+
+// initializes static constants (aka they are not time dependent)
+void ocean::init_wave_index_constants(){
+
+ for (int i=0; i<N; i++){
+ Eigen::Vector2i m_n = index_1d_to_2d(i);
+ int n_prime = m_n[0];
+ int m_prime = m_n[1];
+
+ Eigen::Vector2d k = get_k_vector(n_prime, m_prime);
+ Eigen::Vector2d k_conj = get_k_vector(-n_prime, m_prime);
+
+
+ // store h0'(n,m) and w'(n,m) for every index, to be used for later
+ Eigen::Vector2d h0_prime = h_0_prime(k);
+
+ // conjugate of a+bi is a-bi
+ Eigen::Vector2d h0_prime_conj = h_0_prime(k_conj);
+ h0_prime_conj = Eigen::Vector2d(h0_prime_conj[0], -h0_prime_conj[1]);
+
+ double w_prime = omega_prime(k);
+
+ // populate map to be used for later
+ WaveIndexConstant wave_const;
+ wave_const.h0_prime = h0_prime;
+ wave_const.h0_prime_conj = h0_prime_conj;
+ wave_const.w_prime = w_prime;
+ wave_const.base_horiz_pos = get_horiz_pos(i);
+ wave_const.k_vector = k;
+
+ m_waveIndexConstants[i] = wave_const;
+
+ // initialize m_current_h to be h0 for now
+ m_current_h.push_back(h0_prime);
+ m_displacements.push_back(Eigen::Vector2d(0.0, 0.0));
+ }
+}
+
+std::vector<Eigen::Vector2d> ocean::fast_fft(std::vector<Eigen::Vector2d> h)
+{
+ int N = h.size();
+ std::vector<Eigen::Vector2d> H = std::vector<Eigen::Vector2d>(N);
+
+ if (N == 1)
+ {
+ H[0] = h[0];
+ return H;
+ }
+ else
+ {
+ std::vector<Eigen::Vector2d> even = std::vector<Eigen::Vector2d>(N / 2);
+ std::vector<Eigen::Vector2d> odd = std::vector<Eigen::Vector2d>(N / 2);
+
+ for (int i = 0; i < N / 2; i++)
+ {
+ even[i] = h[2 * i];
+ odd[i] = h[2 * i + 1];
+ }
+
+ std::vector<Eigen::Vector2d> even_fft = fast_fft(even);
+ std::vector<Eigen::Vector2d> odd_fft = fast_fft(odd);
+
+ for (int i = 0; i < N / 2; i++)
+ {
+
+ Eigen::Vector2d k = m_waveIndexConstants[i].k_vector;
+ Eigen::Vector2d x = m_waveIndexConstants[i].base_horiz_pos;
+
+
+ double k_dot_xz = k.dot(x);
+
+ Eigen::Vector2d omega = complex_exp(k_dot_xz);
+ Eigen::Vector2d omega_times_odd = Eigen::Vector2d(omega[0] * odd_fft[i][0] - omega[1] * odd_fft[i][1], omega[0] * odd_fft[i][1] + omega[1] * odd_fft[i][0]);
+
+ H[i] = Eigen::Vector2d(even_fft[i][0] + omega_times_odd[0], even_fft[i][1] + omega_times_odd[1]);
+ H[i + N / 2] = Eigen::Vector2d(even_fft[i][0] - omega_times_odd[0], even_fft[i][1] - omega_times_odd[1]);
+ }
+
+ return H;
+ }
+}
+
+// fast fourier transform at time t
+void ocean::fft_prime(double t){
+
+// // NON FFT
+// for (int i=0; i<N; i++){
+// Eigen::Vector2d h_t_prime = h_prime_t(i, t); // vector(real, imag)
+
+// m_current_h[i] = h_t_prime;
+// }
+
+// return;
+
+ // FFT
+ std::vector<Eigen::Vector2d> h_tildas = std::vector<Eigen::Vector2d>();
+
+ // find each h_tilda at each index, to be used for next for loop
+ for (int i=0; i<N; i++){
+ Eigen::Vector2d h_t_prime = h_prime_t(i, t); // vector(real, imag)
+
+ h_tildas.emplace_back(h_t_prime);
+ }
+
+ // for each position in grid, sum up amplitudes dependng on that position
+ for (int i=0; i<N; i++){
+ Eigen::Vector2d x_vector = m_waveIndexConstants[i].base_horiz_pos;
+ m_current_h[i] = Eigen::Vector2d(0.0, 0.0);
+ m_displacements[i] = Eigen::Vector2d(0.0, 0.0);
+
+
+ for (int j = 0; j < N; j++){
+ Eigen::Vector2d k_vector = m_waveIndexConstants[j].k_vector;
+ Eigen::Vector2d h_tilda_prime = h_tildas[j]; // vector(real, imag)
+
+
+ // add x vector and k vector as imaginary numbers
+ double imag_xk_sum = x_vector.dot(k_vector);
+ Eigen::Vector2d exp = complex_exp(imag_xk_sum); // vector(real, imag)
+
+ double real_comp = h_tilda_prime[0]*exp[0] - h_tilda_prime[1]*exp[1];
+ double imag_comp = h_tilda_prime[0]*exp[1] + h_tilda_prime[1]*exp[0];
+
+ m_current_h[i] += Eigen::Vector2d(real_comp, imag_comp);
+
+ Eigen::Vector2d k_normalized = k_vector.normalized();
+
+ m_displacements[i] += k_normalized*imag_comp;
+
+ }
+ }
+
+}
+
+// time dependent calculation of h'(n,m,t)
+Eigen::Vector2d ocean::h_prime_t(int i, double t){
+ Eigen::Vector2d h0_prime = m_waveIndexConstants[i].h0_prime; // vector(real, imag)
+ Eigen::Vector2d h0_prime_conj = m_waveIndexConstants[i].h0_prime_conj; // vector(real, imag)
+ double w_prime = m_waveIndexConstants[i].w_prime;
+
+ Eigen::Vector2d pos_complex_exp = complex_exp(w_prime*t); // vector(real, imag)
+ Eigen::Vector2d neg_complex_exp = complex_exp(-w_prime*t); // vector(real, imag)
+
+ // now multiply our four vector(real, imag) out
+
+ double real_comp =
+ h0_prime[0]*pos_complex_exp[0]
+ - h0_prime[1]*pos_complex_exp[1]
+ + h0_prime_conj[0]*neg_complex_exp[0]
+ + h0_prime_conj[1]*neg_complex_exp[1];
+
+ double imag_comp =
+ h0_prime[0]*pos_complex_exp[1]
+ + h0_prime[1]*pos_complex_exp[0]
+ + h0_prime_conj[0]*neg_complex_exp[1]
+ - h0_prime_conj[1]*neg_complex_exp[0];
+
+
+
+ return Eigen::Vector2d(real_comp, imag_comp);
+}
+
+double ocean::omega_prime(Eigen::Vector2d k){
+ // calculate omega^4 first to prevent sqrts
+ double w = sqrt(gravity*k.norm());
+
+ return w;
+}
+
+Eigen::Vector2d ocean::h_0_prime(Eigen::Vector2d k){
+ double Ph_prime = phillips_prime(k);
+ std::pair<double,double> randoms = sample_complex_gaussian();
+ double random_r = randoms.first;
+ double random_i = randoms.second;
+
+ // seperate real and imag products
+ double coeff = 0.707106781187 * sqrt(Ph_prime);
+ double real_comp = coeff*random_r;
+ double imag_comp = coeff*random_i;
+
+ return Eigen::Vector2d(real_comp, imag_comp);
+}
+
+
+double ocean::phillips_prime(Eigen::Vector2d k){
+ double k_mag = k.norm();
+
+ k.normalize();
+ double dot_prod = k.dot(omega_wind);
+
+ double output = 0.0;
+ // l = 1
+ if (k_mag < .0001) return 0.0;
+
+ if (k_mag > 1.0){
+
+ output = A*exp(-(k_mag*k_mag))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag);
+ } else {
+ output = A*exp(-1.0/(k_mag*L*k_mag*L))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag);
+
+ }
+
+
+
+ return output;
+}
+
+Eigen::Vector2d ocean::get_k_vector(int n_prime, int m_prime){
+ double n_ = (double)n_prime;
+ double m_ = (double)m_prime;
+ double N_ = (double)num_rows;
+ double M_ = (double)num_cols;
+
+ double k_x = (2.0*M_PI*n_ - M_PI*N_)/Lx;
+ double k_z = (2.0*M_PI*m_ - M_PI*M_)/Lz;
+
+ return Eigen::Vector2d(k_x, k_z);
+}
+
+Eigen::Vector2d ocean::get_horiz_pos(int i){
+ Eigen::Vector2i m_n = index_1d_to_2d(i);
+ double n_prime = (double)m_n[0];
+ double m_prime = (double)m_n[1];
+ double N_ = (double)num_rows;
+ double M_ = (double)num_cols;
+
+
+ double x = (n_prime-.5*N_)*Lx / N_;
+ double z = (m_prime-.5*M_)*Lz / M_;
+
+
+
+ return Eigen::Vector2d(x, z);
+}
+
+
+Eigen::Vector2i ocean::index_1d_to_2d(int i){
+ int row = i/num_rows; // n'
+ int col = i%num_rows; // m'
+
+ return Eigen::Vector2i(row, col);
+
+}
+
+std::pair<double,double> ocean::sample_complex_gaussian(){
+ double uniform_1 = (double)rand() / (RAND_MAX);
+ double uniform_2 = (double)rand() / (RAND_MAX);
+
+ // set a lower bound on zero to avoid undefined log(0)
+ if (uniform_1 == 0)
+ {
+ uniform_1 = 1e-10;
+ }
+ if (uniform_2 == 0)
+ {
+ uniform_2 = 1e-10;
+ }
+
+ // real and imaginary parts of the complex number
+ double real = sqrt(-2 * log(uniform_1)) * cos(2 * M_PI * uniform_2);
+ double imag = sqrt(-2 * log(uniform_1)) * sin(2 * M_PI * uniform_2);
+
+ return std::make_pair(real, imag);
+}
+
+Eigen::Vector2d ocean::complex_exp(double exponent){
+ double real = cos(exponent);
+ double imag = sin(exponent);
+
+ return Eigen::Vector2d(real, imag);
+}
+
+std::vector<Eigen::Vector3f> ocean::get_vertices()
+{
+ std::vector<Eigen::Vector3f> vertices = std::vector<Eigen::Vector3f>();
+ for (int i = 0; i < N; i++){
+ Eigen::Vector2d horiz_pos = spacing*m_waveIndexConstants[i].base_horiz_pos;
+ Eigen::Vector2d amplitude = m_current_h[i];
+
+
+ // calculate displacement
+ Eigen::Vector2d disp = lambda*m_displacements[i];
+
+
+ // for final vertex position, use the real number component of amplitude vector
+ vertices.push_back(Eigen::Vector3f(horiz_pos[0] + disp[0], amplitude[0], horiz_pos[1] + disp[1]));
+ }
+ return vertices;
+}
+
+std::vector<Eigen::Vector3i> ocean::get_faces()
+{
+ // connect the vertices into faces
+ std::vector<Eigen::Vector3i> faces = std::vector<Eigen::Vector3i>();
+ for (int i = 0; i < N; i++)
+ {
+ int x = i / num_rows;
+ int z = i % num_rows;
+
+ // connect the vertices into faces
+ if (x < num_rows - 1 && z < num_cols - 1)
+ {
+ int i1 = i;
+ int i2 = i + 1;
+ int i3 = i + num_rows;
+ int i4 = i + num_rows + 1;
+
+// faces.emplace_back(i2, i1, i3);
+// faces.emplace_back(i2, i3, i4);
+ faces.emplace_back(i1, i2, i3);
+ faces.emplace_back(i3, i2, i4);
+ }
+ }
+ return faces;
+}
diff --git a/engine-ocean/Game/Ocean/ocean.h b/engine-ocean/Game/Ocean/ocean.h
new file mode 100644
index 0000000..b2abe87
--- /dev/null
+++ b/engine-ocean/Game/Ocean/ocean.h
@@ -0,0 +1,89 @@
+#ifndef ocean_H
+#define ocean_H
+
+#include <map>
+#include <vector>
+#include <utility>
+#include <Eigen/Dense>
+
+// for every 1d index up to length*width
+struct WaveIndexConstant{
+ Eigen::Vector2d h0_prime = Eigen::Vector2d(0.f, 0.f);
+ Eigen::Vector2d h0_prime_conj = Eigen::Vector2d(0.f, 0.f);
+
+ double w_prime = 0.0;
+
+
+ Eigen::Vector2d base_horiz_pos = Eigen::Vector2d(0.f, 0.f); // static horiz pos with no displacement
+ Eigen::Vector2d k_vector = Eigen::Vector2d(0.f, 0.f); // static horiz pos with no displacement
+
+
+
+};
+
+class ocean
+{
+public:
+ ocean();
+ void updateVertexAmplitudes(double t);
+ std::vector<Eigen::Vector3f> get_vertices();
+ std::vector<Eigen::Vector3i> get_faces();
+ void fft_prime(double t);
+
+
+
+
+
+private:
+
+ Eigen::Vector2i index_1d_to_2d(int i);
+ Eigen::Vector2d get_k_vector(int n_prime, int m_prime);
+ double phillips_prime(Eigen::Vector2d k);
+ Eigen::Vector2d h_0_prime(Eigen::Vector2d k);
+ double omega_prime(Eigen::Vector2d k);
+ void init_wave_index_constants();
+ Eigen::Vector2d complex_exp(double exponent);
+ Eigen::Vector2d h_prime_t(int i, double t);
+ Eigen::Vector2d get_horiz_pos(int i);
+ std::pair<double, double> sample_complex_gaussian();
+ std::vector<Eigen::Vector2d> fast_fft(std::vector<Eigen::Vector2d> h);
+
+
+
+
+
+
+
+
+
+ std::map<int, WaveIndexConstant> m_waveIndexConstants; // stores constants that only need to be calculate once for each grid constant
+
+
+
+ const double Lx = 10.0;
+ const double Lz = 10.0;
+
+ const int num_rows = 8;
+ const int num_cols = 8;
+
+ const int N = num_rows*num_cols; // total number of grid points
+ const double lambda = .40; // how much displacement matters
+ const double spacing = 35.0; // spacing between grid points
+
+ const double A = 1.0; // numeric constant for the Phillips spectrum
+ const double V = 5.5; // wind speed
+ const double gravity = 9.81;
+ const double L = V*V/gravity;
+ const Eigen::Vector2d omega_wind = Eigen::Vector2d(1.0, 0.0); // wind direction, used in Phillips equation
+
+ std::vector<Eigen::Vector2d> m_current_h; // current height fields for each K
+ std::vector<Eigen::Vector2d> m_displacements; // current displacement vector for each K
+
+
+
+ const double D = 1.0; // Depth below mean water level (for dispersion relation)
+
+
+};
+
+#endif // ocean_H
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
diff --git a/engine-ocean/Game/TypeMap.h b/engine-ocean/Game/TypeMap.h
new file mode 100644
index 0000000..add3367
--- /dev/null
+++ b/engine-ocean/Game/TypeMap.h
@@ -0,0 +1,54 @@
+#ifndef TYPEMAP_H
+#define TYPEMAP_H
+#include <unordered_map>
+#include <atomic>
+
+template <class ValueType>
+class TypeMap {
+ typedef std::unordered_map<int, ValueType> InternalMap;
+
+public:
+ typedef typename InternalMap::iterator iterator;
+ typedef typename InternalMap::const_iterator const_iterator;
+ typedef typename InternalMap::value_type value_type;
+
+ const_iterator begin() const { return m_map.begin(); }
+ const_iterator end() const { return m_map.end(); }
+
+ iterator begin() { return m_map.begin(); }
+ iterator end() { return m_map.end(); }
+
+ // finds the value associated with type "Key" in the typemap
+ template <class Key>
+ iterator find() { return m_map.find(getTypeId<Key>()); }
+
+ template <class Key>
+ const_iterator find() const { return m_map.find(getTypeId<Key>()); }
+
+ template <class Key>
+ bool contains() { return m_map.count(getTypeId<Key>()); }
+
+ // associates a value with the type "Key"
+ template <class Key>
+ void put(ValueType &&value){
+ m_map[getTypeId<Key>()] = std::forward<ValueType>(value);
+ }
+
+ template <class Key>
+ void remove() { m_map.erase(getTypeId<Key>()); }
+
+private:
+ template <class Key>
+ inline static int getTypeId(){
+ static const int id = LastTypeId++;
+ return id;
+ }
+
+ static std::atomic_int LastTypeId;
+ InternalMap m_map;
+};
+
+template <class ValueType>
+std::atomic_int TypeMap<ValueType>::LastTypeId(0);
+
+#endif // TYPEMAP_H
diff --git a/engine-ocean/Game/menuscreen.h b/engine-ocean/Game/menuscreen.h
new file mode 100644
index 0000000..77ecd2c
--- /dev/null
+++ b/engine-ocean/Game/menuscreen.h
@@ -0,0 +1,27 @@
+#ifndef MENUSCREEN_H
+#define MENUSCREEN_H
+#include "Game/GameWorld.h"
+#include "screen.h"
+#include <map>
+
+
+class MenuScreen: public Screen
+{
+public:
+ MenuScreen(std::map<int, Input>& input_map);
+ ~MenuScreen();
+
+
+ void update(double deltaTime) override;
+ void draw() override;
+ void keyEvent(int key, int action) override;
+ void mousePosEvent(double xpos, double ypos) override;
+ void mouseButtonEvent(int button, int action) override;
+ void scrollEvent(double distance) override;
+ void windowResizeEvent(int width, int height) override;
+ void framebufferResizeEvent(int width, int height) override;
+private:
+ std::map<int, Input>& m_input_map;
+};
+
+#endif // MENUSCREEN_H
diff --git a/engine-ocean/Game/screen.cpp b/engine-ocean/Game/screen.cpp
new file mode 100644
index 0000000..525e009
--- /dev/null
+++ b/engine-ocean/Game/screen.cpp
@@ -0,0 +1,6 @@
+#include "screen.h"
+
+Screen::Screen()
+{
+
+}
diff --git a/engine-ocean/Game/screen.h b/engine-ocean/Game/screen.h
new file mode 100644
index 0000000..0a4ebb1
--- /dev/null
+++ b/engine-ocean/Game/screen.h
@@ -0,0 +1,20 @@
+#ifndef SCREEN_H
+#define SCREEN_H
+
+
+class Screen
+{
+public:
+ Screen();
+
+ virtual void update(double deltaTime) = 0;
+ virtual void draw() = 0;
+ virtual void keyEvent(int key, int action) = 0;
+ virtual void mousePosEvent(double xpos, double ypos) = 0;
+ virtual void mouseButtonEvent(int button, int action) = 0;
+ virtual void scrollEvent(double distance) = 0;
+ virtual void windowResizeEvent(int width, int height) = 0;
+ virtual void framebufferResizeEvent(int width, int height) = 0;
+};
+
+#endif // SCREEN_H