diff --git a/CMakeLists.txt b/CMakeLists.txt
index a53b860..c36571b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -86,8 +86,8 @@ set(EXECUTABLE_SOURCES
${EXECUTABLE_SOURCE_DIR}/render-passes.hpp
${EXECUTABLE_SOURCE_DIR}/settings.cpp
${EXECUTABLE_SOURCE_DIR}/settings.hpp
- ${EXECUTABLE_SOURCE_DIR}/terrain.cpp
- ${EXECUTABLE_SOURCE_DIR}/terrain.hpp
+ ${EXECUTABLE_SOURCE_DIR}/game/terrain.cpp
+ ${EXECUTABLE_SOURCE_DIR}/game/terrain.hpp
${EXECUTABLE_SOURCE_DIR}/controls.hpp
${EXECUTABLE_SOURCE_DIR}/input.cpp
${EXECUTABLE_SOURCE_DIR}/input.hpp
@@ -109,10 +109,14 @@ set(EXECUTABLE_SOURCES
${EXECUTABLE_SOURCE_DIR}/ui/tween.hpp
${EXECUTABLE_SOURCE_DIR}/ui/tween.cpp
${EXECUTABLE_SOURCE_DIR}/render-passes.cpp
- ${EXECUTABLE_SOURCE_DIR}/ant.hpp
- ${EXECUTABLE_SOURCE_DIR}/ant.cpp
- ${EXECUTABLE_SOURCE_DIR}/nest.hpp
- ${EXECUTABLE_SOURCE_DIR}/nest.cpp
+ ${EXECUTABLE_SOURCE_DIR}/game/ant.hpp
+ ${EXECUTABLE_SOURCE_DIR}/game/ant.cpp
+ ${EXECUTABLE_SOURCE_DIR}/game/agent.hpp
+ ${EXECUTABLE_SOURCE_DIR}/game/agent.cpp
+ ${EXECUTABLE_SOURCE_DIR}/game/nest.hpp
+ ${EXECUTABLE_SOURCE_DIR}/game/nest.cpp
+ ${EXECUTABLE_SOURCE_DIR}/game/navmesh.hpp
+ ${EXECUTABLE_SOURCE_DIR}/game/navmesh.cpp
${EXECUTABLE_SOURCE_DIR}/debug.hpp
${EXECUTABLE_SOURCE_DIR}/debug.cpp
${EXECUTABLE_SOURCE_DIR}/camera-controller.hpp
diff --git a/data b/data
index 3f2b504..37456bb 160000
--- a/data
+++ b/data
@@ -1 +1 @@
-Subproject commit 3f2b504970e90fd476a682f4754d276bf162729c
+Subproject commit 37456bb0933b6eed8444f2d6f1ce0819bac00b15
diff --git a/lib/emergent b/lib/emergent
index 94f7940..341a6cd 160000
--- a/lib/emergent
+++ b/lib/emergent
@@ -1 +1 @@
-Subproject commit 94f7940aa2ab6375c7672354f3a731a86542f51c
+Subproject commit 341a6cd0b704379cd38c9382f9ea0ef4b33a382a
diff --git a/src/ant.cpp b/src/ant.cpp
deleted file mode 100644
index 3929efd..0000000
--- a/src/ant.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2017 Christopher J. Howard
- *
- * This file is part of Antkeeper Source Code.
- *
- * Antkeeper Source Code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Antkeeper Source Code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Antkeeper Source Code. If not, see .
- */
-
-#include "ant.hpp"
-
diff --git a/src/ant.hpp b/src/ant.hpp
deleted file mode 100644
index 11ca645..0000000
--- a/src/ant.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2017 Christopher J. Howard
- *
- * This file is part of Antkeeper Source Code.
- *
- * Antkeeper Source Code is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Antkeeper Source Code is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Antkeeper Source Code. If not, see .
- */
-
-#ifndef ANT_HPP
-#define ANT_HPP
-
-#include
-
-#include
-using namespace Emergent;
-
-class Gait;
-
-class Ant
-{
-public:
- /**
- * Named constants corresponding to leg indices.
- *
- * \_/
- * L1 --| |-- R1
- * L2 --| |-- R2
- * L3 --|_|-- R3
- */
- enum class LegIndex
- {
- L1,
- L2,
- L3,
- R1,
- R2,
- R3
- };
-
-private:
- Transform transform;
- ModelInstance modelInstance;
- Pose* skeletonPose;
-};
-
-class Colony
-{
-public:
- Ant* spawn();
-
- const Model* getAntModel() const;
- Model* getAntModel();
-
- const Skeleton* getAntSkeleton() const;
- Skeleton* getSkeleton();
-
-private:
- // Rendering
- Model* antModel;
- Skeleton* antSkeleton;
-
- // Locomotion
- float walkSpeed;
- float turnSpeed;
- Gait* tripodGait;
- Gait* rippleGait;
- Gait* slowWaveGait;
-
-
- std::vector ants;
-};
-
-#endif // ANT_HPP
\ No newline at end of file
diff --git a/src/application.cpp b/src/application.cpp
index aaf4614..65e7cfd 100644
--- a/src/application.cpp
+++ b/src/application.cpp
@@ -340,6 +340,11 @@ Application::Application(int argc, char* argv[]):
gameControlProfile->registerControl("camera-zoom-out", &cameraZoomOut);
gameControlProfile->registerControl("camera-toggle-nest-view", &cameraToggleNestView);
gameControlProfile->registerControl("camera-toggle-overhead-view", &cameraToggleOverheadView);
+ gameControlProfile->registerControl("walk-forward", &walkForward);
+ gameControlProfile->registerControl("walk-back", &walkBack);
+ gameControlProfile->registerControl("turn-left", &turnLeft);
+ gameControlProfile->registerControl("turn-right", &turnRight);
+
cameraMoveForward.bindKey(keyboard, SDL_SCANCODE_W);
cameraMoveBack.bindKey(keyboard, SDL_SCANCODE_S);
cameraMoveLeft.bindKey(keyboard, SDL_SCANCODE_A);
@@ -350,6 +355,10 @@ Application::Application(int argc, char* argv[]):
cameraZoomOut.bindKey(keyboard, SDL_SCANCODE_MINUS);
cameraToggleOverheadView.bindKey(keyboard, SDL_SCANCODE_R);
cameraToggleNestView.bindKey(keyboard, SDL_SCANCODE_F);
+ walkForward.bindKey(keyboard, SDL_SCANCODE_UP);
+ walkBack.bindKey(keyboard, SDL_SCANCODE_DOWN);
+ turnLeft.bindKey(keyboard, SDL_SCANCODE_LEFT);
+ turnRight.bindKey(keyboard, SDL_SCANCODE_RIGHT);
cameraOverheadView = true;
cameraNestView = false;
@@ -364,6 +373,7 @@ Application::Application(int argc, char* argv[]):
SDL_GL_SwapWindow(window);
// Setup loaders
+ textureLoader = new TextureLoader();
materialLoader = new MaterialLoader();
modelLoader = new ModelLoader();
modelLoader->setMaterialLoader(materialLoader);
diff --git a/src/application.hpp b/src/application.hpp
index c55be67..c15580e 100644
--- a/src/application.hpp
+++ b/src/application.hpp
@@ -24,7 +24,7 @@
using namespace Emergent;
#include "mesh.hpp"
-#include "terrain.hpp"
+#include "game/terrain.hpp"
#include "input.hpp"
#include "controls.hpp"
#include "settings.hpp"
@@ -102,7 +102,9 @@ public:
Camera camera;
Scene scene;
BillboardBatch particleBatch;
+ Arcball arcball;
+ TextureLoader* textureLoader;
MaterialLoader* materialLoader;
ModelLoader* modelLoader;
@@ -158,6 +160,11 @@ public:
bool cameraOverheadView;
bool cameraNestView;
+ Control walkForward;
+ Control walkBack;
+ Control turnLeft;
+ Control turnRight;
+
// Misc
Timer frameTimer;
@@ -167,8 +174,8 @@ public:
float fontSizePT;
float fontSizePX;
Font* menuFont;
- Texture splashTexture;
- Texture titleTexture;
+ Texture* splashTexture;
+ Texture* titleTexture;
Vector4 selectedColor;
Vector4 deselectedColor;
UIContainer* uiRootElement;
diff --git a/src/game/agent.cpp b/src/game/agent.cpp
new file mode 100644
index 0000000..4f7345f
--- /dev/null
+++ b/src/game/agent.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2017 Christopher J. Howard
+ *
+ * This file is part of Antkeeper Source Code.
+ *
+ * Antkeeper Source Code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper Source Code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper Source Code. If not, see .
+ */
+
+#include "agent.hpp"
+
+Agent::Agent():
+ navmeshTriangle(nullptr),
+ barycentricPosition(0.0f),
+ position(0.0f),
+ forward(0, 0, -1),
+ up(0, 1, 0),
+ right(1, 0, 0),
+ rotation(1, 0, 0, 0),
+ wanderDirection(0, 0, -1)
+{}
+
+void Agent::applyForce(const Vector3& force)
+{
+ acceleration += force;
+}
+
+void Agent::updateVelocity()
+{
+ // Limit acceleration
+ acceleration = limit(acceleration / mass, maxAcceleration);
+
+ // Add acceleration to velocity and limit
+ velocity = limit(velocity + acceleration, maxSpeed);
+
+ // Reset acceleration to zero
+ acceleration = Vector3(0.0f);
+}
+
+Vector3 Agent::wander(float dt)
+{
+ // Calculate center of wander circle
+ Vector3 wanderCircleCenter = forward * wanderCircleDistance;
+
+ // Calculate wander force
+ Vector3 force = wanderCircleCenter + wanderDirection * wanderCircleRadius;
+
+ // Rotate wander direction by a random displacement angle
+ float displacement = frand(-wanderRate * 0.5f, wanderRate * 0.5f);
+ wanderDirection = glm::normalize(glm::angleAxis(displacement, up) * wanderDirection);
+
+ return force;
+}
+
+Vector3 Agent::seek(const Vector3& target) const
+{
+ Vector3 desiredVelocity = glm::normalize(position - target) * maxSpeed;
+ return desiredVelocity - velocity;
+}
+
+Vector3 Agent::flee(const Vector3& target) const
+{
+ Vector3 desiredVelocity = glm::normalize(target - position) * maxSpeed;
+ return desiredVelocity - velocity;
+}
+
+Vector3 Agent::containment(const Vector3& probe) const
+{
+ std::vector traversal;
+ Navmesh::traverse(navmeshTriangle, barycentricPosition, probe, &traversal);
+
+ if (traversal.empty())
+ {
+ return Vector3(0.0f);
+ }
+
+ const Navmesh::Step& step = traversal.back();
+
+ // If not on edge or on connected edge
+ if (step.edge == nullptr || step.edge->symmetric != nullptr)
+ {
+ return Vector3(0.0f);
+ }
+
+ // Calculate edge normal
+ const Vector3& a = step.edge->vertex->position;
+ const Vector3& b = step.edge->next->vertex->position;
+ Vector3 ab = glm::normalize(b - a);
+ Vector3 edgeNormal = glm::cross(up, ab);
+
+ // Calculate reflection vector of forward vector and edge normal
+ Vector3 force = glm::reflect(forward, edgeNormal);
+
+ return force;
+}
+
+void Agent::setPosition(Navmesh::Triangle* triangle, const Vector3& position)
+{
+ // Update navmesh triangle and position
+ navmeshTriangle = triangle;
+ barycentricPosition = position;
+
+ // Convert navmesh-space barycentric position to world-space cartesian position
+ const Vector3& a = triangle->edge->vertex->position;
+ const Vector3& b = triangle->edge->next->vertex->position;
+ const Vector3& c = triangle->edge->previous->vertex->position;
+ this->position = cartesian(position, a, b, c);
+}
+
+void Agent::setOrientation(const Vector3& newForward, const Vector3& newUp)
+{
+ // Calculate alignment quaternion
+ Quaternion alignment = glm::rotation(up, newUp);
+
+ // Rebuild vector basis
+ forward = newForward;
+ right = glm::normalize(glm::cross(newUp, forward));
+ up = glm::cross(forward, right);
+
+ // Calculate rotation quaternion from vector basis
+ rotation = glm::normalize(glm::quat_cast(Matrix3(right, up, forward)));
+
+ // Align wander direction
+ wanderDirection = glm::normalize(project_on_plane(alignment * wanderDirection, Vector3(0.0f), up));
+}
+
+void Agent::setWanderCircleDistance(float distance)
+{
+ wanderCircleDistance = distance;
+}
+
+void Agent::setWanderCircleRadius(float radius)
+{
+ wanderCircleRadius = radius;
+}
+
+void Agent::setWanderRate(float angle)
+{
+ wanderRate = angle;
+}
+
+/** EXAMPLE USAGE
+Vector3 wanderForce = wander(dt) * wanderWeight;
+Vector3 fleeForce = flee(mouse) * fleeWeight;
+Vector3 steerForce = wanderForce + fleeForce;
+steer(steerForce);
+**/
diff --git a/src/game/agent.hpp b/src/game/agent.hpp
new file mode 100644
index 0000000..0e3bf6f
--- /dev/null
+++ b/src/game/agent.hpp
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2017 Christopher J. Howard
+ *
+ * This file is part of Antkeeper Source Code.
+ *
+ * Antkeeper Source Code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper Source Code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper Source Code. If not, see .
+ */
+
+#ifndef AGENT_HPP
+#define AGENT_HPP
+
+#include "navmesh.hpp"
+
+#include
+
+#include
+using namespace Emergent;
+
+class Obstacle;
+
+
+/*************88
+
+Ant is an agent.
+
+Ant combines steering behaviors with different weights.
+
+I.E.
+
+seek pheromones * 0.5
+separation * 0.1
+alignment * 0.1
+cohesion * 0.1
+followWall * 0.2
+
+*/
+
+/**
+ * An agent which navigates on a navmesh.
+ */
+class Agent
+{
+public:
+ Agent();
+
+ /**
+ * Adds a force to the agent's acceleration vector.
+ *
+ * @param force Acceleration force
+ */
+ void applyForce(const Vector3& force);
+
+ /**
+ * Calculates velocity based on current acceleration vector, then resets acceleration to zero.
+ */
+ void updateVelocity();
+
+ /**
+ * Calculates steering force for the wander behavior.
+ */
+ Vector3 wander(float dt);
+
+ /**
+ * Calculates steering force for the seek behavior.
+ */
+ Vector3 seek(const Vector3& target) const;
+
+ /**
+ * Calculates steering force for the flee behavior.
+ */
+ Vector3 flee(const Vector3& target) const;
+
+ Vector3 containment(const Vector3& probe) const;
+
+ void setMaxSpeed(float speed);
+ void setMaxAcceleration(float acceleration);
+ void setMass(float mass);
+ void setWanderCircleDistance(float distance);
+ void setWanderCircleRadius(float radius);
+ void setWanderRate(float angle);
+
+ /**
+ * Sets the position of the agent on a navmesh.
+ *
+ * @param triangle Navmesh triangle on which the agent resides
+ * @param position Barycentric position on the specified triangle
+ */
+ void setPosition(Navmesh::Triangle* triangle, const Vector3& position);
+
+ /**
+ * Sets the orientation of the agent. This effectively updates the agent's vector basis and rotation quaternion.
+ *
+ * @param forward Normalized forward vector
+ * @param up Normalized up vector
+ */
+ void setOrientation(const Vector3& newForward, const Vector3& newUp);
+
+ /*
+ Vector3 followWall();
+ // or
+ Vector3 followEdge();
+ Vector3 avoidObstacle(const Obstacle* obstacle);
+ Vector3 separation(const std::vector* neighbors);
+ Vector3 alignment(const std::vector* neighbors);
+ Vector3 cohesion(const std::vector* neighbors);
+ */
+
+ const Navmesh::Triangle* getNavmeshTriangle() const;
+ Navmesh::Triangle* getNavmeshTriangle();
+ const Vector3& getBarycentricPosition() const;
+ const Vector3& getPosition() const;
+ const Vector3& getForward() const;
+ const Vector3& getUp() const;
+ const Vector3& getRight() const;
+ const Quaternion& getRotation() const;
+
+private:
+ Navmesh::Triangle* navmeshTriangle;
+ Vector3 barycentricPosition;
+ Vector3 position;
+ Vector3 forward;
+ Vector3 up;
+ Vector3 right;
+ Quaternion rotation;
+
+ // Limits
+ float maxSpeed;
+ float maxAcceleration;
+
+ // Steering forces
+ float mass;
+ Vector3 acceleration;
+ Vector3 velocity;
+
+ // Wander variables
+ float wanderCircleDistance;
+ float wanderCircleRadius;
+ float wanderRate;
+ Vector3 wanderDirection;
+};
+
+inline const Navmesh::Triangle* Agent::getNavmeshTriangle() const
+{
+ return navmeshTriangle;
+}
+
+inline Navmesh::Triangle* Agent::getNavmeshTriangle()
+{
+ return navmeshTriangle;
+}
+
+inline const Vector3& Agent::getBarycentricPosition() const
+{
+ return barycentricPosition;
+}
+
+inline const Vector3& Agent::getPosition() const
+{
+ return position;
+}
+
+inline const Vector3& Agent::getForward() const
+{
+ return forward;
+}
+
+inline const Vector3& Agent::getUp() const
+{
+ return up;
+}
+
+inline const Vector3& Agent::getRight() const
+{
+ return right;
+}
+
+inline const Quaternion& Agent::getRotation() const
+{
+ return rotation;
+}
+
+#endif // AGENT_HPP
\ No newline at end of file
diff --git a/src/game/ant.cpp b/src/game/ant.cpp
new file mode 100644
index 0000000..eda7f7b
--- /dev/null
+++ b/src/game/ant.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 Christopher J. Howard
+ *
+ * This file is part of Antkeeper Source Code.
+ *
+ * Antkeeper Source Code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper Source Code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper Source Code. If not, see .
+ */
+
+#include "ant.hpp"
+
+Ant::Ant(Colony* colony):
+ colony(colony),
+ state(Ant::State::IDLE),
+ transform(Transform::getIdentity()),
+ skeletonPose(nullptr)
+{
+ modelInstance.setModel(colony->getAntModel());
+}
+
+void Ant::move(const Vector3& velocity)
+{
+ std::vector traversal;
+ Navmesh::traverse(getNavmeshTriangle(), getBarycentricPosition(), velocity, &traversal);
+
+ if (!traversal.empty())
+ {
+ const Navmesh::Step& step = traversal.back();
+
+ if (step.start != step.end)
+ {
+ if (step.triangle != getNavmeshTriangle())
+ {
+ Quaternion alignment = glm::rotation(getNavmeshTriangle()->normal, step.triangle->normal);
+ Vector3 newForward = glm::normalize(project_on_plane(alignment * getForward(), Vector3(0.0f), step.triangle->normal));
+
+ setOrientation(newForward, step.triangle->normal);
+ }
+ }
+
+ setPosition(step.triangle, step.end);
+ }
+}
+
+void Ant::turn(float angle)
+{
+ // Rotate forward vector
+ Vector3 newForward = glm::normalize(glm::angleAxis(angle, getUp()) * getForward());
+ setOrientation(newForward, getUp());
+}
+
+void Ant::update(float dt)
+{
+ if (state == Ant::State::WANDER)
+ {
+ setWanderCircleDistance(3.0f);
+ setWanderCircleRadius(0.25f);
+ setWanderRate(glm::radians(90.0f));
+
+ // Calculate wander force
+ Vector3 wanderForce = wander(dt);
+
+ // Setup containment probes
+ float probeLateralOffset = 0.35f;
+ Vector3 forwardProbe = getForward() * 0.5f;
+ Vector3 leftProbe = getForward() * 0.1f - getRight() * probeLateralOffset;
+ Vector3 rightProbe = getForward() * 0.1f + getRight() * probeLateralOffset;
+
+ // Calculate containment force
+ Vector3 containmentForce = containment(forwardProbe)
+ + containment(leftProbe)
+ + containment(rightProbe);
+
+ // Calculate velocity
+ Vector3 velocity(0.0f);
+ velocity += wanderForce;
+ velocity += containmentForce;
+ velocity = limit(velocity, 0.025f);
+
+ setOrientation(glm::normalize(velocity), getUp());
+
+ // Move ant
+ move(velocity);
+ }
+
+ // Update transform
+ transform.translation = getPosition();
+ transform.rotation = getRotation();
+
+ // Update model instance
+ modelInstance.setTransform(transform);
+}
+
+void Ant::setState(Ant::State state)
+{
+ this->state = state;
+}
+
+Colony::Colony():
+ antModel(nullptr)
+{}
+
+Ant* Colony::spawn(Navmesh* navmesh, Navmesh::Triangle* triangle, const Vector3& position)
+{
+ // Allocate ant
+ Ant* ant = new Ant(this);
+
+ // Position it on the navmesh
+ ant->setPosition(triangle, position);
+
+ // Add ant to the colony
+ ants.push_back(ant);
+
+ return ant;
+}
+
+void Colony::update(float dt)
+{
+ for (Ant* ant: ants)
+ {
+ ant->update(dt);
+ }
+}
+
+void Colony::setAntModel(Model* model)
+{
+ this->antModel = model;
+}
diff --git a/src/game/ant.hpp b/src/game/ant.hpp
new file mode 100644
index 0000000..eef0c47
--- /dev/null
+++ b/src/game/ant.hpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2017 Christopher J. Howard
+ *
+ * This file is part of Antkeeper Source Code.
+ *
+ * Antkeeper Source Code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper Source Code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper Source Code. If not, see .
+ */
+
+#ifndef ANT_HPP
+#define ANT_HPP
+
+#include
+#include "navmesh.hpp"
+#include "agent.hpp"
+
+#include
+using namespace Emergent;
+
+class Colony;
+class Gait;
+
+/**
+ * An individual ant which belongs to a colony.
+ */
+class Ant: public Agent
+{
+public:
+ /**
+ * Named constants corresponding to leg indices.
+ *
+ * \_/
+ * L1 --| |-- R1
+ * L2 --| |-- R2
+ * L3 --|_|-- R3
+ */
+ enum class LegIndex
+ {
+ L1,
+ L2,
+ L3,
+ R1,
+ R2,
+ R3
+ };
+
+ enum class State
+ {
+ IDLE,
+ WANDER
+ };
+
+ /**
+ * Creates an instance of Ant.
+ */
+ Ant(Colony* colony);
+
+ void move(const Vector3& velocity);
+
+ void turn(float angle);
+
+ void update(float dt);
+
+ void setState(Ant::State state);
+
+ const Colony* getColony() const;
+ Colony* getColony();
+ const Transform& getTransform() const;
+
+ const ModelInstance* getModelInstance() const;
+ ModelInstance* getModelInstance();
+
+private:
+ /**
+ * Calculates the surface normal averaged between the surface normals at each of the ant's grounded feet.
+ */
+ Vector3 calculateAverageSurfaceNormal() const;
+
+ void updateTransform();
+
+ Colony* colony;
+ Ant::State state;
+
+ Transform transform;
+ ModelInstance modelInstance;
+ Pose* skeletonPose;
+};
+
+inline const Colony* Ant::getColony() const
+{
+ return colony;
+}
+
+inline Colony* Ant::getColony()
+{
+ return colony;
+}
+
+inline const Transform& Ant::getTransform() const
+{
+ return transform;
+}
+
+inline const ModelInstance* Ant::getModelInstance() const
+{
+ return &modelInstance;
+}
+
+inline ModelInstance* Ant::getModelInstance()
+{
+ return &modelInstance;
+}
+
+/**
+ * A colony of ants.
+ */
+class Colony
+{
+public:
+ Colony();
+
+ Ant* spawn(Navmesh* navmesh, Navmesh::Triangle* triangle, const Vector3& position);
+
+ void update(float dt);
+
+ void setAntModel(Model* model);
+ const Model* getAntModel() const;
+ Model* getAntModel();
+
+private:
+ // Rendering
+ Model* antModel;
+
+ // Locomotion
+ float walkSpeed;
+ float turnSpeed;
+ Gait* tripodGait;
+ Gait* rippleGait;
+ Gait* slowWaveGait;
+
+
+ std::vector ants;
+};
+
+inline const Model* Colony::getAntModel() const
+{
+ return antModel;
+}
+
+inline Model* Colony::getAntModel()
+{
+ return antModel;
+}
+
+#endif // ANT_HPP
\ No newline at end of file
diff --git a/src/game/navmesh.cpp b/src/game/navmesh.cpp
new file mode 100644
index 0000000..c319bb8
--- /dev/null
+++ b/src/game/navmesh.cpp
@@ -0,0 +1,546 @@
+/*
+ * Copyright (C) 2017 Christopher J. Howard
+ *
+ * This file is part of Antkeeper Source Code.
+ *
+ * Antkeeper Source Code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Antkeeper Source Code is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Antkeeper Source Code. If not, see .
+ */
+
+#include "navmesh.hpp"
+#include
+#include