@ -1,12 +0,0 @@ | |||||
[submodule "emergent"] | |||||
path = lib/emergent | |||||
url = https://github.com/cjhoward/emergent.git | |||||
[submodule "lib/SDL2"] | |||||
path = lib/SDL2 | |||||
url = https://github.com/cjhoward/SDL2.git | |||||
[submodule "data"] | |||||
path = data | |||||
url = https://gitlab.com/cjhoward/antkeeper-data.git | |||||
[submodule "lib/dirent"] | |||||
path = lib/dirent | |||||
url = https://github.com/cjhoward/dirent.git |
@ -1,64 +1,18 @@ | |||||
# Antkeeper | |||||
Antkeeper is an ant colony simulation game. This repository contains all of the source code to Antkeeper. The game data, however, is proprietary and resides in a closed-source Git submodule. | |||||
## Download | |||||
Use Git to download the `antkeeper` repository and its submodules: | |||||
git clone --recursive https://github.com/cjhoward/antkeeper.git antkeeper | |||||
## Configuration & Building | |||||
CMake is required to configure and build the application. Depending on the target build platform, CMake should be invoked from one of the following directories: | |||||
build/linux32 // 32-bit GNU/Linux application | |||||
build/linux64 // 64-bit GNU/Linux application | |||||
build/win32 // 32-bit Windows application | |||||
build/win64 // 64-bit Windows application | |||||
The following arguments may be passed to CMake during configuration: | |||||
-DCMAKE_BUILD_TYPE // [Debug, Release] | |||||
-DLANGUAGE // [en-us, zh-cn] | |||||
-DSTANDALONE // [OFF, ON] | |||||
### GNU/Linux | |||||
Building on GNU/Linux requires CMake, GCC, G++, and GNU Make. Open a terminal in the project root directory and run the following commands: | |||||
cd build/linux64 | |||||
cmake ../.. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=... | |||||
cmake --build . | |||||
### Windows | |||||
Building on Windows requires CMake and Visual Studio 2017. Additionally, [NSIS](http://nsis.sourceforge.net/) is required if you want to build a distributable installer program. In order to correctly build for your target architecture, you must use the `x86 Native Tools Command Prompt` or the `x64 Native Tools Command Prompt` for 32-bit and 64-bit applications, respectively. Then navigate to the project root directory and run the following commands: | |||||
cd build\win64 | |||||
cmake ..\.. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=... | |||||
cmake --build . | |||||
## Testing | |||||
After building, a standalone version of the application will be located somewhere in the `bin` directory according to the build type, build platform, and version string. This application can be executed with the following command: | |||||
cmake --build . --target run | |||||
## Distribution | |||||
The built application can be packaged into a distributable format with the following command: | |||||
cmake --build . --target package | |||||
The resulting package will be located in the `dist` directory. | |||||
## Contributing | |||||
If any changes have been made to the submodules, commit those first. Each submodule can then be updated to their latest commits with the following command: | |||||
git submodule update --recursive --remote | |||||
## License | |||||
The source code for Antkeeper is licensed under the GNU General Public License, version 3. See [COPYING](./COPYING) for details. | |||||
# Antkeeper Source · [![GitHub license](https://img.shields.io/github/license/cjhoward/antkeeper.svg)](https://github.com/cjhoward/antkeeper/blob/master/COPYING) [![GitHub release](https://img.shields.io/github/release/cjhoward/antkeeper.svg)](https://github.com/cjhoward/antkeeper/releases/) | |||||
Antkeeper is an ant colony simulation game for Windows, Mac OS X, and GNU/Linux. This repository contains all of the source code to Antkeeper. The game data, however, is proprietary. You can access the game data by purchasing a copy of Antkeeper at [https://antkeeper.com/](). | |||||
## License | |||||
The source code for Antkeeper is licensed under the GNU General Public License, version 3. See [`COPYING`](./COPYING) for details. | |||||
### 3rd-Party Software | |||||
| Name | Author(s) | License | Files | | |||||
| :--------------- | :----------- | :-------------------------- | :---- | | |||||
| dr_wav | David Reid | Public Domain | [`dr_wav.h`](./src/dr_libs/dr_wav.h) | | |||||
| Emergent | C. J. Howard | GNU GPL v3.0 | | | |||||
| OpenAL soft | | GNU GPL v2.0 | | | |||||
| stb_image | Sean Barrett | Public Domain / MIT License | [`stb_image.h`](./src/stb/stb_image.h) | | |||||
| stb_image_writer | Sean Barrett | Public Domain / MIT License | [`stb_image_writer.h`](./src/stb/stb_image_writer.h) | | |||||
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -0,0 +1 @@ | |||||
project(antkeeper VERSION "0.0.0") |
@ -1,3 +0,0 @@ | |||||
* | |||||
*/* | |||||
!.gitignore |
@ -1,429 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef APPLICATION_HPP | |||||
#define APPLICATION_HPP | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#include "mesh.hpp" | |||||
#include "game/terrain.hpp" | |||||
#include "game/level.hpp" | |||||
#include "game/biome.hpp" | |||||
#include "game/terrain.hpp" | |||||
#include "input.hpp" | |||||
#include "controls.hpp" | |||||
#include "settings.hpp" | |||||
#include "render-passes.hpp" | |||||
#include "ui/ui.hpp" | |||||
#include "ui/tween.hpp" | |||||
class Menu; | |||||
class MenuItem; | |||||
class ApplicationState; | |||||
class Colony; | |||||
class LoadingState; | |||||
class SplashState; | |||||
class TitleState; | |||||
class GameState; | |||||
class CameraRig; | |||||
class OrbitCam; | |||||
class FreeCam; | |||||
class LineBatcher; | |||||
class ModelLoader; | |||||
class MaterialLoader; | |||||
class Toolbar; | |||||
class PieMenu; | |||||
class Tool; | |||||
class Forceps; | |||||
class Lens; | |||||
class Brush; | |||||
/** | |||||
* Encapsulates the state of the application. | |||||
*/ | |||||
class Application | |||||
{ | |||||
public: | |||||
Application(int argc, char* argv[]); | |||||
~Application(); | |||||
// Executes the application and returns a status code | |||||
int execute(); | |||||
// Changes the application state | |||||
void changeState(ApplicationState* state); | |||||
// Sets the termination code to be returned when the application finishes | |||||
void setTerminationCode(int code); | |||||
// Closes the application | |||||
void close(int terminationCode); | |||||
void changeFullscreen(); | |||||
void changeVerticalSync(); | |||||
void saveUserSettings(); | |||||
bool loadScene(); | |||||
bool loadUI(); | |||||
bool loadModels(); | |||||
bool loadControls(); | |||||
bool loadGame(); | |||||
void resizeUI(); | |||||
void restringUI(); | |||||
void openMenu(Menu* menu); | |||||
void closeMenu(); | |||||
void selectMenuItem(std::size_t index); | |||||
void activateMenuItem(); | |||||
void incrementMenuItem(); | |||||
void decrementMenuItem(); | |||||
void loadWorld(std::size_t index); | |||||
void loadLevel(std::size_t index); | |||||
void continueGame(); | |||||
void newGame(); | |||||
void deselectTool(Tool* tool); | |||||
void selectTool(Tool* tool); | |||||
void pauseSimulation(); | |||||
void unpauseSimulation(); | |||||
void openPauseMenu(); | |||||
void closePauseMenu(); | |||||
void setDisplayDebugInfo(bool display); | |||||
std::u32string getLevelName(std::size_t world, std::size_t level) const; | |||||
// Options menu functions | |||||
void selectWindowedResolution(std::size_t index); | |||||
void selectFullscreenResolution(std::size_t index); | |||||
void selectFullscreenMode(std::size_t index); | |||||
void selectVSyncMode(std::size_t index); | |||||
void selectLanguage(std::size_t index); | |||||
void bindControl(Control* control); | |||||
private: | |||||
ApplicationState* state; | |||||
ApplicationState* nextState; | |||||
int terminationCode; | |||||
public: | |||||
// SDL | |||||
SDL_Window* window; | |||||
SDL_GLContext context; | |||||
// Paths | |||||
std::string appDataPath; | |||||
std::string userDataPath; | |||||
std::string defaultSettingsFilename; | |||||
std::string userSettingsFilename; | |||||
// Settings | |||||
ParameterDict settings; | |||||
// State machine | |||||
LoadingState* loadingState; | |||||
SplashState* splashState; | |||||
TitleState* titleState; | |||||
GameState* gameState; | |||||
// Scene | |||||
Scene scene; | |||||
SceneLayer* defaultLayer; | |||||
SceneLayer* uiLayer; | |||||
Camera camera; | |||||
Camera sunlightCamera; | |||||
Camera uiCamera; | |||||
DirectionalLight sunlight; | |||||
ModelInstance forcepsModelInstance; | |||||
ModelInstance navigatorObject; | |||||
ModelInstance antModelInstance; | |||||
ModelInstance antHillModelInstance; | |||||
ModelInstance nestModelInstance; | |||||
ModelInstance sidewalkPanelInstance; | |||||
ModelInstance sidewalkPanelInstance1; | |||||
ModelInstance sidewalkPanelInstance2; | |||||
ModelInstance sidewalkPanelInstance3; | |||||
ModelInstance sidewalkPanelInstance4; | |||||
ModelInstance soilInstance; | |||||
// Graphics | |||||
Renderer renderer; | |||||
RenderTarget defaultRenderTarget; | |||||
int shadowMapResolution; | |||||
GLuint shadowMapDepthTextureID; | |||||
GLuint shadowMapFramebuffer; | |||||
RenderTarget shadowMapRenderTarget; | |||||
ShadowMapRenderPass shadowMapPass; | |||||
Compositor shadowMapCompositor; | |||||
Texture2D shadowMapDepthTexture; | |||||
GLuint framebufferAColorTextureID; | |||||
GLuint framebufferADepthTextureID; | |||||
GLuint framebufferA; | |||||
RenderTarget framebufferARenderTarget; | |||||
Texture2D framebufferAColorTexture; | |||||
GLuint framebufferBColorTextureID; | |||||
GLuint framebufferBDepthTextureID; | |||||
GLuint framebufferB; | |||||
RenderTarget framebufferBRenderTarget; | |||||
Texture2D framebufferBColorTexture; | |||||
GLuint pheromonePBO; | |||||
GLuint pheromoneTextureID; | |||||
Texture2D pheromoneTexture; | |||||
ClearRenderPass clearDepthPass; | |||||
LightingRenderPass lightingPass; | |||||
DebugRenderPass debugPass; | |||||
Compositor defaultCompositor; | |||||
BillboardBatch* uiBatch; | |||||
UIBatcher* uiBatcher; | |||||
UIRenderPass uiPass; | |||||
Compositor uiCompositor; | |||||
SkyboxRenderPass skyboxPass; | |||||
TextureLoader* textureLoader; | |||||
MaterialLoader* materialLoader; | |||||
ModelLoader* modelLoader; | |||||
BlurRenderPass horizontalBlurPass; | |||||
BlurRenderPass verticalBlurPass; | |||||
BlurRenderPass horizontalBlurPass2; | |||||
BlurRenderPass verticalBlurPass2; | |||||
// Controls | |||||
Control* bindingControl; | |||||
InputManager* inputManager; | |||||
Keyboard* keyboard; | |||||
Mouse* mouse; | |||||
ControlProfile* menuControlProfile; | |||||
Control menuLeft; | |||||
Control menuRight; | |||||
Control menuUp; | |||||
Control menuDown; | |||||
Control menuSelect; | |||||
Control menuCancel; | |||||
Control toggleFullscreen; | |||||
Control toggleDebugDisplay; | |||||
Control escape; | |||||
ControlProfile* gameControlProfile; | |||||
Control cameraMoveForward; | |||||
Control cameraMoveBack; | |||||
Control cameraMoveLeft; | |||||
Control cameraMoveRight; | |||||
Control cameraRotateCW; | |||||
Control cameraRotateCCW; | |||||
Control cameraZoomIn; | |||||
Control cameraZoomOut; | |||||
Control cameraToggleOverheadView; | |||||
Control cameraToggleNestView; | |||||
Control walkForward; | |||||
Control walkBack; | |||||
Control turnLeft; | |||||
Control turnRight; | |||||
Control togglePause; | |||||
Control togglePauseMenu; | |||||
Control fastForward; | |||||
Control switchRig; | |||||
Arcball arcball; | |||||
// Misc | |||||
Timer frameTimer; | |||||
float t; | |||||
float dt; | |||||
// UI text | |||||
ParameterDict strings; | |||||
float dpi; | |||||
float fontSizePT; | |||||
float fontSizePX; | |||||
Font* menuFont; | |||||
Font* copyrightFont; | |||||
Font* levelNameFont; | |||||
// UI textures | |||||
Texture2D* splashTexture; | |||||
Texture2D* titleTexture; | |||||
Texture2D* rectangularPaletteTexture; | |||||
Texture2D* foodIndicatorTexture; | |||||
Texture2D* toolBrushTexture; | |||||
Texture2D* toolLensTexture; | |||||
Texture2D* toolForcepsTexture; | |||||
Texture2D* toolTrowelTexture; | |||||
Texture2D* toolbarTopTexture; | |||||
Texture2D* toolbarBottomTexture; | |||||
Texture2D* toolbarMiddleTexture; | |||||
Texture2D* toolbarButtonRaisedTexture; | |||||
Texture2D* toolbarButtonDepressedTexture; | |||||
Texture2D* arcNorthTexture; | |||||
Texture2D* arcEastTexture; | |||||
Texture2D* arcSouthTexture; | |||||
Texture2D* arcWestTexture; | |||||
Texture2D* mouseLeftTexture; | |||||
Texture2D* mouseRightTexture; | |||||
Texture2D* depthTexture; | |||||
// UI elements | |||||
Vector4 selectedColor; | |||||
Vector4 deselectedColor; | |||||
UIContainer* uiRootElement; | |||||
UIImage* blackoutImage; | |||||
UIImage* splashBackgroundImage; | |||||
UIImage* splashImage; | |||||
UIImage* titleImage; | |||||
UIImage* darkenImage; | |||||
UILabel* frameTimeLabel; | |||||
UILabel* anyKeyLabel; | |||||
UILabel* copyrightLabel; | |||||
UIImage* rectangularPaletteImage; | |||||
UIImage* foodIndicatorImage; | |||||
UIImage* contextButtonImage0; | |||||
UIImage* contextButtonImage1; | |||||
UIImage* depthTextureImage; | |||||
UILabel* levelNameLabel; | |||||
Toolbar* toolbar; | |||||
PieMenu* pieMenu; | |||||
// Animation | |||||
Tweener* tweener; | |||||
Tween<Vector4>* fadeInTween; | |||||
Tween<Vector4>* fadeOutTween; | |||||
Tween<Vector4>* darkenFadeInTween; | |||||
Tween<Vector4>* darkenFadeOutTween; | |||||
Tween<float>* blurFadeInTween; | |||||
Tween<float>* blurFadeOutTween; | |||||
Tween<Vector4>* splashFadeInTween; | |||||
Tween<Vector4>* splashFadeOutTween; | |||||
Tween<float>* splashHangTween; | |||||
Tween<Vector4>* titleFadeInTween; | |||||
Tween<Vector4>* titleFadeOutTween; | |||||
Tween<Vector4>* anyKeyFadeInTween; | |||||
Tween<Vector4>* anyKeyFadeOutTween; | |||||
Tween<Vector4>* menuFadeInTween; | |||||
Tween<Vector4>* menuFadeOutTween; | |||||
Tween<float>* menuActivateTween; | |||||
Tween<Vector3>* cameraTranslationTween; | |||||
Tween<float>* forcepsSwoopTween; | |||||
// Menus | |||||
Menu* activeMenu; | |||||
Menu* previousActiveMenu; | |||||
Menu* mainMenu; | |||||
MenuItem* mainMenuContinueItem; | |||||
MenuItem* mainMenuLevelsItem; | |||||
MenuItem* mainMenuNewGameItem; | |||||
MenuItem* mainMenuSandboxItem; | |||||
MenuItem* mainMenuOptionsItem; | |||||
MenuItem* mainMenuExitItem; | |||||
Menu* levelsMenu; | |||||
MenuItem* levelsMenuBackItem; | |||||
Menu* optionsMenu; | |||||
MenuItem* optionsMenuWindowedResolutionItem; | |||||
MenuItem* optionsMenuFullscreenResolutionItem; | |||||
MenuItem* optionsMenuFullscreenItem; | |||||
MenuItem* optionsMenuVSyncItem; | |||||
MenuItem* optionsMenuLanguageItem; | |||||
MenuItem* optionsMenuControlsItem; | |||||
MenuItem* optionsMenuBackItem; | |||||
Menu* controlsMenu; | |||||
MenuItem* controlsMenuResetToDefaultItem; | |||||
MenuItem* controlsMenuMoveForwardItem; | |||||
MenuItem* controlsMenuMoveBackItem; | |||||
MenuItem* controlsMenuMoveLeftItem; | |||||
MenuItem* controlsMenuMoveRightItem; | |||||
MenuItem* controlsMenuBackItem; | |||||
Menu* graphicsMenu; | |||||
Menu* audioMenu; | |||||
Menu* gameplayMenu; | |||||
Menu* pauseMenu; | |||||
MenuItem* pauseMenuResumeItem; | |||||
MenuItem* pauseMenuLevelsItem; | |||||
MenuItem* pauseMenuOptionsItem; | |||||
MenuItem* pauseMenuMainMenuItem; | |||||
MenuItem* pauseMenuExitItem; | |||||
// Models | |||||
Model* antModel; | |||||
Model* antHillModel; | |||||
Model* nestModel; | |||||
Model* forcepsModel; | |||||
Model* lensModel; | |||||
Model* brushModel; | |||||
Model* sidewalkPanelModel; | |||||
Model* soilModel; | |||||
// Game variables | |||||
Biosphere biosphere; | |||||
Campaign campaign; | |||||
int currentWorldIndex; | |||||
int currentLevelIndex; | |||||
Level* currentLevel; | |||||
Colony* colony; | |||||
OrbitCam* orbitCam; | |||||
FreeCam* freeCam; | |||||
CameraRig* activeRig; | |||||
bool cameraOverheadView; | |||||
bool cameraNestView; | |||||
int toolIndex; | |||||
Tool* currentTool; | |||||
Forceps* forceps; | |||||
Lens* lens; | |||||
Brush* brush; | |||||
bool simulationPaused; | |||||
// Debug | |||||
LineBatcher* lineBatcher; | |||||
bool displayDebugInfo; | |||||
// Options menu values | |||||
bool fullscreen; | |||||
int swapInterval; | |||||
Vector2 resolution; | |||||
std::vector<Vector2> resolutions; | |||||
std::size_t windowedResolutionIndex; | |||||
std::size_t fullscreenResolutionIndex; | |||||
int* fullscreenModes; | |||||
int* vsyncModes; | |||||
std::vector<std::string> languages; | |||||
std::size_t languageIndex; | |||||
}; | |||||
#endif // APPLICATION_HPP |
@ -1,65 +1,9 @@ | |||||
/* | |||||
* 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef CONFIGURATION_HPP | |||||
#define CONFIGURATION_HPP | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#define ANTKEEPER_VERSION_MAJOR @ANTKEEPER_VERSION_MAJOR@ | |||||
#define ANTKEEPER_VERSION_MINOR @ANTKEEPER_VERSION_MINOR@ | |||||
#define ANTKEEPER_VERSION_PATCH @ANTKEEPER_VERSION_PATCH@ | |||||
#define ANTKEEPER_VERSION_STRING "@ANTKEEPER_VERSION@" | |||||
#cmakedefine ANTKEEPER_DEBUG | |||||
// Terrain dimensions | |||||
const float ANTKEEPER_TERRAIN_WIDTH = 100.0f; | |||||
const float ANTKEEPER_TERRAIN_BASE_HEIGHT = 35.7f; | |||||
const float ANTKEEPER_TERRAIN_DEPTH = ANTKEEPER_TERRAIN_WIDTH; | |||||
const float ANTKEEPER_OCTREE_PADDING = 5.0f; | |||||
// UI | |||||
const int ANTKEEPER_UI_LAYER_LOADING = 40; | |||||
const int ANTKEEPER_UI_LAYER_BLACKOUT = 30; | |||||
const int ANTKEEPER_UI_LAYER_MENU = 20; | |||||
const int ANTKEEPER_UI_LAYER_DARKEN = 10; | |||||
const int ANTKEEPER_UI_LAYER_HUD = 0; | |||||
const float WORLD_WIDTH = 100.0f; // cm | |||||
const float WORLD_HEIGHT = 100.0f; // cm | |||||
const float FRAMES_PER_SECOND = 60.0f; | |||||
const float TIMESTEP = 1.0f / FRAMES_PER_SECOND; | |||||
const float PHEROMONE_MATRIX_RESOLUTION = 5.12f; // pheromone cells per cm | |||||
const int PHEROMONE_MATRIX_COLUMNS = (int)(WORLD_WIDTH * PHEROMONE_MATRIX_RESOLUTION); | |||||
const int PHEROMONE_MATRIX_ROWS = (int)(WORLD_HEIGHT * PHEROMONE_MATRIX_RESOLUTION); | |||||
const Vector2 WORLD_BOUNDS_MIN = Vector2(-WORLD_WIDTH * 0.5f, -WORLD_HEIGHT * 0.5f); | |||||
const Vector2 WORLD_BOUNDS_MAX = Vector2(WORLD_WIDTH * 0.5f, WORLD_HEIGHT * 0.5f); | |||||
const float BRUSH_RADIUS = 0.5f; | |||||
const float EVAPORATION_FACTOR = 0.99925f; | |||||
const float DIFFUSIONS_PER_SECOND = 4.0f; | |||||
const int DIFFUSION_FRAME = static_cast<int>(FRAMES_PER_SECOND / DIFFUSIONS_PER_SECOND); | |||||
const float HOMING_PHEROMONE_COLOR[] = {0.55f, 0.55f, 0.00f, 0.0f}; // CMYK | |||||
const float RECRUITMENT_PHEROMONE_COLOR[] = {0.00f, 0.55f, 0.55f, 0.0f}; // CMYK | |||||
const float ALARM_PHEROMONE_COLOR[] = {0.00f, 0.00f, 1.00f, 0.0f}; // CMYK | |||||
const std::uint64_t MATERIAL_FLAG_TRANSLUCENT = 0x0000000001; | |||||
const std::uint64_t MATERIAL_FLAG_DISABLE_SHADOW_CASTING = 0x0000000002; | |||||
#endif // CONFIGURATION_HPP | |||||
#ifndef CONFIGURATION_HPP | |||||
#define CONFIGURATION_HPP | |||||
#define VERSION_MAJOR @PROJECT_VERSION_MAJOR@ | |||||
#define VERSION_MINOR @PROJECT_VERSION_MINOR@ | |||||
#define VERSION_PATCH @PROJECT_VERSION_PATCH@ | |||||
#define VERSION_STRING "@PROJECT_VERSION@" | |||||
#endif // CONFIGURATION_HPP |
@ -1,134 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef CONTROLS_HPP | |||||
#define CONTROLS_HPP | |||||
#include "input.hpp" | |||||
#include <list> | |||||
#include <utility> | |||||
#include <tuple> | |||||
#include <map> | |||||
enum class MouseWheelAxis | |||||
{ | |||||
POSITIVE_X, | |||||
NEGATIVE_X, | |||||
POSITIVE_Y, | |||||
NEGATIVE_Y | |||||
}; | |||||
class Control: | |||||
public KeyObserver, | |||||
public MouseButtonObserver, | |||||
public MouseWheelObserver, | |||||
public GamepadButtonObserver, | |||||
public GamepadAxisObserver | |||||
{ | |||||
public: | |||||
Control(); | |||||
virtual ~Control(); | |||||
void setDeadzone(float value); | |||||
void update(); | |||||
float getDeadzone() const; | |||||
float getCurrentValue() const; | |||||
float getPreviousValue() const; | |||||
bool isTriggered() const; | |||||
bool wasTriggered() const; | |||||
bool isUnbound() const; | |||||
void bindKey(Keyboard* keyboard, int scancode); | |||||
void bindMouseButton(Mouse* mouse, int button); | |||||
void bindMouseWheelAxis(Mouse* mouse, MouseWheelAxis axis); | |||||
void bindGamepadButton(Gamepad* gamepad, int button); | |||||
void bindGamepadAxis(Gamepad* gamepad, int axis, bool negative); | |||||
void bind(const InputEvent& event); | |||||
void unbind(); | |||||
virtual void keyPressed(int scancode); | |||||
virtual void keyReleased(int scancode); | |||||
virtual void mouseButtonPressed(int button, int x, int y); | |||||
virtual void mouseButtonReleased(int button, int x, int y); | |||||
virtual void mouseWheelScrolled(int x, int y); | |||||
virtual void gamepadButtonPressed(int button); | |||||
virtual void gamepadButtonReleased(int button); | |||||
virtual void gamepadAxisMoved(int axis, bool negative, float value); | |||||
const std::list<std::pair<Keyboard*, int>>* getBoundKeys() const; | |||||
const std::list<std::pair<Mouse*, int>>* getBoundMouseButtons() const; | |||||
const std::list<std::pair<Mouse*, MouseWheelAxis>>* getBoundMouseWheelAxes() const; | |||||
const std::list<std::pair<Gamepad*, int>>* getBoundGamepadButtons() const; | |||||
const std::list<std::tuple<Gamepad*, int, bool>>* getBoundGamepadAxes() const; | |||||
private: | |||||
float deadzone; | |||||
float currentValue; | |||||
float previousValue; | |||||
std::list<std::pair<Keyboard*, int>> boundKeys; | |||||
std::list<std::pair<Mouse*, int>> boundMouseButtons; | |||||
std::list<std::pair<Mouse*, MouseWheelAxis>> boundMouseWheelAxes; | |||||
std::list<std::pair<Gamepad*, int>> boundGamepadButtons; | |||||
std::list<std::tuple<Gamepad*, int, bool>> boundGamepadAxes; | |||||
}; | |||||
inline float Control::getDeadzone() const | |||||
{ | |||||
return deadzone; | |||||
} | |||||
inline float Control::getCurrentValue() const | |||||
{ | |||||
return currentValue; | |||||
} | |||||
inline float Control::getPreviousValue() const | |||||
{ | |||||
return previousValue; | |||||
} | |||||
class ControlProfile | |||||
{ | |||||
public: | |||||
ControlProfile(InputManager* inputManager); | |||||
void registerControl(const std::string& name, Control* control); | |||||
bool save(const std::string& filename); | |||||
bool load(const std::string& filename); | |||||
// Calls Control::update() on each control registered with this profile | |||||
void update(); | |||||
const std::map<std::string, Control*>* getControlMap() const; | |||||
private: | |||||
InputManager* inputManager; | |||||
std::map<std::string, Control*> controls; | |||||
}; | |||||
inline const std::map<std::string, Control*>* ControlProfile::getControlMap() const | |||||
{ | |||||
return &controls; | |||||
} | |||||
#endif | |||||
@ -1,80 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "debug.hpp" | |||||
#include <iostream> | |||||
LineBatcher::LineBatcher(std::size_t lineCount): | |||||
lineCount(lineCount), | |||||
currentLine(0), | |||||
width(1.0f), | |||||
color(1.0f) | |||||
{ | |||||
batch.resize(lineCount); | |||||
range = batch.addRange(); | |||||
range->material = nullptr;//&material; | |||||
//material.albedo = Vector3(1.0f); | |||||
} | |||||
void LineBatcher::begin() | |||||
{ | |||||
currentLine = 0; | |||||
range->start = 0; | |||||
range->length = 0; | |||||
} | |||||
void LineBatcher::end() | |||||
{ | |||||
range->length = currentLine; | |||||
batch.update(); | |||||
} | |||||
void LineBatcher::draw(const Vector3& start, const Vector3& end) | |||||
{ | |||||
if (currentLine >= batch.getBillboardCount()) | |||||
{ | |||||
std::cout << "LineBatcher::draw(): maximum line count exceeded" << std::endl; | |||||
return; | |||||
} | |||||
Vector3 center = (start + end) * 0.5f; | |||||
float length = glm::length(end - start); | |||||
Vector3 forward = glm::normalize(end - start); | |||||
glm::quat rotation = glm::normalize(glm::rotation(Vector3(1, 0, 0), forward)); | |||||
Billboard* billboard = batch.getBillboard(currentLine); | |||||
billboard->setTranslation(center); | |||||
billboard->setDimensions(Vector2(length, width)); | |||||
billboard->setRotation(rotation); | |||||
billboard->setTintColor(color); | |||||
++currentLine; | |||||
} | |||||
void LineBatcher::setWidth(float width) | |||||
{ | |||||
this->width = width; | |||||
} | |||||
void LineBatcher::setColor(const Vector4& color) | |||||
{ | |||||
this->color = color; | |||||
} |
@ -0,0 +1,2 @@ | |||||
#define DR_WAV_IMPLEMENTATION | |||||
#include "dr_wav.h" |
@ -0,0 +1,81 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "component-manager.hpp" | |||||
#include "component-observer.hpp" | |||||
void ComponentManager::addComponentObserver(ComponentObserver* observer) | |||||
{ | |||||
componentObservers.push_back(observer); | |||||
} | |||||
void ComponentManager::removeComponentObserver(ComponentObserver* observer) | |||||
{ | |||||
componentObservers.remove(observer); | |||||
} | |||||
void ComponentManager::addComponent(EntityID entity, ComponentBase* component) | |||||
{ | |||||
ComponentType componentType = component->getComponentType(); | |||||
entityMap[entity][componentType] = component; | |||||
// Notify observers | |||||
for (auto observer: componentObservers) | |||||
{ | |||||
observer->componentAdded(entity, component); | |||||
} | |||||
} | |||||
ComponentBase* ComponentManager::removeComponent(EntityID entity, ComponentType type) | |||||
{ | |||||
ComponentMap& componentMap = entityMap[entity]; | |||||
auto it = componentMap.find(type); | |||||
if (it == componentMap.end()) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
ComponentBase* component = it->second; | |||||
// Notify observers | |||||
for (auto observer: componentObservers) | |||||
{ | |||||
observer->componentRemoved(entity, component); | |||||
} | |||||
componentMap.erase(it); | |||||
return component; | |||||
} | |||||
ComponentBase* ComponentManager::getComponent(EntityID entity, ComponentType type) | |||||
{ | |||||
ComponentMap& componentMap = entityMap[entity]; | |||||
auto it = componentMap.find(type); | |||||
if (it == componentMap.end()) | |||||
{ | |||||
return nullptr; | |||||
} | |||||
return it->second; | |||||
} | |||||
@ -0,0 +1,116 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COMPONENT_MANAGER_HPP | |||||
#define COMPONENT_MANAGER_HPP | |||||
#include "entity-id.hpp" | |||||
#include "component.hpp" | |||||
#include <list> | |||||
#include <map> | |||||
class ComponentObserver; | |||||
/// Maps component types to components. | |||||
typedef std::map<ComponentType, ComponentBase*> ComponentMap; | |||||
/// Maps entity IDs to a component map. | |||||
typedef std::map<EntityID, ComponentMap> EntityComponentMap; | |||||
/** | |||||
* Manages the aggregation of components which make up entities. | |||||
*/ | |||||
class ComponentManager | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an instance of ComponentManager. | |||||
*/ | |||||
ComponentManager() = default; | |||||
/** | |||||
* Destroys an instance of ComponentManager. | |||||
*/ | |||||
~ComponentManager() = default; | |||||
/** | |||||
* Adds a ComponentObserver. | |||||
* | |||||
* @param observer Pointer to the observer to add. | |||||
*/ | |||||
void addComponentObserver(ComponentObserver* observer); | |||||
/** | |||||
* Removes a ComponentObserver. | |||||
* | |||||
* @param observer Pointer to the observer to remove. | |||||
*/ | |||||
void removeComponentObserver(ComponentObserver* observer); | |||||
/** | |||||
* Adds a component to the specified entity. | |||||
* | |||||
* @param entity Specifies an entity. | |||||
* @param component Specifies the component to add. | |||||
*/ | |||||
void addComponent(EntityID entity, ComponentBase* component); | |||||
/** | |||||
* Removes a component from the specified entity. | |||||
* | |||||
* @param entity Specifies an entity. | |||||
* @param type Specifies the type of component. | |||||
* | |||||
* @return Pointer to the removed component. | |||||
*/ | |||||
ComponentBase* removeComponent(EntityID entity, ComponentType type); | |||||
/** | |||||
* Returns the specified component of an entity. | |||||
* | |||||
* @param entity Specifies an entity. | |||||
* @param type Specifies the type of component. | |||||
* | |||||
* @return Pointer to the component, or `nullptr` if the specified component was not found. | |||||
*/ | |||||
ComponentBase* getComponent(EntityID entity, ComponentType type); | |||||
/** | |||||
* Returns the component map of the specified entity. | |||||
* | |||||
* @param entity Specifies an entity. | |||||
* | |||||
* @return Pointer to the component map. | |||||
*/ | |||||
ComponentMap* getComponents(EntityID entity); | |||||
private: | |||||
ComponentManager(const ComponentManager&) = delete; | |||||
ComponentManager& operator=(const ComponentManager&) = delete; | |||||
EntityComponentMap entityMap; | |||||
std::list<ComponentObserver*> componentObservers; | |||||
}; | |||||
inline ComponentMap* ComponentManager::getComponents(EntityID entity) | |||||
{ | |||||
return &entityMap[entity]; | |||||
} | |||||
#endif // COMPONENT_MANAGER_HPP |
@ -0,0 +1,69 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COMPONENT_OBSERVER_HPP | |||||
#define COMPONENT_OBSERVER_HPP | |||||
#include "entity-id.hpp" | |||||
class ComponentBase; | |||||
class ComponentManager; | |||||
/** | |||||
* Abstract base class for component observers. | |||||
*/ | |||||
class ComponentObserver | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a component observer. | |||||
* | |||||
* @param componentManager Specifies the component manager with which to associate this component observer. | |||||
*/ | |||||
ComponentObserver(ComponentManager* componentManager); | |||||
/** | |||||
* Destroys a component observer. | |||||
*/ | |||||
virtual ~ComponentObserver(); | |||||
protected: | |||||
ComponentManager* componentManager; | |||||
private: | |||||
friend class ComponentManager; | |||||
/** | |||||
* Called after a component is added to an entity. | |||||
* | |||||
* @param entity Specifies the entity with which the component is associated. | |||||
* @param component Specifies the component added. | |||||
*/ | |||||
virtual void componentAdded(EntityID entity, ComponentBase* component) = 0; | |||||
/** | |||||
* Called after a component is removed from an entity. | |||||
* | |||||
* @param entity Specifies the entity with which the component is associated. | |||||
* @param component Specifies the component removed. | |||||
*/ | |||||
virtual void componentRemoved(EntityID entity, ComponentBase* component) = 0; | |||||
}; | |||||
#endif // COMPONENT_OBSERVER_HPP |
@ -0,0 +1,77 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COMPONENT_HPP | |||||
#define COMPONENT_HPP | |||||
enum class ComponentType; | |||||
/** | |||||
* Abstract base class for entity components. | |||||
*/ | |||||
class ComponentBase | |||||
{ | |||||
public: | |||||
/** | |||||
* Destroys a component. | |||||
*/ | |||||
virtual ~ComponentBase() = default; | |||||
/** | |||||
* Clones the component. | |||||
*/ | |||||
virtual ComponentBase* clone() const = 0; | |||||
/** | |||||
* Returns the component type. | |||||
*/ | |||||
virtual ComponentType getComponentType() const = 0; | |||||
}; | |||||
/** | |||||
* Abstract templated class for entity components. | |||||
*/ | |||||
template <ComponentType type> | |||||
class Component: public ComponentBase | |||||
{ | |||||
public: | |||||
static const ComponentType TYPE; | |||||
/** | |||||
* Destroys a component. | |||||
*/ | |||||
virtual ~Component() = default; | |||||
/** | |||||
* Returns the component type. | |||||
*/ | |||||
virtual ComponentType getComponentType() const final; | |||||
}; | |||||
template <ComponentType type> | |||||
const ComponentType Component<type>::TYPE = type; | |||||
template <ComponentType type> | |||||
inline ComponentType Component<type>::getComponentType() const | |||||
{ | |||||
return type; | |||||
} | |||||
#endif // COMPONENT_HPP | |||||
@ -0,0 +1,27 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "ant-hill-component.hpp" | |||||
ComponentBase* AntHillComponent::clone() const | |||||
{ | |||||
AntHillComponent* component = new AntHillComponent(); | |||||
return component; | |||||
} | |||||
@ -0,0 +1,36 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANT_HILL_COMPONENT_HPP | |||||
#define ANT_HILL_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class AntHillComponent: public Component<ComponentType::ANT_HILL> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
}; | |||||
#endif // ANT_HILL_COMPONENT_HPP | |||||
@ -0,0 +1,29 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "behavior-component.hpp" | |||||
ComponentBase* BehaviorComponent::clone() const | |||||
{ | |||||
BehaviorComponent* component = new BehaviorComponent(); | |||||
component->wanderDirection = wanderDirection; | |||||
component->wanderTriangle = wanderTriangle; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,41 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef BEHAVIOR_COMPONENT_HPP | |||||
#define BEHAVIOR_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class BehaviorComponent: public Component<ComponentType::BEHAVIOR> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
float wanderCircleDistance; // cm | |||||
float wanderCircleRadius; // cm | |||||
float wanderRate; // radians/s | |||||
Vector3 wanderDirection; | |||||
TriangleMesh::Triangle* wanderTriangle; | |||||
}; | |||||
#endif // BEHAVIOR_COMPONENT_HPP | |||||
@ -0,0 +1,30 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "collision-component.hpp" | |||||
ComponentBase* CollisionComponent::clone() const | |||||
{ | |||||
CollisionComponent* component = new CollisionComponent(); | |||||
component->radius = radius; | |||||
component->collisions = collisions; | |||||
component->mesh = mesh; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,38 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COMPONENT__TYPE_HPP | |||||
#define COMPONENT__TYPE_HPP | |||||
enum class ComponentType | |||||
{ | |||||
ANIMATION, | |||||
ANT_HILL, | |||||
BEHAVIOR, | |||||
COLLISION, | |||||
LEGGED_LOCOMOTION, | |||||
MODEL, | |||||
STEERING, | |||||
SOUND_SOURCE, | |||||
TOOL, | |||||
TRANSFORM | |||||
}; | |||||
#endif // COMPONENT_TYPE_HPP | |||||
@ -0,0 +1,34 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "legged-locomotion-component.hpp" | |||||
ComponentBase* LeggedLocomotionComponent::clone() const | |||||
{ | |||||
LeggedLocomotionComponent* component = new LeggedLocomotionComponent(); | |||||
component->legCount = legCount; | |||||
component->crawlingSpeed = crawlingSpeed; | |||||
component->walkingSpeed = walkingSpeed; | |||||
component->runningSpeed = runningSpeed; | |||||
component->turningSpeed = turningSpeed; | |||||
component->speed = walkingSpeed; | |||||
component->surface = nullptr; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,45 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef LEGGED_LOCOMOTION_COMPONENT_HPP | |||||
#define LEGGED_LOCOMOTION_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class LeggedLocomotionComponent: public Component<ComponentType::LEGGED_LOCOMOTION> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
unsigned char legCount; | |||||
float crawlingSpeed; // cm/s | |||||
float walkingSpeed; // cm/s | |||||
float runningSpeed; // cm/s | |||||
float turningSpeed; // radians/s | |||||
float speed; | |||||
TriangleMesh::Triangle* surface; | |||||
Vector3 barycentricPosition; | |||||
}; | |||||
#endif // LEGGED_LOCOMOTION_COMPONENT_HPP | |||||
@ -0,0 +1,29 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "model-component.hpp" | |||||
ComponentBase* ModelComponent::clone() const | |||||
{ | |||||
ModelComponent* component = new ModelComponent(); | |||||
component->model.setModel(model.getModel()); | |||||
component->model.setPose(nullptr); | |||||
return component; | |||||
} | |||||
@ -0,0 +1,37 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef MODEL_COMPONENT_HPP | |||||
#define MODEL_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class ModelComponent: public Component<ComponentType::MODEL> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
ModelInstance model; | |||||
}; | |||||
#endif // MODEL_COMPONENT_HPP | |||||
@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "sound-source-component.hpp" | |||||
ComponentBase* SoundSourceComponent::clone() const | |||||
{ | |||||
SoundSourceComponent* component = new SoundSourceComponent(); | |||||
component->playing = playing; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,39 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef SOUND_SOURCE_COMPONENT_HPP | |||||
#define SOUND_SOURCE_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "../entity-id.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class SoundSourceComponent: public Component<ComponentType::SOUND_SOURCE> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
bool playing; | |||||
}; | |||||
#endif // SOUND_SOURCE_COMPONENT_HPP | |||||
@ -0,0 +1,27 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "steering-component.hpp" | |||||
ComponentBase* SteeringComponent::clone() const | |||||
{ | |||||
SteeringComponent* component = new SteeringComponent(); | |||||
return component; | |||||
} | |||||
@ -0,0 +1,56 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef STEERING_COMPONENT_HPP | |||||
#define STEERING_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#define MAX_STEERING_BEHAVIORS 8 | |||||
struct SteeringBehavior | |||||
{ | |||||
/// Function object which calculates steering force | |||||
std::function<Vector3()> function; | |||||
/// Priority value which determines in what order the behaviors will be evaluated | |||||
float priority; | |||||
/// Weight factor by which the calculated steering force should be multiplied | |||||
float weight; | |||||
}; | |||||
class SteeringComponent: public Component<ComponentType::STEERING> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
SteeringBehavior behaviors[MAX_STEERING_BEHAVIORS]; | |||||
std::size_t behaviorCount; | |||||
Vector3 force; | |||||
float speed; | |||||
float maxSpeed; | |||||
}; | |||||
#endif // STEERING_COMPONENT_HPP | |||||
@ -0,0 +1,29 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "tool-component.hpp" | |||||
ComponentBase* ToolComponent::clone() const | |||||
{ | |||||
ToolComponent* component = new ToolComponent(); | |||||
component->active = active; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "transform-component.hpp" | |||||
ComponentBase* TransformComponent::clone() const | |||||
{ | |||||
TransformComponent* component = new TransformComponent(); | |||||
component->transform = transform; | |||||
return component; | |||||
} | |||||
@ -0,0 +1,38 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef TRANSFORM_COMPONENT_HPP | |||||
#define TRANSFORM_COMPONENT_HPP | |||||
#include "../component.hpp" | |||||
#include "component-type.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class TransformComponent: public Component<ComponentType::TRANSFORM> | |||||
{ | |||||
public: | |||||
virtual ComponentBase* clone() const; | |||||
Transform transform; | |||||
}; | |||||
#endif // TRANSFORM_COMPONENT_HPP | |||||
@ -0,0 +1,43 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_GROUP_MEMBER_HPP | |||||
#define ENTITY_GROUP_MEMBER_HPP | |||||
#include "entity-id.hpp" | |||||
#include <tuple> | |||||
#include <type_traits> | |||||
/** | |||||
* A group of entities which share a set of specified component types. | |||||
* | |||||
* @tparam T Set of components which are required for group membership. | |||||
*/ | |||||
template <typename... T> | |||||
struct EntityGroupMember | |||||
{ | |||||
/// Entity ID of the group member. | |||||
EntityID entity; | |||||
/// A tuple containing pointers to the member's group-related components, in the order specified by the order of the template parameters. | |||||
std::tuple<T*...> components; | |||||
}; | |||||
#endif // ENTITY_GROUP_MEMBER_HPP | |||||
@ -0,0 +1,52 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_GROUP_OBSERVER_HPP | |||||
#define ENTITY_GROUP_OBSERVER_HPP | |||||
#include "entity-group-member.hpp" | |||||
/** | |||||
* Abstract base class for entity group observers, which are notified each time a member is registered or unregistered from the group. | |||||
* | |||||
* @tparam T Set of components which are required for group membership. | |||||
*/ | |||||
template <typename... T> | |||||
class EntityGroupObserver | |||||
{ | |||||
public: | |||||
typedef EntityGroupMember<T...> Member; | |||||
/** | |||||
* Called each time an entity joins the entity group by obtaining the necessary component types. | |||||
* | |||||
* @param entity Entity ID of the new member. | |||||
*/ | |||||
virtual void memberRegistered(const Member* member) = 0; | |||||
/** | |||||
* Called each time an entity leaves an the entity group by no longer possessing the necessary component types. | |||||
* | |||||
* @param entity Entity ID of the former member. | |||||
*/ | |||||
virtual void memberUnregistered(const Member* member) = 0; | |||||
}; | |||||
#endif // ENTITY_GROUP_OBSERVER_HPP | |||||
@ -0,0 +1,59 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "component.hpp" | |||||
#include "component-manager.hpp" | |||||
#include "entity-group.hpp" | |||||
EntityGroupBase::EntityGroupBase(ComponentManager* componentManager, const ComponentFilter& componentFilter): | |||||
ComponentObserver(componentManager), | |||||
componentFilter(componentFilter) | |||||
{} | |||||
void EntityGroupBase::componentAdded(EntityID entity, ComponentBase* component) | |||||
{ | |||||
if (componentFilter.find(component->getComponentType()) != componentFilter.end()) | |||||
{ | |||||
for (auto it = componentFilter.begin(); it != componentFilter.end(); ++it) | |||||
{ | |||||
if (*it == component->getComponentType()) | |||||
{ | |||||
continue; | |||||
} | |||||
else if (!componentManager->getComponent(entity, *it)) | |||||
{ | |||||
return; | |||||
} | |||||
} | |||||
registerMember(entity); | |||||
} | |||||
} | |||||
void EntityGroupBase::componentRemoved(EntityID entity, ComponentBase* component) | |||||
{ | |||||
if (componentFilter.find(component->getComponentType()) != componentFilter.end()) | |||||
{ | |||||
if (isRegistered(entity)) | |||||
{ | |||||
unregisterMember(entity); | |||||
} | |||||
} | |||||
} | |||||
@ -0,0 +1,268 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_GROUP_HPP | |||||
#define ENTITY_GROUP_HPP | |||||
#include "component-observer.hpp" | |||||
#include "component-manager.hpp" | |||||
#include "entity-group-member.hpp" | |||||
#include "entity-group-observer.hpp" | |||||
#include <list> | |||||
#include <map> | |||||
#include <set> | |||||
#include <tuple> | |||||
#include <utility> | |||||
enum class ComponentType; | |||||
/// A set of component types used to filter entities | |||||
typedef std::set<ComponentType> ComponentFilter; | |||||
/** | |||||
* Abstract base class for entity groups. | |||||
*/ | |||||
class EntityGroupBase: protected ComponentObserver | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a entity group base. | |||||
* | |||||
* @param componentManager The component manager with which to associate this entity group. | |||||
* @param componentFilter Set of component types which an entity must possess in order to join this entity group. | |||||
*/ | |||||
EntityGroupBase(ComponentManager* componentManager, const ComponentFilter& componentFilter); | |||||
/// Returns the set of components which an entity must possess in order to join this entity group. | |||||
const ComponentFilter& getComponentFilter() const; | |||||
/** | |||||
* Returns true if the specified entity is registered with this entity group. | |||||
* | |||||
* @param entity ID of the entity to check. | |||||
*/ | |||||
virtual bool isRegistered(EntityID entity) const = 0; | |||||
private: | |||||
virtual void componentAdded(EntityID entity, ComponentBase* component); | |||||
virtual void componentRemoved(EntityID entity, ComponentBase* component); | |||||
/** | |||||
* Called each time an entity joins the entity group by obtaining the necessary component types. | |||||
* | |||||
* @param entity Entity ID of the new member. | |||||
*/ | |||||
virtual void registerMember(EntityID entity) = 0; | |||||
/** | |||||
* Called each time an entity leaves an the entity group by no longer possessing the necessary component types. | |||||
* | |||||
* @param entity Entity ID of the former member. | |||||
*/ | |||||
virtual void unregisterMember(EntityID entity) = 0; | |||||
ComponentFilter componentFilter; | |||||
}; | |||||
inline const ComponentFilter& EntityGroupBase::getComponentFilter() const | |||||
{ | |||||
return componentFilter; | |||||
} | |||||
/** | |||||
* A group of entities which share a set of specified component types. | |||||
* | |||||
* @tparam T Set of components which are required for group membership. | |||||
*/ | |||||
template <typename... T> | |||||
class EntityGroup: public EntityGroupBase | |||||
{ | |||||
public: | |||||
typedef EntityGroupMember<T...> Member; | |||||
typedef EntityGroupObserver<T...> Observer; | |||||
/** | |||||
* Creates a entity group. | |||||
* | |||||
* @param componentManager Component manager with which to associate this entity group. | |||||
*/ | |||||
EntityGroup(ComponentManager* componentManager); | |||||
/// Destroys a entity group. | |||||
~EntityGroup(); | |||||
/** | |||||
* Adds a group observer. | |||||
* | |||||
* @param observer Observer to add. | |||||
*/ | |||||
void addGroupObserver(Observer* observer); | |||||
/** | |||||
* Removes a group observer. | |||||
* | |||||
* @param observer Observer to remove. | |||||
*/ | |||||
void removeGroupObserver(Observer* observer); | |||||
/// Removes all group observers. | |||||
void removeGroupObservers(); | |||||
/// @copydoc EntityGroupBase::isRegistered(EntityID) const | |||||
virtual bool isRegistered(EntityID entity) const; | |||||
/** | |||||
* Returns the member list. | |||||
* | |||||
* @return List of members. | |||||
*/ | |||||
const std::list<Member*>* getMembers() const; | |||||
/** | |||||
* Returns the member with the specified ID. | |||||
* | |||||
* @param entity Entity ID of a group member. | |||||
* @return Member with the specified ID, or nullptr if an entity with that ID is not registered. | |||||
*/ | |||||
const Member* getMemberByEntity(EntityID entity) const; | |||||
private: | |||||
template <std::size_t index, typename U, typename... V> | |||||
typename std::enable_if<(sizeof...(V) == 0), void>::type attachComponents(Member* member) | |||||
{ | |||||
std::get<index>(member->components) = static_cast<U*>(componentManager->getComponent(member->entity, U::TYPE)); | |||||
} | |||||
template <std::size_t index, typename U, typename... V> | |||||
typename std::enable_if<(sizeof...(V) > 0), void>::type attachComponents(Member* member) | |||||
{ | |||||
std::get<index>(member->components) = static_cast<U*>(componentManager->getComponent(member->entity, U::TYPE)); | |||||
attachComponents<index + 1, V...>(member); | |||||
} | |||||
virtual void registerMember(EntityID entity); | |||||
virtual void unregisterMember(EntityID entity); | |||||
std::list<Member*> members; | |||||
std::map<EntityID, Member*> memberMap; | |||||
std::list<Observer*> observers; | |||||
}; | |||||
template <typename... T> | |||||
EntityGroup<T...>::EntityGroup(ComponentManager* componentManager): | |||||
EntityGroupBase(componentManager, ComponentFilter({(T::TYPE)...})) | |||||
{} | |||||
template <typename... T> | |||||
EntityGroup<T...>::~EntityGroup() | |||||
{ | |||||
while (!members.empty()) | |||||
{ | |||||
Member* member = members.back(); | |||||
members.pop_back(); | |||||
memberMap.erase(memberMap.find(member->entity)); | |||||
for (Observer* observer: observers) | |||||
{ | |||||
observer->memberUnregistered(member); | |||||
} | |||||
delete member; | |||||
} | |||||
} | |||||
template <typename... T> | |||||
void EntityGroup<T...>::addGroupObserver(Observer* observer) | |||||
{ | |||||
observers.push_back(observer); | |||||
} | |||||
template <typename... T> | |||||
void EntityGroup<T...>::removeGroupObserver(Observer* observer) | |||||
{ | |||||
observers.remove(observer); | |||||
} | |||||
template <typename... T> | |||||
void EntityGroup<T...>::removeGroupObservers() | |||||
{ | |||||
observers.clear(); | |||||
} | |||||
template <typename... T> | |||||
inline bool EntityGroup<T...>::isRegistered(EntityID entity) const | |||||
{ | |||||
return (memberMap.find(entity) != memberMap.end()); | |||||
} | |||||
template <typename... T> | |||||
inline const std::list<typename EntityGroup<T...>::Member*>* EntityGroup<T...>::getMembers() const | |||||
{ | |||||
return &members; | |||||
} | |||||
template <typename... T> | |||||
inline const typename EntityGroup<T...>::Member* EntityGroup<T...>::getMemberByEntity(EntityID entity) const | |||||
{ | |||||
auto it = memberMap.find(entity); | |||||
if (it != memberMap.end()) | |||||
{ | |||||
return it->second; | |||||
} | |||||
return nullptr; | |||||
} | |||||
template <typename... T> | |||||
void EntityGroup<T...>::registerMember(EntityID entity) | |||||
{ | |||||
Member* member = new Member(); | |||||
member->entity = entity; | |||||
attachComponents<0, T...>(member); | |||||
members.push_back(member); | |||||
memberMap[entity] = member; | |||||
for (Observer* observer: observers) | |||||
{ | |||||
observer->memberRegistered(member); | |||||
} | |||||
} | |||||
template <typename... T> | |||||
void EntityGroup<T...>::unregisterMember(EntityID entity) | |||||
{ | |||||
auto it = memberMap.find(entity); | |||||
Member* member = it->second; | |||||
memberMap.erase(it); | |||||
members.remove(member); | |||||
for (Observer* observer: observers) | |||||
{ | |||||
observer->memberUnregistered(member); | |||||
} | |||||
delete member; | |||||
} | |||||
#endif // ENTITY_GROUP_HPP | |||||
@ -0,0 +1,68 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "entity-id-pool.hpp" | |||||
EntityIDPool::EntityIDPool(): | |||||
nextID(0) | |||||
{} | |||||
EntityIDPool::~EntityIDPool() | |||||
{} | |||||
EntityID EntityIDPool::reserveNextID() | |||||
{ | |||||
EntityID id; | |||||
if (!availableIDs.empty()) | |||||
{ | |||||
id = *availableIDs.begin(); | |||||
availableIDs.erase(availableIDs.begin()); | |||||
reservedIDs.insert(id); | |||||
} | |||||
else | |||||
{ | |||||
id = nextID; | |||||
reservedIDs.insert(id); | |||||
findNextID(); | |||||
} | |||||
return id; | |||||
} | |||||
void EntityIDPool::reserveID(EntityID id) | |||||
{ | |||||
availableIDs.erase(id); | |||||
reservedIDs.insert(id); | |||||
if (nextID == id) | |||||
{ | |||||
findNextID(); | |||||
} | |||||
} | |||||
inline void EntityIDPool::findNextID() | |||||
{ | |||||
do | |||||
{ | |||||
++nextID; | |||||
} | |||||
while (reservedIDs.find(nextID) != reservedIDs.end()); | |||||
} | |||||
@ -0,0 +1,87 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_ID_POOL_HPP | |||||
#define ENTITY_ID_POOL_HPP | |||||
#include "entity-id.hpp" | |||||
#include <set> | |||||
/** | |||||
* Manages the creation and destruction of entities. | |||||
*/ | |||||
class EntityIDPool | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an instance of EntityIDPool. | |||||
*/ | |||||
EntityIDPool(); | |||||
/** | |||||
* Destroys an instance of EntityIDPool. | |||||
*/ | |||||
~EntityIDPool(); | |||||
/** | |||||
* Reserves the next available ID. | |||||
* | |||||
* @return Reserved ID. | |||||
*/ | |||||
EntityID reserveNextID(); | |||||
/** | |||||
* Reserves the specified ID. | |||||
* | |||||
* @param id Specifies an ID to reserve. | |||||
*/ | |||||
void reserveID(EntityID id); | |||||
/** | |||||
* Frees the specified ID. | |||||
* | |||||
* @param id Specifies an ID to free. | |||||
*/ | |||||
void freeID(EntityID id); | |||||
/** | |||||
* Returns `true` if the specified ID is reserved. | |||||
*/ | |||||
bool isReserved(EntityID id) const; | |||||
private: | |||||
void findNextID(); | |||||
EntityID nextID; | |||||
std::set<EntityID> reservedIDs; | |||||
std::set<EntityID> availableIDs; | |||||
}; | |||||
inline void EntityIDPool::freeID(EntityID id) | |||||
{ | |||||
reservedIDs.erase(id); | |||||
availableIDs.insert(id); | |||||
} | |||||
inline bool EntityIDPool::isReserved(EntityID id) const | |||||
{ | |||||
return (reservedIDs.find(id) != reservedIDs.end()); | |||||
} | |||||
#endif // ENTITY_ID_POOL_HPP |
@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_ID_HPP | |||||
#define ENTITY_ID_HPP | |||||
#include <cstdint> | |||||
typedef std::uint32_t EntityID; | |||||
#endif // ENTITY_ID_HPP | |||||
@ -0,0 +1,69 @@ | |||||
/* | |||||
* Copyright (C) 2015 Christopher J. Howard | |||||
* | |||||
* This file is part of Ecosys. | |||||
* | |||||
* Ecosys 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. | |||||
* | |||||
* Ecosys 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 Ecosys. If not, see <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "entity-manager.hpp" | |||||
#include "component-manager.hpp" | |||||
EntityManager::EntityManager(ComponentManager* componentManager): | |||||
componentManager(componentManager) | |||||
{} | |||||
EntityManager::~EntityManager() | |||||
{} | |||||
EntityID EntityManager::createEntity() | |||||
{ | |||||
return idPool.reserveNextID(); | |||||
} | |||||
bool EntityManager::createEntity(EntityID id) | |||||
{ | |||||
if (idPool.isReserved(id)) | |||||
{ | |||||
return false; | |||||
} | |||||
idPool.reserveID(id); | |||||
return true; | |||||
} | |||||
bool EntityManager::destroyEntity(EntityID id) | |||||
{ | |||||
if (!idPool.isReserved(id)) | |||||
{ | |||||
return false; | |||||
} | |||||
// Delete components | |||||
ComponentMap* components = componentManager->getComponents(id); | |||||
for (auto it = components->begin(); it != components->end(); it = components->begin()) | |||||
{ | |||||
ComponentBase* component = it->second; | |||||
componentManager->removeComponent(id, component->getComponentType()); | |||||
delete component; | |||||
} | |||||
// Free ID | |||||
idPool.freeID(id); | |||||
return true; | |||||
} | |||||
@ -0,0 +1,97 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_MANAGER_HPP | |||||
#define ENTITY_MANAGER_HPP | |||||
#include "entity-id.hpp" | |||||
#include "entity-id-pool.hpp" | |||||
class ComponentManager; | |||||
/** | |||||
* Manages the creation and destruction of entities. | |||||
*/ | |||||
class EntityManager | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an entity manager. | |||||
* | |||||
* @param componentManager Component manager with which to associate this entity manag.er | |||||
*/ | |||||
EntityManager(ComponentManager* componentManager); | |||||
/** | |||||
* Destroys an entity manager. | |||||
*/ | |||||
~EntityManager(); | |||||
/** | |||||
* Creates an entity with the next available ID. | |||||
* | |||||
* @return ID of the created entity. | |||||
*/ | |||||
EntityID createEntity(); | |||||
/** | |||||
* Creates an entity with the specified ID. | |||||
* | |||||
* @param id ID of the entity to be created. | |||||
* @return `true` if the entity was created, and `false` if an entity with the specified ID already exists. | |||||
*/ | |||||
bool createEntity(EntityID id); | |||||
/** | |||||
* Destroys an entity with the specified ID. | |||||
* | |||||
* @param id ID of the entity to be destroyed. | |||||
* | |||||
* @return `true` if the entity was destroyed, and `false` if an invalid ID was supplied. | |||||
*/ | |||||
bool destroyEntity(EntityID id); | |||||
/** | |||||
* Returns the component manager associated with this entity manager. | |||||
*/ | |||||
const ComponentManager* getComponentManager() const; | |||||
/// @copydoc EntityManager::getComponentManager() const | |||||
ComponentManager* getComponentManager(); | |||||
private: | |||||
EntityManager(const EntityManager&) = delete; | |||||
EntityManager& operator=(const EntityManager&) = delete; | |||||
EntityIDPool idPool; | |||||
ComponentManager* componentManager; | |||||
}; | |||||
inline const ComponentManager* EntityManager::getComponentManager() const | |||||
{ | |||||
return componentManager; | |||||
} | |||||
inline ComponentManager* EntityManager::getComponentManager() | |||||
{ | |||||
return componentManager; | |||||
} | |||||
#endif // ENTITY_MANAGER_HPP | |||||
@ -0,0 +1,54 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "component.hpp" | |||||
#include "component-manager.hpp" | |||||
#include "entity-template.hpp" | |||||
EntityTemplate::EntityTemplate(const std::list<ComponentBase*>& components) | |||||
{ | |||||
for (ComponentBase* component: components) | |||||
{ | |||||
this->components.push_back(component->clone()); | |||||
} | |||||
} | |||||
EntityTemplate::~EntityTemplate() | |||||
{ | |||||
for (ComponentBase* component: components) | |||||
{ | |||||
delete component; | |||||
} | |||||
} | |||||
void EntityTemplate::apply(EntityID entity, ComponentManager* componentManager) | |||||
{ | |||||
for (ComponentBase* component: components) | |||||
{ | |||||
ComponentBase* oldComponent = componentManager->getComponent(entity, component->getComponentType()); | |||||
if (oldComponent != nullptr) | |||||
{ | |||||
componentManager->removeComponent(entity, component->getComponentType()); | |||||
delete oldComponent; | |||||
} | |||||
componentManager->addComponent(entity, component->clone()); | |||||
} | |||||
} | |||||
@ -0,0 +1,60 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ENTITY_TEMPLATE_HPP | |||||
#define ENTITY_TEMPLATE_HPP | |||||
#include <list> | |||||
#include "entity-id.hpp" | |||||
class ComponentBase; | |||||
class ComponentManager; | |||||
/** | |||||
* A template which can be applied to entities. | |||||
*/ | |||||
class EntityTemplate | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an entity template. | |||||
* | |||||
* @param components List of components which make up the template. The components in the list will be cloned and the cloned data managed by this template. | |||||
*/ | |||||
EntityTemplate(const std::list<ComponentBase*>& components); | |||||
/** | |||||
* Destroys an entity template. | |||||
*/ | |||||
~EntityTemplate(); | |||||
/** | |||||
* Applies the template to an entity. | |||||
* | |||||
* @param entity ID of an entity to which the template should be applied. | |||||
* @param componentManager Component manager with which the entity is associated. | |||||
*/ | |||||
void apply(EntityID entity, ComponentManager* componentManager); | |||||
private: | |||||
std::list<ComponentBase*> components; | |||||
}; | |||||
#endif // ENTITY_TEMPLATE_HPP | |||||
@ -0,0 +1,45 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "system-manager.hpp" | |||||
#include "system.hpp" | |||||
SystemManager::SystemManager() | |||||
{} | |||||
SystemManager::~SystemManager() | |||||
{} | |||||
void SystemManager::update(float t, float dt) | |||||
{ | |||||
for (System* system: systems) | |||||
{ | |||||
system->update(t, dt); | |||||
} | |||||
} | |||||
void SystemManager::addSystem(System* system) | |||||
{ | |||||
systems.push_back(system); | |||||
} | |||||
void SystemManager::removeSystem(System* system) | |||||
{ | |||||
systems.remove(system); | |||||
} |
@ -0,0 +1,68 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef SYSTEM_MANAGER_HPP | |||||
#define SYSTEM_MANAGER_HPP | |||||
#include <list> | |||||
class System; | |||||
/** | |||||
* Manages a series of systems. | |||||
*/ | |||||
class SystemManager | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a system manager. | |||||
*/ | |||||
SystemManager(); | |||||
/** | |||||
* Destroys a system manager. | |||||
*/ | |||||
~SystemManager(); | |||||
/** | |||||
* Updates all systems. Systems will be updated in the order that they were added to the system manager. | |||||
* | |||||
* @param t Total elapsed time, in seconds. | |||||
* @param dt Time elapsed since last update, in seconds. | |||||
*/ | |||||
void update(float t, float dt); | |||||
/** | |||||
* Adds a system to the system manager. | |||||
* | |||||
* @param system System to add. | |||||
*/ | |||||
void addSystem(System* system); | |||||
/** | |||||
* Removes a system from the system manager. | |||||
*/ | |||||
void removeSystem(System* system); | |||||
private: | |||||
std::list<System*> systems; | |||||
}; | |||||
#endif // SYSTEM_MANAGER_HPP | |||||
@ -0,0 +1,48 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "animation-system.hpp" | |||||
AnimationSystem::AnimationSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
animationGroup(componentManager) | |||||
{} | |||||
AnimationSystem::~AnimationSystem() | |||||
{} | |||||
void AnimationSystem::update(float t, float dt) | |||||
{ | |||||
auto members = animationGroup.getMembers(); | |||||
for (const AnimationEntityGroup::Member* member: *members) | |||||
{ | |||||
AnimationComponent* animationComponent = std::get<0>(member->components); | |||||
ModelComponent* modelComponent = std::get<1>(member->components); | |||||
Pose* pose = modelComponent->model.getPose(); | |||||
for (const std::pair<AnimationClip<Transform>, float>& clipWeightPair: animationComponent->animations) | |||||
{ | |||||
const AnimationClip<Transform>& clip = clipWeightPair.first; | |||||
float weight = clipWeightPair.second; | |||||
} | |||||
} | |||||
} | |||||
@ -0,0 +1,46 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANIMATION_SYSTEM_HPP | |||||
#define ANIMATION_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/animation-component.hpp" | |||||
#include "../components/model-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<AnimationComponent, ModelComponent> AnimationEntityGroup; | |||||
class AnimationSystem: public System | |||||
{ | |||||
public: | |||||
AnimationSystem(ComponentManager* componentManager); | |||||
virtual ~AnimationSystem(); | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
AnimationEntityGroup animationGroup; | |||||
}; | |||||
#endif // ANIMATION_SYSTEM_HPP | |||||
@ -0,0 +1,181 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "behavior-system.hpp" | |||||
#include <set> | |||||
BehaviorSystem::BehaviorSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
behaviorGroup(componentManager), | |||||
antHillGroup(componentManager) | |||||
{ | |||||
behaviorGroup.addGroupObserver(this); | |||||
} | |||||
BehaviorSystem::~BehaviorSystem() | |||||
{} | |||||
void BehaviorSystem::update(float t, float dt) | |||||
{ | |||||
auto members = behaviorGroup.getMembers(); | |||||
for (const BehaviorGroup::Member* member: *members) | |||||
{ | |||||
BehaviorComponent* behavior = std::get<0>(member->components); | |||||
LeggedLocomotionComponent* leggedLocomotion = std::get<1>(member->components); | |||||
SteeringComponent* steering = std::get<2>(member->components); | |||||
TransformComponent* transform = std::get<3>(member->components); | |||||
steering->maxSpeed = leggedLocomotion->speed; | |||||
steering->behaviorCount = 2; | |||||
steering->behaviors[0].priority = 2.0f; | |||||
steering->behaviors[0].weight = 1.0f; | |||||
steering->behaviors[0].function = std::bind(&BehaviorSystem::containment, this, member); | |||||
steering->behaviors[1].priority = 1.0f; | |||||
steering->behaviors[1].weight = 0.5f; | |||||
steering->behaviors[1].function = std::bind(&BehaviorSystem::wander, this, dt, member); | |||||
} | |||||
} | |||||
void BehaviorSystem::memberRegistered(const BehaviorGroup::Member* member) | |||||
{ | |||||
BehaviorComponent* behavior = std::get<0>(member->components); | |||||
LeggedLocomotionComponent* leggedLocomotion = std::get<1>(member->components); | |||||
behavior->wanderDirection = Vector3(0.0f); | |||||
while (glm::length2(behavior->wanderDirection) == 0.0f) | |||||
{ | |||||
behavior->wanderDirection = Vector3(frand(-1, 1), frand(-1, 1), frand(-1, 1)); | |||||
} | |||||
behavior->wanderTriangle = leggedLocomotion->surface; | |||||
behavior->wanderDirection = glm::normalize(behavior->wanderDirection); | |||||
behavior->wanderCircleDistance = 3.0f; | |||||
behavior->wanderCircleRadius = 2.0f; | |||||
behavior->wanderRate = glm::radians(180.0f) * 5.0f; | |||||
leggedLocomotion->speed = 2.0f; | |||||
} | |||||
void BehaviorSystem::memberUnregistered(const BehaviorGroup::Member* member) | |||||
{} | |||||
Vector3 BehaviorSystem::containment(const BehaviorGroup::Member* agent) | |||||
{ | |||||
LeggedLocomotionComponent* leggedLocomotion = std::get<1>(agent->components); | |||||
TransformComponent* transform = std::get<3>(agent->components); | |||||
float probeAngle = glm::radians(30.0f); | |||||
float probeDistance = 5.0f; | |||||
Vector3 direction = transform->transform.rotation * Vector3(0, 0, 1); | |||||
TriangleMesh::Triangle* surface = leggedLocomotion->surface; | |||||
Vector3 forward = transform->transform.rotation * Vector3(0, 0, 1); | |||||
Vector3 up = surface->normal; | |||||
Vector3 right = glm::normalize(glm::cross(forward, up)); | |||||
Vector3 force(0.0f); | |||||
return force; | |||||
} | |||||
Vector3 BehaviorSystem::wander(float dt, const BehaviorGroup::Member* agent) | |||||
{ | |||||
BehaviorComponent* behavior = std::get<0>(agent->components); | |||||
LeggedLocomotionComponent* leggedLocomotion = std::get<1>(agent->components); | |||||
SteeringComponent* steering = std::get<2>(agent->components); | |||||
TransformComponent* transform = std::get<3>(agent->components); | |||||
// Reorientate wander direction | |||||
if (behavior->wanderTriangle != leggedLocomotion->surface) | |||||
{ | |||||
if (behavior->wanderTriangle) | |||||
{ | |||||
behavior->wanderDirection = glm::normalize(glm::rotation(behavior->wanderTriangle->normal, leggedLocomotion->surface->normal) * behavior->wanderDirection); | |||||
} | |||||
behavior->wanderTriangle = leggedLocomotion->surface; | |||||
} | |||||
// Make wander direction coplanar with surface triangle | |||||
TriangleMesh::Triangle* triangle = leggedLocomotion->surface; | |||||
Vector3 triangleCenter = (triangle->edge->vertex->position + triangle->edge->next->vertex->position + triangle->edge->previous->vertex->position) * (1.0f / 3.0f); | |||||
behavior->wanderDirection = glm::normalize(projectOnPlane(transform->transform.translation + behavior->wanderDirection, triangleCenter, triangle->normal) - transform->transform.translation); | |||||
Vector3 forward = transform->transform.rotation * Vector3(0, 0, 1); | |||||
Vector3 up = triangle->normal; | |||||
// Calculate center of wander circle | |||||
Vector3 wanderCircleCenter = forward * behavior->wanderCircleDistance; | |||||
// Calculate wander force | |||||
Vector3 wanderForce = wanderCircleCenter + behavior->wanderDirection * behavior->wanderCircleRadius; | |||||
// Displace wander direction | |||||
float displacementAngle = frand(-behavior->wanderRate, behavior->wanderRate) * 0.5f * dt; | |||||
behavior->wanderDirection = glm::normalize(glm::angleAxis(displacementAngle, up) * behavior->wanderDirection); | |||||
return wanderForce; | |||||
} | |||||
Vector3 BehaviorSystem::forage(const BehaviorGroup::Member* agent) | |||||
{ | |||||
return Vector3(0.0f); | |||||
} | |||||
Vector3 BehaviorSystem::homing(const BehaviorGroup::Member* agent) | |||||
{ | |||||
// Get ant position | |||||
const Vector3& antPosition = std::get<3>(agent->components)->transform.translation; | |||||
// Find nearest ant-hill | |||||
bool found = false; | |||||
float minDistanceSquared = 0.0f; | |||||
Vector3 homingDirection(0.0f); | |||||
auto antHills = antHillGroup.getMembers(); | |||||
for (const AntHillGroup::Member* antHill: *antHills) | |||||
{ | |||||
// Get ant-hill position | |||||
const Vector3& antHillPosition = std::get<1>(antHill->components)->transform.translation; | |||||
// Determine distance to ant-hill | |||||
Vector3 difference = antHillPosition - antPosition; | |||||
float distanceSquared = glm::length2(difference); | |||||
if (!found || distanceSquared < minDistanceSquared) | |||||
{ | |||||
minDistanceSquared = distanceSquared; | |||||
homingDirection = difference; | |||||
found = true; | |||||
} | |||||
} | |||||
if (found) | |||||
{ | |||||
homingDirection = glm::normalize(homingDirection); | |||||
} | |||||
return homingDirection; | |||||
} | |||||
@ -0,0 +1,61 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef BEHAVIOR_SYSTEM_HPP | |||||
#define BEHAVIOR_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/ant-hill-component.hpp" | |||||
#include "../components/behavior-component.hpp" | |||||
#include "../components/legged-locomotion-component.hpp" | |||||
#include "../components/steering-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<BehaviorComponent, LeggedLocomotionComponent, SteeringComponent, TransformComponent> BehaviorGroup; | |||||
typedef EntityGroup<AntHillComponent, TransformComponent> AntHillGroup; | |||||
class BehaviorSystem: public | |||||
System, | |||||
BehaviorGroup::Observer | |||||
{ | |||||
public: | |||||
BehaviorSystem(ComponentManager* componentManager); | |||||
virtual ~BehaviorSystem(); | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
BehaviorGroup behaviorGroup; | |||||
AntHillGroup antHillGroup; | |||||
virtual void memberRegistered(const BehaviorGroup::Member* member); | |||||
virtual void memberUnregistered(const BehaviorGroup::Member* member); | |||||
Vector3 containment(const BehaviorGroup::Member* agent); | |||||
Vector3 wander(float dt, const BehaviorGroup::Member* agent); | |||||
Vector3 forage(const BehaviorGroup::Member* agent); | |||||
Vector3 homing(const BehaviorGroup::Member* agent); | |||||
}; | |||||
#endif // BEHAVIOR_SYSTEM_HPP | |||||
@ -0,0 +1,65 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "collision-system.hpp" | |||||
CollisionSystem::CollisionSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
entityGroup(componentManager) | |||||
{} | |||||
CollisionSystem::~CollisionSystem() | |||||
{} | |||||
void CollisionSystem::update(float t, float dt) | |||||
{ | |||||
auto members = entityGroup.getMembers(); | |||||
// INEFFICIENT! Currently done twice (A vs B, then B vs A) | |||||
// Also no octrees or other structure | |||||
for (const CollisionEntityGroup::Member* memberA: *members) | |||||
{ | |||||
CollisionComponent* collisionA = std::get<0>(memberA->components); | |||||
TransformComponent* transformA = std::get<1>(memberA->components); | |||||
// Clear previous collisions | |||||
collisionA->collisions.clear(); | |||||
for (const CollisionEntityGroup::Member* memberB: *members) | |||||
{ | |||||
if (memberA == memberB) | |||||
{ | |||||
continue; | |||||
} | |||||
CollisionComponent* collisionB = std::get<0>(memberB->components); | |||||
TransformComponent* transformB = std::get<1>(memberB->components); | |||||
Vector3 difference = transformA->transform.translation - transformB->transform.translation; | |||||
float distanceSquared = glm::length2(difference); | |||||
float collisionRadius = collisionA->radius + collisionB->radius; | |||||
if (distanceSquared <= collisionRadius * collisionRadius) | |||||
{ | |||||
collisionA->collisions.push_back(memberB->entity); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
@ -0,0 +1,46 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COLLISION_SYSTEM_HPP | |||||
#define COLLISION_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/collision-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<CollisionComponent, TransformComponent> CollisionEntityGroup; | |||||
class CollisionSystem: public System | |||||
{ | |||||
public: | |||||
CollisionSystem(ComponentManager* componentManager); | |||||
virtual ~CollisionSystem(); | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
CollisionEntityGroup entityGroup; | |||||
}; | |||||
#endif // COLLISION_SYSTEM_HPP | |||||
@ -0,0 +1,107 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "locomotion-system.hpp" | |||||
#include "../../triangle-mesh-operations.hpp" | |||||
LocomotionSystem::LocomotionSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
leggedLocomotionGroup(componentManager) | |||||
{ | |||||
leggedLocomotionGroup.addGroupObserver(this); | |||||
} | |||||
LocomotionSystem::~LocomotionSystem() | |||||
{} | |||||
void LocomotionSystem::update(float t, float dt) | |||||
{ | |||||
auto members = leggedLocomotionGroup.getMembers(); | |||||
// Perform legged locomotion | |||||
for (const LeggedLocomotionGroup::Member* member: *members) | |||||
{ | |||||
LeggedLocomotionComponent* leggedLocomotion = std::get<0>(member->components); | |||||
SteeringComponent* steering = std::get<1>(member->components); | |||||
TransformComponent* transform = std::get<2>(member->components); | |||||
// Skip entities which are not on a surface | |||||
if (!leggedLocomotion->surface) | |||||
{ | |||||
continue; | |||||
} | |||||
// Determine target position | |||||
Vector3 force = steering->force * dt; | |||||
float speed = steering->speed * dt; | |||||
if (speed == 0.0f) | |||||
{ | |||||
continue; | |||||
} | |||||
// Calculate direction vector | |||||
Vector3 direction = force * (1.0f / speed); | |||||
std::vector<WrapOperationSegment> segments; | |||||
float wrapDistance = wrap(leggedLocomotion->surface, transform->transform.translation, direction, speed, &segments); | |||||
WrapOperationSegment segment = segments.back(); | |||||
Vector3 cartesianStart = cartesian(segment.startPosition, | |||||
segment.triangle->edge->vertex->position, | |||||
segment.triangle->edge->next->vertex->position, | |||||
segment.triangle->edge->previous->vertex->position); | |||||
Vector3 cartesianEnd = cartesian(segment.endPosition, | |||||
segment.triangle->edge->vertex->position, | |||||
segment.triangle->edge->next->vertex->position, | |||||
segment.triangle->edge->previous->vertex->position); | |||||
// Calculate wrap direction of final segment | |||||
Vector3 segmentDirection(0.0f); | |||||
if (cartesianStart != cartesianEnd) | |||||
{ | |||||
segmentDirection = glm::normalize(cartesianEnd - cartesianStart); | |||||
} | |||||
// Determine angle between the triangles | |||||
float angle = std::acos(glm::dot(leggedLocomotion->surface->normal, segment.triangle->normal)); | |||||
if (std::abs(angle) > glm::radians(35.0f)) | |||||
{ | |||||
// Transition | |||||
} | |||||
leggedLocomotion->surface = segment.triangle; | |||||
leggedLocomotion->barycentricPosition = segment.endPosition; | |||||
transform->transform.translation = cartesianEnd; | |||||
if (cartesianStart != cartesianEnd) | |||||
{ | |||||
transform->transform.rotation = lookRotation(segmentDirection, segment.triangle->normal); | |||||
} | |||||
} | |||||
} | |||||
void LocomotionSystem::memberRegistered(const LeggedLocomotionGroup::Member* member) | |||||
{} | |||||
void LocomotionSystem::memberUnregistered(const LeggedLocomotionGroup::Member* member) | |||||
{} | |||||
@ -0,0 +1,52 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef LOCOMOTION_SYSTEM_HPP | |||||
#define LOCOMOTION_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/legged-locomotion-component.hpp" | |||||
#include "../components/steering-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<LeggedLocomotionComponent, SteeringComponent, TransformComponent> LeggedLocomotionGroup; | |||||
class LocomotionSystem: public | |||||
System, | |||||
LeggedLocomotionGroup::Observer | |||||
{ | |||||
public: | |||||
LocomotionSystem(ComponentManager* componentManager); | |||||
virtual ~LocomotionSystem(); | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
LeggedLocomotionGroup leggedLocomotionGroup; | |||||
virtual void memberRegistered(const LeggedLocomotionGroup::Member* member); | |||||
virtual void memberUnregistered(const LeggedLocomotionGroup::Member* member); | |||||
}; | |||||
#endif // LOCOMOTION_SYSTEM_HPP | |||||
@ -0,0 +1,161 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "particle-system.hpp" | |||||
#include "../../game/curl-noise.hpp" | |||||
ParticleSystem::ParticleSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
range(nullptr), | |||||
material(nullptr) | |||||
{ | |||||
batch.setTransform(Transform::getIdentity()); | |||||
batch.setCullingEnabled(false); | |||||
} | |||||
ParticleSystem::~ParticleSystem() | |||||
{} | |||||
void ParticleSystem::resize(std::size_t count) | |||||
{ | |||||
particles.resize(count); | |||||
batch.resize(count); | |||||
range = batch.addRange(); | |||||
range->start = 0; | |||||
range->length = particles.size(); | |||||
range->material = material; | |||||
while (!stack.empty()) | |||||
stack.pop(); | |||||
for (int i = 0; i < particles.size(); ++i) | |||||
{ | |||||
Particle& particle = particles[i]; | |||||
particle.life = 0.0f; | |||||
particle.size = 0.0f; | |||||
Billboard* billboard = batch.getBillboard(i); | |||||
billboard->setDimensions(Vector2(particle.size)); | |||||
billboard->resetTweens(); | |||||
stack.push(i); | |||||
} | |||||
} | |||||
void ParticleSystem::emit(const Vector3& position) | |||||
{ | |||||
if (!stack.empty()) | |||||
{ | |||||
std::size_t index = stack.top(); | |||||
stack.pop(); | |||||
Particle& particle = particles[index]; | |||||
particle.life = frand(1.0f, 5.0f); | |||||
particle.translation = position; | |||||
particle.size = frand(0.01f, 0.2f); | |||||
particle.speed = frand(2.0f, 3.0f); | |||||
particle.direction = direction + Vector3(frand(-1, 1), 0, frand(-1, 1)) * 0.1f; | |||||
particle.direction = glm::normalize(particle.direction); | |||||
Billboard* billboard = batch.getBillboard(index); | |||||
billboard->setTranslation(particle.translation); | |||||
billboard->setRotation(Quaternion(1, 0, 0, 0)); | |||||
billboard->setDimensions(Vector2(particle.size)); | |||||
billboard->setTintColor(Vector4(1.0f)); | |||||
billboard->resetTweens(); | |||||
} | |||||
} | |||||
void ParticleSystem::update(float t, float dt) | |||||
{ | |||||
if (stack.size() == particles.size()) | |||||
{ | |||||
// Inactive | |||||
return; | |||||
} | |||||
batch.reset(); | |||||
const Vector3 wind = glm::normalize(Vector3(1.0f, 0.0f, -1.0f)) * 1.5f * dt; | |||||
float frequency = 0.4f; | |||||
Vector3 noiseOffset = Vector3(77.7f, 33.3f, 11.1f) * t * 0.01f; | |||||
for (std::size_t i = 0; i < particles.size(); ++i) | |||||
{ | |||||
Particle& particle = particles[i]; | |||||
if (particle.life <= 0.0f) | |||||
{ | |||||
continue; | |||||
} | |||||
Billboard* billboard = batch.getBillboard(i); | |||||
bool reset = false; | |||||
Vector3 smoke = curl(particle.translation, noiseOffset, frequency) * 8.0f; | |||||
particle.translation += particle.direction * particle.speed * dt + smoke * dt + wind; | |||||
particle.size += 0.1f * dt; | |||||
particle.life -= dt; | |||||
if (particle.life <= 0.0f) | |||||
{ | |||||
particle.size = 0.0f; | |||||
reset = true; | |||||
stack.push(i); | |||||
} | |||||
billboard->setTranslation(particle.translation); | |||||
billboard->setRotation(Quaternion(1, 0, 0, 0)); | |||||
billboard->setDimensions(Vector2(particle.size)); | |||||
billboard->setTintColor(Vector4(0.5f)); | |||||
if (reset) | |||||
{ | |||||
billboard->resetTweens(); | |||||
} | |||||
} | |||||
} | |||||
void ParticleSystem::setMaterial(Material* material) | |||||
{ | |||||
this->material = material; | |||||
if (range) | |||||
{ | |||||
range->material = material; | |||||
} | |||||
} | |||||
void ParticleSystem::setDirection(const Vector3& direction) | |||||
{ | |||||
this->direction = direction; | |||||
} | |||||
void ParticleSystem::setLifeTime(float time) | |||||
{ | |||||
this->lifeTime = time; | |||||
} | |||||
void ParticleSystem::setEmissionRate(float frequency) | |||||
{ | |||||
this->emissionRate = frequency; | |||||
} | |||||
@ -0,0 +1,86 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef PARTICLE_SYSTEM_HPP | |||||
#define PARTICLE_SYSTEM_HPP | |||||
#include "../components/model-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../entity-group.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#include <stack> | |||||
class ParticleSystem: | |||||
public System | |||||
{ | |||||
public: | |||||
ParticleSystem(ComponentManager* componentManager); | |||||
~ParticleSystem(); | |||||
void setMaterial(Material* material); | |||||
void setParticleCount(std::size_t count); | |||||
void setDirection(const Vector3& direction); | |||||
void setLifeTime(float time); | |||||
void setEmissionRate(float frequency); | |||||
const BillboardBatch* getBillboardBatch() const; | |||||
BillboardBatch* getBillboardBatch(); | |||||
void resize(std::size_t count); | |||||
virtual void update(float t, float dt); | |||||
void emit(const Vector3& position); | |||||
private: | |||||
struct Particle | |||||
{ | |||||
Vector3 translation; | |||||
float size; | |||||
float life; | |||||
float speed; | |||||
Vector3 direction; | |||||
}; | |||||
BillboardBatch batch; | |||||
BillboardBatch::Range* range; | |||||
Material* material; | |||||
std::vector<Particle> particles; | |||||
Vector3 direction; | |||||
float lifeTime; | |||||
float emissionRate; | |||||
std::stack<std::size_t> stack; | |||||
}; | |||||
inline const BillboardBatch* ParticleSystem::getBillboardBatch() const | |||||
{ | |||||
return &batch; | |||||
} | |||||
inline BillboardBatch* ParticleSystem::getBillboardBatch() | |||||
{ | |||||
return &batch; | |||||
} | |||||
#endif // PARTICLE_SYSTEM_HPP |
@ -0,0 +1,56 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "render-system.hpp" | |||||
RenderSystem::RenderSystem(ComponentManager* componentManager, SceneLayer* scene): | |||||
System(componentManager), | |||||
modelEntityGroup(componentManager), | |||||
scene(scene) | |||||
{ | |||||
modelEntityGroup.addGroupObserver(this); | |||||
} | |||||
RenderSystem::~RenderSystem() | |||||
{} | |||||
void RenderSystem::update(float t, float dt) | |||||
{ | |||||
auto members = modelEntityGroup.getMembers(); | |||||
for (const ModelEntityGroup::Member* member: *members) | |||||
{ | |||||
ModelComponent* model = std::get<0>(member->components); | |||||
TransformComponent* transform = std::get<1>(member->components); | |||||
model->model.setTransform(transform->transform); | |||||
} | |||||
} | |||||
void RenderSystem::memberRegistered(const ModelEntityGroup::Member* member) | |||||
{ | |||||
ModelComponent* model = std::get<0>(member->components); | |||||
scene->addObject(&model->model); | |||||
} | |||||
void RenderSystem::memberUnregistered(const ModelEntityGroup::Member* member) | |||||
{ | |||||
ModelComponent* model = std::get<0>(member->components); | |||||
scene->removeObject(&model->model); | |||||
} | |||||
@ -0,0 +1,55 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef RENDER_SYSTEM_HPP | |||||
#define RENDER_SYSTEM_HPP | |||||
#include "../components/model-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../entity-group.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<ModelComponent, TransformComponent> ModelEntityGroup; | |||||
/** | |||||
* Abstract base class for entity systems. | |||||
*/ | |||||
class RenderSystem: public | |||||
System, | |||||
ModelEntityGroup::Observer | |||||
{ | |||||
public: | |||||
RenderSystem(ComponentManager* componentManager, SceneLayer* scene); | |||||
virtual ~RenderSystem(); | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
ModelEntityGroup modelEntityGroup; | |||||
SceneLayer* scene; | |||||
virtual void memberRegistered(const ModelEntityGroup::Member* member); | |||||
virtual void memberUnregistered(const ModelEntityGroup::Member* member); | |||||
}; | |||||
#endif // RENDER_SYSTEM_HPP | |||||
@ -0,0 +1,119 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "sound-system.hpp" | |||||
#include <stdexcept> | |||||
#include "dr_libs/dr_wav.h" | |||||
SoundSystem::SoundSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
entityGroup(componentManager), | |||||
device(nullptr), | |||||
context(nullptr) | |||||
{ | |||||
device = alcOpenDevice(nullptr); | |||||
if (!device) | |||||
{ | |||||
throw std::runtime_error("SoundSystem::SoundSystem(): Failed to open audio device."); | |||||
} | |||||
context = alcCreateContext(device, nullptr); | |||||
if (!alcMakeContextCurrent(context)) | |||||
{ | |||||
throw std::runtime_error("SoundSystem::SoundSystem(): Failed to create audio context."); | |||||
} | |||||
ALfloat listenerOrientation[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f }; | |||||
alListener3f(AL_POSITION, 0.0f, 0.0f, 1.0f); | |||||
alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f); | |||||
alListenerfv(AL_ORIENTATION, listenerOrientation); | |||||
alGenSources((ALuint)1, &source); | |||||
alSourcef(source, AL_PITCH, 1); | |||||
alSourcef(source, AL_GAIN, 1); | |||||
alSource3f(source, AL_POSITION, 0, 0, 0); | |||||
alSource3f(source, AL_VELOCITY, 0, 0, 0); | |||||
alSourcei(source, AL_LOOPING, AL_FALSE); | |||||
alGenBuffers((ALuint)1, &buffer); | |||||
// Load wav file | |||||
{ | |||||
const char* filename = "/home/cjhoward/projects/antkeeper/modules/antkeeper-data/sounds/shutter.wav"; | |||||
unsigned int channels; | |||||
unsigned int sampleRate; | |||||
drwav_uint64 frameCount; | |||||
std::int16_t* sampleData = drwav_open_file_and_read_pcm_frames_s16(filename, &channels, &sampleRate, &frameCount); | |||||
if (sampleData == nullptr) | |||||
{ | |||||
throw std::runtime_error("Couldn't load wav file"); | |||||
drwav_free(sampleData); | |||||
} | |||||
bool stereo = (channels > 1); | |||||
ALenum format = (stereo) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16; | |||||
std::size_t sampleCount = frameCount * channels; | |||||
std::size_t sampleDataSize = sampleCount * sizeof(drwav_int16); | |||||
alBufferData(buffer, format, sampleData, sampleDataSize, sampleRate); | |||||
} | |||||
alSourcei(source, AL_BUFFER, buffer); | |||||
//alSourcePlay(source); | |||||
} | |||||
SoundSystem::~SoundSystem() | |||||
{ | |||||
alDeleteSources(1, &source); | |||||
alDeleteBuffers(1, &buffer); | |||||
alcMakeContextCurrent(nullptr); | |||||
alcDestroyContext(context); | |||||
alcCloseDevice(device); | |||||
} | |||||
void SoundSystem::scrot() | |||||
{ | |||||
alSourcePlay(source); | |||||
} | |||||
void SoundSystem::update(float t, float dt) | |||||
{ | |||||
auto members = entityGroup.getMembers(); | |||||
for (const SoundSourceEntityGroup::Member* member: *members) | |||||
{ | |||||
TransformComponent* transform = std::get<0>(member->components); | |||||
SoundSourceComponent* sound = std::get<1>(member->components); | |||||
} | |||||
} | |||||
void SoundSystem::memberRegistered(const SoundSourceEntityGroup::Member* member) | |||||
{ | |||||
TransformComponent* transform = std::get<0>(member->components); | |||||
SoundSourceComponent* sound = std::get<1>(member->components); | |||||
} | |||||
void SoundSystem::memberUnregistered(const SoundSourceEntityGroup::Member* member) | |||||
{ | |||||
TransformComponent* transform = std::get<0>(member->components); | |||||
SoundSourceComponent* sound = std::get<1>(member->components); | |||||
} | |||||
@ -0,0 +1,56 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef SOUND_SYSTEM_HPP | |||||
#define SOUND_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../system.hpp" | |||||
#include "../components/sound-source-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include <AL/al.h> | |||||
#include <AL/alc.h> | |||||
typedef EntityGroup<TransformComponent, SoundSourceComponent> SoundSourceEntityGroup; | |||||
class SoundSystem: | |||||
public System, | |||||
public SoundSourceEntityGroup::Observer | |||||
{ | |||||
public: | |||||
SoundSystem(ComponentManager* componentManager); | |||||
virtual ~SoundSystem(); | |||||
virtual void update(float t, float dt); | |||||
void scrot(); | |||||
private: | |||||
virtual void memberRegistered(const SoundSourceEntityGroup::Member* member); | |||||
virtual void memberUnregistered(const SoundSourceEntityGroup::Member* member); | |||||
SoundSourceEntityGroup entityGroup; | |||||
ALCdevice* device; | |||||
ALCcontext* context; | |||||
ALuint source; | |||||
ALuint buffer; | |||||
}; | |||||
#endif // SOUND_SYSTEM_HPP | |||||
@ -0,0 +1,96 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "steering-system.hpp" | |||||
SteeringSystem::SteeringSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
boids(componentManager) | |||||
{ | |||||
boids.addGroupObserver(this); | |||||
} | |||||
SteeringSystem::~SteeringSystem() | |||||
{} | |||||
void SteeringSystem::update(float t, float dt) | |||||
{ | |||||
auto members = boids.getMembers(); | |||||
for (const SteeringGroup::Member* member: *members) | |||||
{ | |||||
SteeringComponent* steering = std::get<0>(member->components); | |||||
// Initialize summed steering force | |||||
steering->force = Vector3(0.0f); | |||||
steering->speed = 0.0f; | |||||
float speedSquared = 0.0f; | |||||
float maxSpeedSquared = steering->maxSpeed * steering->maxSpeed; | |||||
bool truncated = false; | |||||
if (steering->behaviorCount > 0) | |||||
{ | |||||
// Sort steering beaviors by priority | |||||
std::sort(steering->behaviors, steering->behaviors + steering->behaviorCount, | |||||
[](const SteeringBehavior& a, const SteeringBehavior& b) -> bool | |||||
{ | |||||
return (a.priority >= b.priority); | |||||
} | |||||
); | |||||
} | |||||
// Evaluate steering forces in order | |||||
for (std::size_t i = 0; i < steering->behaviorCount; ++i) | |||||
{ | |||||
const SteeringBehavior& behavior = steering->behaviors[i]; | |||||
// Skip zero-weighted steering behaviors | |||||
if (behavior.weight == 0.0f) | |||||
{ | |||||
continue; | |||||
} | |||||
// Add weighted steering behavior force | |||||
steering->force += behavior.function() * behavior.weight; | |||||
// Limit speed | |||||
speedSquared = glm::length2(steering->force); | |||||
if (speedSquared >= maxSpeedSquared) | |||||
{ | |||||
steering->force *= (1.0f / std::sqrt(speedSquared)) * steering->maxSpeed; | |||||
steering->speed = steering->maxSpeed; | |||||
truncated = true; | |||||
break; | |||||
} | |||||
} | |||||
if (!truncated) | |||||
{ | |||||
steering->speed = std::sqrt(speedSquared); | |||||
} | |||||
} | |||||
} | |||||
void SteeringSystem::memberRegistered(const SteeringGroup::Member* member) | |||||
{} | |||||
void SteeringSystem::memberUnregistered(const SteeringGroup::Member* member) | |||||
{} | |||||
@ -0,0 +1,53 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef STEERING_SYSTEM_HPP | |||||
#define STEERING_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/steering-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<SteeringComponent> SteeringGroup; | |||||
class SteeringSystem: public | |||||
System, | |||||
SteeringGroup::Observer | |||||
{ | |||||
public: | |||||
SteeringSystem(ComponentManager* componentManager); | |||||
virtual ~SteeringSystem(); | |||||
/** | |||||
* Calculates the steering force for each steering component using weighted truncated running sums with prioritization. | |||||
*/ | |||||
virtual void update(float t, float dt); | |||||
private: | |||||
SteeringGroup boids; | |||||
virtual void memberRegistered(const SteeringGroup::Member* member); | |||||
virtual void memberUnregistered(const SteeringGroup::Member* member); | |||||
}; | |||||
#endif // STEERING_SYSTEM_HPP | |||||
@ -0,0 +1,96 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "tool-system.hpp" | |||||
ToolSystem::ToolSystem(ComponentManager* componentManager): | |||||
System(componentManager), | |||||
tools(componentManager), | |||||
picked(false) | |||||
{ | |||||
tools.addGroupObserver(this); | |||||
} | |||||
ToolSystem::~ToolSystem() | |||||
{} | |||||
void ToolSystem::update(float t, float dt) | |||||
{ | |||||
pick(); | |||||
auto members = tools.getMembers(); | |||||
for (const ToolGroup::Member* member: *members) | |||||
{ | |||||
ModelComponent* model = std::get<0>(member->components); | |||||
ToolComponent* tool = std::get<1>(member->components); | |||||
TransformComponent* transform = std::get<2>(member->components); | |||||
model->model.setActive(tool->active); | |||||
if (picked) | |||||
{ | |||||
transform->transform.translation = mouseWorldPosition; | |||||
} | |||||
} | |||||
picked = false; | |||||
} | |||||
void ToolSystem::setPickingCamera(const Camera* camera) | |||||
{ | |||||
pickingCamera = camera; | |||||
} | |||||
void ToolSystem::setPickingViewport(const Vector4& viewport) | |||||
{ | |||||
pickingViewport = viewport; | |||||
} | |||||
void ToolSystem::pick() | |||||
{ | |||||
Vector3 mouseNear = pickingCamera->unproject(Vector3(mouseScreenPosition, 0.0f), pickingViewport); | |||||
Vector3 mouseFar = pickingCamera->unproject(Vector3(mouseScreenPosition, 1.0f), pickingViewport); | |||||
Ray pickingRay; | |||||
pickingRay.origin = mouseNear; | |||||
pickingRay.direction = glm::normalize(mouseFar - mouseNear); | |||||
Plane pickingPlane(Vector3(0.0f, 1.0f, 0.0f), Vector3(0.0f)); | |||||
auto pickingIntersection = pickingRay.intersects(pickingPlane); | |||||
picked = std::get<0>(pickingIntersection); | |||||
if (picked) | |||||
{ | |||||
mouseWorldPosition = pickingRay.extrapolate(std::get<1>(pickingIntersection)); | |||||
} | |||||
} | |||||
void ToolSystem::memberRegistered(const ToolGroup::Member* member) | |||||
{ | |||||
ToolComponent* tool = std::get<1>(member->components); | |||||
tool->active = false; | |||||
} | |||||
void ToolSystem::memberUnregistered(const ToolGroup::Member* member) | |||||
{} | |||||
void ToolSystem::handleEvent(const MouseMovedEvent& event) | |||||
{ | |||||
mouseScreenPosition = Vector2(event.x, pickingViewport[3] - event.y); | |||||
} | |||||
@ -0,0 +1,66 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef TOOL_SYSTEM_HPP | |||||
#define TOOL_SYSTEM_HPP | |||||
#include "../entity-group.hpp" | |||||
#include "../components/model-component.hpp" | |||||
#include "../components/tool-component.hpp" | |||||
#include "../components/transform-component.hpp" | |||||
#include "../system.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
typedef EntityGroup<ModelComponent, ToolComponent, TransformComponent> ToolGroup; | |||||
/** | |||||
* Abstract base class for entity systems. | |||||
*/ | |||||
class ToolSystem: | |||||
public System, | |||||
public ToolGroup::Observer, | |||||
public EventHandler<MouseMovedEvent> | |||||
{ | |||||
public: | |||||
ToolSystem(ComponentManager* componentManager); | |||||
virtual ~ToolSystem(); | |||||
virtual void update(float t, float dt); | |||||
void setPickingCamera(const Camera* camera); | |||||
void setPickingViewport(const Vector4& viewport); | |||||
private: | |||||
void pick(); | |||||
virtual void memberRegistered(const ToolGroup::Member* member); | |||||
virtual void memberUnregistered(const ToolGroup::Member* member); | |||||
virtual void handleEvent(const MouseMovedEvent& event); | |||||
Vector2 mouseScreenPosition; | |||||
Vector3 mouseWorldPosition; | |||||
const Camera* pickingCamera; | |||||
Vector4 pickingViewport; | |||||
bool picked; | |||||
ToolGroup tools; | |||||
}; | |||||
#endif // TOOL_SYSTEM_HPP | |||||
@ -0,0 +1,404 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef GAME_HPP | |||||
#define GAME_HPP | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
#include "entity/entity-id.hpp" | |||||
#include <map> | |||||
#include <string> | |||||
#include <vector> | |||||
class GameState; | |||||
class SplashState; | |||||
class SandboxState; | |||||
class UIContainer; | |||||
class UIBatcher; | |||||
class UIImage; | |||||
class UILabel; | |||||
class UIRenderPass; | |||||
class ClearRenderPass; | |||||
class SkyRenderPass; | |||||
class ShadowMapRenderPass; | |||||
class LightingRenderPass; | |||||
class SilhouetteRenderPass; | |||||
class FinalRenderPass; | |||||
class ResourceManager; | |||||
typedef std::vector<std::vector<std::string>> CSVTable; | |||||
class CameraRig; | |||||
class OrbitCam; | |||||
class FreeCam; | |||||
class Tool; | |||||
class Lens; | |||||
class Forceps; | |||||
class Brush; | |||||
class ParticleSystem; | |||||
class EntityManager; | |||||
class ComponentManager; | |||||
class SystemManager; | |||||
class SoundSystem; | |||||
class CollisionSystem; | |||||
class RenderSystem; | |||||
class ToolSystem; | |||||
class BehaviorSystem; | |||||
class SteeringSystem; | |||||
class LocomotionSystem; | |||||
class TestEvent: public Event<TestEvent> | |||||
{ | |||||
public: | |||||
inline EventBase* clone() const | |||||
{ | |||||
TestEvent* event = new TestEvent(); | |||||
event->id = id; | |||||
return event; | |||||
} | |||||
int id; | |||||
}; | |||||
class Game: | |||||
public Application, | |||||
public EventHandler<TestEvent> | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates a game instance. | |||||
* | |||||
* @param argc Argument count | |||||
* @param argv Argument list | |||||
*/ | |||||
Game(int argc, char* argv[]); | |||||
/// Destroys a game instance. | |||||
virtual ~Game(); | |||||
/** | |||||
* Gets a string in the specified language. | |||||
* | |||||
* @param languageIndex Index of a language. | |||||
* @param name Name of the string. | |||||
* @return String in the specified language. | |||||
*/ | |||||
std::string getString(std::size_t languageIndex, const std::string& name) const; | |||||
/** | |||||
* Changes the current language. | |||||
* | |||||
* @param languageIndex Index of the language to use. | |||||
*/ | |||||
void changeLanguage(std::size_t languageIndex); | |||||
/// Returns the number of available languages. | |||||
std::size_t getLanguageCount() const; | |||||
/// Returns the index of the current language. | |||||
std::size_t getCurrentLanguage() const; | |||||
void toggleFullscreen(); | |||||
void setUpdateRate(double frequency); | |||||
/** | |||||
* Changes the game state. | |||||
* | |||||
* @param state New game state. | |||||
*/ | |||||
void changeState(GameState* state); | |||||
const EventDispatcher* getEventDispatcher() const; | |||||
EventDispatcher* getEventDispatcher(); | |||||
const Animator* getAnimator() const; | |||||
Animator* getAnimator(); | |||||
void fadeIn(float duration, const Vector3& color, std::function<void()> callback); | |||||
void fadeOut(float duration, const Vector3& color, std::function<void()> callback); | |||||
void selectTool(int toolIndex); | |||||
void pushNotification(const std::string& text); | |||||
void popNotification(); | |||||
private: | |||||
virtual void setup(); | |||||
virtual void input(); | |||||
virtual void update(float t, float dt); | |||||
virtual void render(); | |||||
virtual void exit(); | |||||
virtual void handleEvent(const WindowResizedEvent& event); | |||||
virtual void handleEvent(const KeyPressedEvent& event); | |||||
virtual void handleEvent(const TestEvent& event); | |||||
void resizeUI(int w, int h); | |||||
void restringUI(); | |||||
void resizeRenderTargets(); | |||||
void setTimeOfDay(float time); | |||||
void toggleWireframe(); | |||||
void screenshot(); | |||||
void queueScreenshot(); | |||||
public: | |||||
EntityID createInstanceOf(const std::string& templateName); | |||||
void destroyInstance(EntityID entity); | |||||
void setTranslation(EntityID entity, const Vector3& translation); | |||||
void setRotation(EntityID entity, const Quaternion& rotation); | |||||
void setScale(EntityID entity, const Vector3& scale); | |||||
void boxSelect(float x, float y, float w, float h); | |||||
public: | |||||
// States | |||||
GameState* currentState; | |||||
SplashState* splashState; | |||||
SandboxState* sandboxState; | |||||
// Paths | |||||
std::string dataPath; | |||||
std::string configPath; | |||||
// Localization | |||||
CSVTable* stringTable; | |||||
std::map<std::string, std::size_t> stringMap; | |||||
std::size_t languageCount; | |||||
std::size_t currentLanguage; | |||||
// Window management | |||||
Window* window; | |||||
bool fullscreen; | |||||
std::string title; | |||||
int w, h; | |||||
float dpi; | |||||
float fontSizePT; | |||||
float fontSizePX; | |||||
// Input | |||||
Mouse* mouse; | |||||
Keyboard* keyboard; | |||||
ControlProfile controlProfile; | |||||
Control fullscreenControl; | |||||
Control closeControl; | |||||
Control openRadialMenuControl; | |||||
Control moveForwardControl; | |||||
Control moveBackControl; | |||||
Control moveLeftControl; | |||||
Control moveRightControl; | |||||
Control rotateCCWControl; | |||||
Control rotateCWControl; | |||||
Control zoomInControl; | |||||
Control zoomOutControl; | |||||
Control adjustCameraControl; | |||||
Control dragCameraControl; | |||||
Control toggleNestViewControl; | |||||
Control toggleWireframeControl; | |||||
Control screenshotControl; | |||||
Control toggleEditModeControl; | |||||
// Logic | |||||
float time; | |||||
float timestep; | |||||
// UI | |||||
Typeface* labelTypeface; | |||||
Font* labelFont; | |||||
Typeface* debugTypeface; | |||||
Font* debugFont; | |||||
BillboardBatch* uiBatch; | |||||
UIBatcher* uiBatcher; | |||||
UIContainer* uiRootElement; | |||||
UIImage* splashBackgroundImage; | |||||
UIImage* splashImage; | |||||
UIContainer* hudContainer; | |||||
UIImage* toolIndicatorBGImage; | |||||
UIImage* toolIndicatorIconImage; | |||||
Rect* toolIndicatorsBounds; | |||||
UIImage* toolIconBrushImage; | |||||
UIImage* toolIconLensImage; | |||||
UIImage* toolIconForcepsImage; | |||||
UIImage* toolIconSpadeImage; | |||||
UIImage* toolIconCameraImage; | |||||
UIImage* toolIconTestTubeImage; | |||||
UIContainer* buttonContainer; | |||||
UIImage* playButtonBGImage; | |||||
UIImage* fastForwardButtonBGImage; | |||||
UIImage* pauseButtonBGImage; | |||||
UIImage* playButtonImage; | |||||
UIImage* fastForwardButtonImage; | |||||
UIImage* pauseButtonImage; | |||||
UIContainer* radialMenuContainer; | |||||
UIImage* radialMenuBackgroundImage; | |||||
UIImage* radialMenuImage; | |||||
UIImage* radialMenuSelectorImage; | |||||
UIImage* blackoutImage; | |||||
UIImage* cameraFlashImage; | |||||
UIImage* notificationBoxImage; | |||||
int notificationCount; | |||||
UIContainer* antTag; | |||||
UIContainer* antLabelContainer; | |||||
UILabel* fpsLabel; | |||||
UILabel* antLabel; | |||||
UIImage* antLabelTL; // Top-left | |||||
UIImage* antLabelTR; // Top-right | |||||
UIImage* antLabelBL; // Bottom-left | |||||
UIImage* antLabelBR; // Bottom-right | |||||
UIImage* antLabelCC; // Center-center | |||||
UIImage* antLabelCT; // Center-top | |||||
UIImage* antLabelCB; // Center-bottom | |||||
UIImage* antLabelCL; // Center-left | |||||
UIImage* antLabelCR; // Center-right | |||||
UIImage* antLabelPinHole; | |||||
UIImage* antPin; | |||||
UIImage* boxSelectionImageBackground; | |||||
UIImage* boxSelectionImageTop; | |||||
UIImage* boxSelectionImageBottom; | |||||
UIImage* boxSelectionImageLeft; | |||||
UIImage* boxSelectionImageRight; | |||||
UIContainer* boxSelectionContainer; | |||||
float boxSelectionBorderWidth; | |||||
UIImage* cameraGridY0Image; | |||||
UIImage* cameraGridY1Image; | |||||
UIImage* cameraGridX0Image; | |||||
UIImage* cameraGridX1Image; | |||||
UIContainer* cameraGridContainer; | |||||
Vector4 cameraGridColor; | |||||
// Rendering | |||||
Renderer renderer; | |||||
RenderTarget defaultRenderTarget; | |||||
ClearRenderPass* clearPass; | |||||
ClearRenderPass* clearSilhouettePass; | |||||
SkyRenderPass* skyPass; | |||||
UIRenderPass* uiPass; | |||||
Compositor uiCompositor; | |||||
Compositor defaultCompositor; | |||||
int shadowMapResolution; | |||||
GLuint shadowMapDepthTextureID; | |||||
GLuint shadowMapFramebuffer; | |||||
RenderTarget shadowMapRenderTarget; | |||||
ShadowMapRenderPass* shadowMapPass; | |||||
Compositor shadowMapCompositor; | |||||
Texture2D shadowMapDepthTexture; | |||||
LightingRenderPass* lightingPass; | |||||
SilhouetteRenderPass* silhouettePass; | |||||
FinalRenderPass* finalPass; | |||||
RenderTarget silhouetteRenderTarget; | |||||
// Scene | |||||
Scene* scene; | |||||
SceneLayer* defaultLayer; | |||||
SceneLayer* uiLayer; | |||||
DirectionalLight sunlight; | |||||
Camera camera; | |||||
Camera sunlightCamera; | |||||
Camera uiCamera; | |||||
// Animation | |||||
Animator animator; | |||||
Animation<float> fadeInAnimation; | |||||
Animation<float> fadeOutAnimation; | |||||
AnimationClip<float> fadeInClip; | |||||
AnimationClip<float> fadeOutClip; | |||||
std::function<void()> fadeInEndCallback; | |||||
std::function<void()> fadeOutEndCallback; | |||||
Animation<Vector2> showNotificationAnimation; | |||||
Animation<float> hideNotificationAnimation; | |||||
AnimationClip<Vector2> showNotificationClip; | |||||
AnimationClip<float> hideNotificationClip; | |||||
Animation<float> cameraFlashAnimation; | |||||
AnimationClip<float> cameraFlashClip; | |||||
// Assets | |||||
ResourceManager* resourceManager; | |||||
Texture2D* splashTexture; | |||||
Texture2D* hudSpriteSheetTexture; | |||||
TextureAtlas hudTextureAtlas; | |||||
Material* smokeMaterial; | |||||
Model* lensModel; | |||||
Model* forcepsModel; | |||||
Model* brushModel; | |||||
// Game | |||||
CameraRig* cameraRig; | |||||
OrbitCam* orbitCam; | |||||
FreeCam* freeCam; | |||||
Tool* currentTool; | |||||
Lens* lens; | |||||
Forceps* forceps; | |||||
Brush* brush; | |||||
ParticleSystem* particleSystem; | |||||
// ECS | |||||
EntityManager* entityManager; | |||||
ComponentManager* componentManager; | |||||
SystemManager* systemManager; | |||||
SoundSystem* soundSystem; | |||||
CollisionSystem* collisionSystem; | |||||
RenderSystem* renderSystem; | |||||
ToolSystem* toolSystem; | |||||
BehaviorSystem* behaviorSystem; | |||||
SteeringSystem* steeringSystem; | |||||
LocomotionSystem* locomotionSystem; | |||||
EntityID lollipop; | |||||
bool wireframe; | |||||
bool screenshotQueued; | |||||
private: | |||||
static void saveScreenshot(const std::string& filename, unsigned int width, unsigned int height, unsigned char* pixels); | |||||
}; | |||||
inline const EventDispatcher* Game::getEventDispatcher() const | |||||
{ | |||||
return &eventDispatcher; | |||||
} | |||||
inline EventDispatcher* Game::getEventDispatcher() | |||||
{ | |||||
return &eventDispatcher; | |||||
} | |||||
inline const Animator* Game::getAnimator() const | |||||
{ | |||||
return &animator; | |||||
} | |||||
inline Animator* Game::getAnimator() | |||||
{ | |||||
return &animator; | |||||
} | |||||
inline std::size_t Game::getLanguageCount() const | |||||
{ | |||||
return languageCount; | |||||
} | |||||
inline std::size_t Game::getCurrentLanguage() const | |||||
{ | |||||
return currentLanguage; | |||||
} | |||||
#endif // GAME_HPP | |||||
@ -1,222 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#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), | |||||
//velocity(0.0f) | |||||
{} | |||||
/* | |||||
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 = position + forward * wanderCircleDistance; | |||||
// Calculate wander force | |||||
Vector3 target = 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 seek(target); | |||||
} | |||||
Vector3 Agent::seek(const Vector3& target) const | |||||
{ | |||||
Vector3 desiredVelocity = glm::normalize(target - position) * maxSpeed; | |||||
return desiredVelocity - velocity; | |||||
} | |||||
Vector3 Agent::flee(const Vector3& target) const | |||||
{ | |||||
Vector3 desiredVelocity = glm::normalize(position - target) * maxSpeed; | |||||
return desiredVelocity - velocity; | |||||
} | |||||
Vector3 Agent::containment(const Vector3& probe) const | |||||
{ | |||||
std::vector<Navmesh::Step> 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 difference between probe position and position on edge | |||||
//Vector3 end = cartesian(step.end, | |||||
// step.triangle->edge->vertex->position, | |||||
// step.triangle->edge->next->vertex->position, | |||||
// step.triangle->edge->previous->vertex->position); | |||||
//Vector3 difference = probe - end; | |||||
//float depth = 0.0f; | |||||
//if (nonzero(difference)) | |||||
//{ | |||||
// depth = glm::length(difference); | |||||
//} | |||||
// 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 reflection = glm::reflect(forward, edgeNormal); | |||||
//Vector3 target = cartesian(step.end, | |||||
// step.triangle->edge->vertex->position, | |||||
// step.triangle->edge->next->vertex->position, | |||||
// step.triangle->edge->previous->vertex->position) + reflection * 0.1f; | |||||
//std::cout << "reflection: " << reflection.x << ", " << reflection.y << ", " << reflection.z << std::endl; | |||||
return edgeNormal; | |||||
} | |||||
Vector3 Agent::separation(const std::list<Agent*>& neighbors) const | |||||
{ | |||||
Vector3 force(0.0f); | |||||
for (Agent* neighbor: neighbors) | |||||
{ | |||||
Vector3 difference = position - neighbor->position; | |||||
float distanceSquared = glm::dot(difference, difference); | |||||
if (distanceSquared > 0.0f && distanceSquared < separationRadiusSquared) | |||||
{ | |||||
force += difference * (1.0f / distanceSquared); | |||||
} | |||||
} | |||||
if (nonzero(force)) | |||||
{ | |||||
force = glm::normalize(force); | |||||
} | |||||
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::setMaxSpeed(float speed) | |||||
{ | |||||
maxSpeed = speed; | |||||
} | |||||
void Agent::setVelocity(const Vector3& velocity) | |||||
{ | |||||
this->velocity = velocity; | |||||
} | |||||
void Agent::setWanderCircleDistance(float distance) | |||||
{ | |||||
wanderCircleDistance = distance; | |||||
} | |||||
void Agent::setWanderCircleRadius(float radius) | |||||
{ | |||||
wanderCircleRadius = radius; | |||||
} | |||||
void Agent::setWanderRate(float angle) | |||||
{ | |||||
wanderRate = angle; | |||||
} | |||||
void Agent::setSeparationRadius(float radius) | |||||
{ | |||||
separationRadius = radius; | |||||
separationRadiusSquared = separationRadius * separationRadius; | |||||
} | |||||
*/ | |||||
/** EXAMPLE USAGE | |||||
Vector3 wanderForce = wander(dt) * wanderWeight; | |||||
Vector3 fleeForce = flee(mouse) * fleeWeight; | |||||
Vector3 steerForce = wanderForce + fleeForce; | |||||
steer(steerForce); | |||||
**/ |
@ -1,216 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef AGENT_HPP | |||||
#define AGENT_HPP | |||||
#include "navmesh.hpp" | |||||
#include <vector> | |||||
#include <emergent/emergent.hpp> | |||||
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; | |||||
//Vector3 separation(const std::list<Agent*>& neighbors) const; | |||||
//Vector3 forage(const Vector3& leftProbe, const Vector3& rightProbe); | |||||
/* | |||||
void setMaxSpeed(float speed); | |||||
void setVelocity(const Vector3& velocity); | |||||
void setMaxAcceleration(float acceleration); | |||||
void setMass(float mass); | |||||
void setWanderCircleDistance(float distance); | |||||
void setWanderCircleRadius(float radius); | |||||
void setWanderRate(float angle); | |||||
void setSeparationRadius(float radius); | |||||
*/ | |||||
/** | |||||
* 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 alignment(const std::vector<const Agent*>* neighbors); | |||||
Vector3 cohesion(const std::vector<const Agent*>* 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; | |||||
//const Vector3& getVelocity() 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; | |||||
float separationRadius; | |||||
float separationRadiusSquared; | |||||
*/ | |||||
}; | |||||
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; | |||||
} | |||||
/* | |||||
inline const Vector3& Agent::getVelocity() const | |||||
{ | |||||
return velocity; | |||||
} | |||||
*/ | |||||
#endif // AGENT_HPP |
@ -1,293 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "ant.hpp" | |||||
#include "colony.hpp" | |||||
#include "pheromone-matrix.hpp" | |||||
#include <cmath> | |||||
float FRAMES_PER_SECOND = 60; | |||||
float TIMESTEP = 1.0f / FRAMES_PER_SECOND; | |||||
float ANT_LENGTH = 0.5f; // 0.5 cm, head to abdomen (not including legs / antennae) | |||||
float ANT_COLLISION_RADIUS = ANT_LENGTH * 1.25f; | |||||
float RECEPTOR_RADIUS = 0.4f; | |||||
float RECEPTOR_SEPARATION = 0.882f; | |||||
float RECEPTOR_DISTANCE = 0.588f; | |||||
float MOUTH_DISTANCE = 0.2646f; | |||||
float BITE_RADIUS = 0.0294f; | |||||
float FOOD_PARTICLE_RADIUS = 0.1176f; | |||||
float MAX_RECEPTOR_NOISE = 0.05f; // essentially an epsilon | |||||
float MAX_EXCITEMENT = 1.0f; | |||||
float MAX_PHEROMONE_TURNING_ANGLE = glm::radians(8.5f); | |||||
float MIN_WALK_TIME = 0.5f; // seconds | |||||
float MAX_WALK_TIME = 8.0f; // seconds | |||||
float MIN_REST_TIME = 0.15f; | |||||
float MAX_REST_TIME = 0.7f; | |||||
float MIN_CHEW_TIME = 0.25f; | |||||
float MAX_CHEW_TIME = 0.5f; | |||||
float DEEXCITEMENT_FACTOR = 0.999f; // This should probably always be less than the evaporation factor | |||||
float CALM_FACTOR = 0.995f; | |||||
float MAX_WALK_FORCE = 1.5; | |||||
float MAX_PANIC_FORCE = 0.1029f; | |||||
float MAX_WALK_SPEED = 3.0f; // cm/s | |||||
float MAX_PANIC_SPEED = 8.82f; // cm/s | |||||
float PANIC_RADIUS = 7.35f; | |||||
float WANDER_CIRCLE_DISTANCE = 0.441f; | |||||
float WANDER_CIRCLE_RADIUS = 0.0294f; | |||||
float MAX_WANDER_ANGLE = 0.15f; | |||||
inline float fwrap(float angle, float limit) | |||||
{ | |||||
return angle - std::floor(angle / limit) * limit; | |||||
} | |||||
Ant::Ant(Colony* colony): | |||||
colony(colony), | |||||
state(Ant::State::IDLE), | |||||
transform(Transform::getIdentity()), | |||||
pose(nullptr) | |||||
{ | |||||
pose = new Pose(colony->getAntModel()->getSkeleton()); | |||||
pose->reset(); | |||||
pose->concatenate(); | |||||
modelInstance.setModel(colony->getAntModel()); | |||||
modelInstance.setPose(pose); | |||||
animationTime = frand(0.0f, 60.0f); | |||||
velocity = Vector3(0); | |||||
acceleration = Vector3(0); | |||||
wanderDirection = getForward(); | |||||
excitement = MAX_EXCITEMENT; | |||||
} | |||||
Ant::~Ant() | |||||
{ | |||||
delete pose; | |||||
} | |||||
void Ant::animate() | |||||
{ | |||||
colony->getTripodGaitAnimation()->animate(pose, animationTime); | |||||
pose->concatenate(); | |||||
animationTime = fwrap(animationTime + 4.0f, colony->getTripodGaitAnimation()->getEndTime()); | |||||
} | |||||
void Ant::suspend(const Vector3& suspensionPoint, const Quaternion& suspensionRotation) | |||||
{ | |||||
transform.translation = suspensionPoint; | |||||
transform.rotation = suspensionRotation; | |||||
modelInstance.setTransform(transform); | |||||
} | |||||
void Ant::move(const Vector3& velocity) | |||||
{ | |||||
std::vector<Navmesh::Step> 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) | |||||
{ | |||||
float probeLateralOffset = 0.1f; | |||||
float probeForwardOffset = 0.3f; | |||||
animate(); | |||||
// Calculate positions of receptors | |||||
receptorL = getPosition() + getForward() * RECEPTOR_DISTANCE; | |||||
receptorR = receptorL; | |||||
receptorL -= getRight() * RECEPTOR_SEPARATION * 0.5f; | |||||
receptorR += getRight() * RECEPTOR_SEPARATION * 0.5f; | |||||
// Steering | |||||
if (state == Ant::State::WANDER) | |||||
{ | |||||
//setWanderCircleDistance(4.0f); | |||||
//setWanderCircleRadius(0.3f); | |||||
//setWanderRate(glm::radians(90.0f)); | |||||
//setSeparationRadius(0.5f); | |||||
//setMaxSpeed(0.025f); | |||||
// Calculate wander force | |||||
Vector3 wanderForce = wander() * 1.5f; | |||||
Vector3 followForce = follow() * 3.0f; | |||||
// Setup containment probes | |||||
//Vector3 leftProbe = getForward() * probeForwardOffset - getRight() * probeLateralOffset; | |||||
//Vector3 rightProbe = getForward() * probeForwardOffset + getRight() * probeLateralOffset; | |||||
// Calculate containment force | |||||
//Vector3 containmentForce = containment(leftProbe) + containment(rightProbe); | |||||
// Determine neighbors | |||||
//float neighborhoodSize = 2.0f; | |||||
//AABB neighborhoodAABB(getPosition() - Vector3(neighborhoodSize * 0.5f), getPosition() + Vector3(neighborhoodSize * 0.5f)); | |||||
//std::list<Agent*> neighbors; | |||||
//colony->queryAnts(neighborhoodAABB, &neighbors); | |||||
// Calculate separation force | |||||
//Vector3 separationForce = separation(neighbors); | |||||
applyForce(wanderForce); | |||||
applyForce(followForce); | |||||
float maxSpeed = MAX_WALK_SPEED * TIMESTEP; | |||||
// Limit acceleration | |||||
float accelerationMagnitudeSquared = glm::dot(acceleration, acceleration); | |||||
if (accelerationMagnitudeSquared > MAX_WALK_FORCE * MAX_WALK_FORCE) | |||||
{ | |||||
acceleration = glm::normalize(acceleration) * MAX_WALK_FORCE; | |||||
} | |||||
// Accelerate | |||||
velocity += acceleration; | |||||
// Limit speed | |||||
float speedSquared = glm::dot(velocity, velocity); | |||||
if (speedSquared > maxSpeed * maxSpeed) | |||||
{ | |||||
velocity = glm::normalize(velocity) * maxSpeed; | |||||
} | |||||
Vector3 direction = glm::normalize(velocity); | |||||
setOrientation(direction, getUp()); | |||||
// Deposit pheromones | |||||
Vector2 position2D = Vector2(getPosition().x, getPosition().z); | |||||
colony->getHomingMatrix()->deposit(position2D, excitement); | |||||
excitement *= DEEXCITEMENT_FACTOR; | |||||
// Move ant | |||||
move(velocity); | |||||
} | |||||
else if (state == Ant::State::IDLE) | |||||
{ | |||||
velocity = Vector3(0.0f); | |||||
// Move ant | |||||
move(velocity); | |||||
} | |||||
// Update transform | |||||
if (state == Ant::State::WANDER || state == Ant::State::IDLE) | |||||
{ | |||||
transform.translation = getPosition(); | |||||
transform.rotation = getRotation(); | |||||
// Update model instance | |||||
modelInstance.setTransform(transform); | |||||
} | |||||
} | |||||
void Ant::setState(Ant::State state) | |||||
{ | |||||
this->state = state; | |||||
} | |||||
Vector3 Ant::seek(const Vector3& target) | |||||
{ | |||||
Vector3 steer(0.0f); | |||||
Vector3 difference = target - getPosition(); | |||||
float distanceSquared = glm::dot(difference, difference); | |||||
if (distanceSquared > 0.0f) | |||||
{ | |||||
float maxForce = MAX_WALK_FORCE; | |||||
steer = glm::normalize(difference) * maxForce - velocity; | |||||
} | |||||
return steer; | |||||
} | |||||
Vector3 Ant::flee(const Vector3& target) | |||||
{ | |||||
return -seek(target); | |||||
} | |||||
Vector3 Ant::wander() | |||||
{ | |||||
// Determine center of wander circle | |||||
Vector3 center = getPosition() + getForward() * WANDER_CIRCLE_DISTANCE; | |||||
// Calculate wander target | |||||
Vector3 target = center + wanderDirection * WANDER_CIRCLE_RADIUS; | |||||
// Rotate wander direction by a random displacement angle | |||||
float displacement = frand(-MAX_WANDER_ANGLE, MAX_WANDER_ANGLE); | |||||
wanderDirection = glm::normalize(glm::angleAxis(displacement, getUp()) * wanderDirection); | |||||
return seek(target); | |||||
} | |||||
Vector3 Ant::follow() | |||||
{ | |||||
const PheromoneMatrix* pheromoneMatrix = colony->getRecruitmentMatrix(); | |||||
Vector2 receptorL2D = Vector2(receptorL.x, receptorL.z); | |||||
Vector2 receptorR2D = Vector2(receptorR.x, receptorR.z); | |||||
float signalL = pheromoneMatrix->query(receptorL2D, RECEPTOR_RADIUS); | |||||
signalL += frand(0.0f, MAX_RECEPTOR_NOISE); | |||||
float signalR = pheromoneMatrix->query(receptorR2D, RECEPTOR_RADIUS); | |||||
signalR += frand(0.0f, MAX_RECEPTOR_NOISE); | |||||
if (signalL + signalR > 0.0f) | |||||
{ | |||||
float angle = -MAX_PHEROMONE_TURNING_ANGLE * ((signalL - signalR) / (signalL + signalR)); | |||||
Vector3 steer = glm::normalize(glm::angleAxis(angle, getUp()) * getForward()); | |||||
return steer; | |||||
} | |||||
return Vector3(0.0f); | |||||
} | |||||
void Ant::applyForce(const Vector3& force) | |||||
{ | |||||
acceleration += force; | |||||
} |
@ -1,155 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef ANT_HPP | |||||
#define ANT_HPP | |||||
#include <vector> | |||||
#include "navmesh.hpp" | |||||
#include "agent.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
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, | |||||
DEAD, | |||||
SUSPENDED | |||||
}; | |||||
/** | |||||
* Creates an instance of Ant. | |||||
*/ | |||||
Ant(Colony* colony); | |||||
~Ant(); | |||||
void animate(); | |||||
void suspend(const Vector3& suspensionPoint, const Quaternion& suspensionRotation); | |||||
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(); | |||||
// Boid functions | |||||
Vector3 seek(const Vector3& target); | |||||
Vector3 flee(const Vector3& target); | |||||
Vector3 wander(); | |||||
Vector3 follow(); | |||||
void applyForce(const Vector3& force); | |||||
private: | |||||
Vector3 forage(const Vector3& leftReceptor, const Vector3& rightReceptor); | |||||
/** | |||||
* 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; | |||||
float animationTime; | |||||
Transform transform; | |||||
ModelInstance modelInstance; | |||||
Pose* pose; | |||||
// Boid variables | |||||
//Vector3 position; | |||||
//Quaternion rotation; | |||||
//Vector3 forward; | |||||
Vector3 velocity; | |||||
Vector3 acceleration; | |||||
Vector3 wanderDirection; | |||||
float excitement; | |||||
Vector3 receptorL; | |||||
Vector3 receptorR; | |||||
}; | |||||
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; | |||||
} | |||||
#endif // ANT_HPP |
@ -1,42 +0,0 @@ | |||||
#ifndef BIOME_HPP | |||||
#define BIOME_HPP | |||||
#include <map> | |||||
#include <string> | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class Biome | |||||
{ | |||||
public: | |||||
Biome(); | |||||
~Biome(); | |||||
bool load(); | |||||
std::string filename; | |||||
std::string name; | |||||
std::string soilHorizonOFilename; | |||||
std::string soilHorizonAFilename; | |||||
std::string soilHorizonBFilename; | |||||
std::string soilHorizonCFilename; | |||||
std::string cubemapName; | |||||
Texture2D* soilHorizonO; | |||||
Texture2D* soilHorizonA; | |||||
Texture2D* soilHorizonB; | |||||
Texture2D* soilHorizonC; | |||||
TextureCube* diffuseCubemap; | |||||
TextureCube* specularCubemap; | |||||
}; | |||||
class Biosphere | |||||
{ | |||||
public: | |||||
bool load(const std::string& directory); | |||||
std::map<std::string, Biome> biomes; | |||||
}; | |||||
#endif // BIOME_HPP |
@ -0,0 +1,168 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "brush.hpp" | |||||
#include "camera-rig.hpp" | |||||
#include <stdexcept> | |||||
Brush::Brush(const Model* model, Animator* animator): | |||||
wasActive(false) | |||||
{ | |||||
// Setup model instance | |||||
modelInstance.setModel(model); | |||||
pressedDistance = -0.25f; | |||||
releasedDistance = 0.5f; | |||||
pressDuration = 0.25f; | |||||
releaseDuration = 0.175f; | |||||
tipDistance = releasedDistance; | |||||
lastTipDistance = tipDistance; | |||||
painting = false; | |||||
speed = 0.0f; | |||||
mousePosition = Vector2(0.0f); | |||||
lastMousePosition = mousePosition; | |||||
screenDimensions = Vector2(1.0f); | |||||
// Construct press animation clip | |||||
AnimationChannel<float>* channel; | |||||
pressClip.setInterpolator(easeOutCubic<float>); | |||||
channel = pressClip.addChannel(0); | |||||
channel->insertKeyframe(0.0f, 0.0f); | |||||
channel->insertKeyframe(pressDuration, 1.0f); | |||||
// Construct release animation clip | |||||
releaseClip.setInterpolator(easeOutCubic<float>); | |||||
channel = releaseClip.addChannel(0); | |||||
channel->insertKeyframe(0.0f, 0.0f); | |||||
channel->insertKeyframe(releaseDuration, 1.0f); | |||||
// Setup press animation callbacks | |||||
pressAnimation.setTimeFrame(pressClip.getTimeFrame()); | |||||
pressAnimation.setClip(&pressClip); | |||||
pressAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, float t) | |||||
{ | |||||
this->tipDistance = lerp(lastTipDistance, pressedDistance, t); | |||||
} | |||||
); | |||||
pressAnimation.setEndCallback | |||||
( | |||||
[this]() | |||||
{ | |||||
this->painting = true; | |||||
} | |||||
); | |||||
// Setup release animation callbacks | |||||
releaseAnimation.setTimeFrame(releaseClip.getTimeFrame()); | |||||
releaseAnimation.setClip(&releaseClip); | |||||
releaseAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, float t) | |||||
{ | |||||
this->tipDistance = lerp(lastTipDistance, releasedDistance, t); | |||||
} | |||||
); | |||||
// Add animations to animator | |||||
animator->addAnimation(&pressAnimation); | |||||
animator->addAnimation(&releaseAnimation); | |||||
} | |||||
Brush::~Brush() | |||||
{} | |||||
void Brush::update(float dt) | |||||
{ | |||||
Vector2 screenCenter = Vector2(screenDimensions.x * 0.5f, screenDimensions.y * 0.5f); | |||||
// Calculate mouse movement speed | |||||
Vector2 mouseDifference = (mousePosition - lastMousePosition) / std::min<float>(screenDimensions.x, screenDimensions.y); | |||||
Vector2 mouseDirection(0.0f); | |||||
float mouseSpeed = glm::length2(mouseDifference); | |||||
if (mouseSpeed != 0.0f) | |||||
{ | |||||
mouseSpeed = std::sqrt(mouseSpeed); | |||||
mouseDirection = mouseDifference * (1.0f / mouseSpeed); | |||||
} | |||||
this->lastMousePosition = this->mousePosition; | |||||
Vector3 tiltDirection = Vector3(mouseDirection.x, 0.0f, mouseDirection.y); | |||||
float tiltMagnitude = std::min<float>(0.5f, mouseSpeed * 10.0f); | |||||
if (!tiltMagnitude) | |||||
{ | |||||
tiltDirection = Vector3(0, 1, 0); | |||||
} | |||||
Vector2 tiltForce = mouseDirection * mouseSpeed; | |||||
velocity += tiltForce; | |||||
Quaternion tilt = glm::normalize(glm::slerp(Quaternion(1, 0, 0, 0), glm::normalize(glm::rotation(Vector3(0, 1, 0), tiltDirection)), tiltMagnitude * 0.0f)); | |||||
Quaternion alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0)); | |||||
Quaternion rotation = glm::normalize(alignment * tilt); | |||||
Vector3 translation = pick + rotation * Vector3(0, tipDistance, 0); | |||||
// Set tool position | |||||
modelInstance.setTranslation(translation); | |||||
modelInstance.setRotation(rotation); | |||||
if (active && !wasActive) | |||||
{ | |||||
modelInstance.resetTweens(); | |||||
modelInstance.setActive(true); | |||||
} | |||||
else if (!active && wasActive) | |||||
{ | |||||
modelInstance.setActive(false); | |||||
} | |||||
wasActive = active; | |||||
} | |||||
void Brush::press() | |||||
{ | |||||
lastTipDistance = tipDistance; | |||||
releaseAnimation.stop(); | |||||
pressAnimation.rewind(); | |||||
pressAnimation.play(); | |||||
} | |||||
void Brush::release() | |||||
{ | |||||
lastTipDistance = tipDistance; | |||||
pressAnimation.stop(); | |||||
releaseAnimation.rewind(); | |||||
releaseAnimation.play(); | |||||
painting = false; | |||||
} | |||||
void Brush::setTiltParams(const Vector2& mousePosition, const Vector2& screenDimensions) | |||||
{ | |||||
this->mousePosition = mousePosition; | |||||
this->screenDimensions = screenDimensions; | |||||
} | |||||
@ -0,0 +1,67 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef BRUSH_HPP | |||||
#define BRUSH_HPP | |||||
#include "tool.hpp" | |||||
class Brush: public Tool | |||||
{ | |||||
public: | |||||
Brush(const Model* model, Animator* animator); | |||||
~Brush(); | |||||
/** | |||||
* Updates the brush. | |||||
* | |||||
* @param dt Game timestep. | |||||
*/ | |||||
virtual void update(float dt); | |||||
void press(); | |||||
void release(); | |||||
void setTiltParams(const Vector2& mousePosition, const Vector2& screenDimensions); | |||||
private: | |||||
float pressedDistance; | |||||
float releasedDistance; | |||||
float tipDistance; | |||||
float lastTipDistance; | |||||
bool painting; | |||||
float pressDuration; | |||||
float releaseDuration; | |||||
Animation<float> pressAnimation; | |||||
Animation<float> releaseAnimation; | |||||
AnimationClip<float> pressClip; | |||||
AnimationClip<float> releaseClip; | |||||
Vector2 mousePosition; | |||||
Vector2 lastMousePosition; | |||||
Vector2 screenDimensions; | |||||
float speed; | |||||
Vector2 velocity; | |||||
bool wasActive; | |||||
}; | |||||
#endif // BRUSH_HPP |
@ -1,106 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "colony.hpp" | |||||
#include "ant.hpp" | |||||
#include "pheromone-matrix.hpp" | |||||
#include "../configuration.hpp" | |||||
Colony::Colony(): | |||||
antModel(nullptr), | |||||
tripodGaitAnimation(nullptr) | |||||
{ | |||||
Vector3 octreeMin = Vector3(-ANTKEEPER_TERRAIN_WIDTH, -ANTKEEPER_TERRAIN_BASE_HEIGHT, -ANTKEEPER_TERRAIN_DEPTH) * 0.5f - Vector3(ANTKEEPER_OCTREE_PADDING); | |||||
Vector3 octreeMax = Vector3( ANTKEEPER_TERRAIN_WIDTH, ANTKEEPER_TERRAIN_BASE_HEIGHT, ANTKEEPER_TERRAIN_DEPTH) * 0.5f + Vector3(ANTKEEPER_OCTREE_PADDING); | |||||
AABB octreeBounds(octreeMin, octreeMax); | |||||
antOctree = new Octree<Agent*>(5, octreeBounds); | |||||
// Create pheromone matrices | |||||
homingMatrix = new PheromoneMatrix(PHEROMONE_MATRIX_COLUMNS, PHEROMONE_MATRIX_ROWS, WORLD_BOUNDS_MIN, WORLD_BOUNDS_MAX); | |||||
recruitmentMatrix = new PheromoneMatrix(PHEROMONE_MATRIX_COLUMNS, PHEROMONE_MATRIX_ROWS, WORLD_BOUNDS_MIN, WORLD_BOUNDS_MAX); | |||||
} | |||||
Colony::~Colony() | |||||
{ | |||||
killAll(); | |||||
delete antOctree; | |||||
delete homingMatrix; | |||||
delete recruitmentMatrix; | |||||
} | |||||
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) | |||||
{ | |||||
// Rebuild octree | |||||
antOctree->clear(); | |||||
for (Ant* ant: ants) | |||||
{ | |||||
antOctree->insert(ant->getModelInstance()->getBounds(), ant); | |||||
} | |||||
// Update ants | |||||
for (Ant* ant: ants) | |||||
{ | |||||
ant->update(dt); | |||||
} | |||||
} | |||||
void Colony::setAntModel(Model* model) | |||||
{ | |||||
this->antModel = model; | |||||
// Find tripod gait animation | |||||
tripodGaitAnimation = model->getSkeleton()->getAnimation("tripod-gait"); | |||||
if (!tripodGaitAnimation) | |||||
{ | |||||
std::cerr << "Ant tripod gait animation not found" << std::endl; | |||||
} | |||||
} | |||||
void Colony::queryAnts(const BoundingVolume& volume, std::list<Agent*>* results) const | |||||
{ | |||||
antOctree->query(volume, results); | |||||
} | |||||
void Colony::killAll() | |||||
{ | |||||
antOctree->clear(); | |||||
homingMatrix->clear(); | |||||
recruitmentMatrix->clear(); | |||||
for (Ant* ant: ants) | |||||
{ | |||||
delete ant; | |||||
} | |||||
ants.clear(); | |||||
} |
@ -1,146 +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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef COLONY_HPP | |||||
#define COLONY_HPP | |||||
#include <vector> | |||||
#include "navmesh.hpp" | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
class Ant; | |||||
class Agent; | |||||
class Pheromone; | |||||
class Gait; | |||||
class PheromoneMatrix; | |||||
/** | |||||
* A colony of ants. | |||||
*/ | |||||
class Colony | |||||
{ | |||||
public: | |||||
Colony(); | |||||
~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(); | |||||
const Animation* getTripodGaitAnimation() const; | |||||
void queryAnts(const BoundingVolume& volume, std::list<Agent*>* results) const; | |||||
std::size_t getAntCount() const; | |||||
const Ant* getAnt(std::size_t index) const; | |||||
Ant* getAnt(std::size_t index); | |||||
void killAll(); | |||||
const Octree<Agent*>* getAntOctree() const; | |||||
const PheromoneMatrix* getHomingMatrix() const; | |||||
PheromoneMatrix* getHomingMatrix(); | |||||
const PheromoneMatrix* getRecruitmentMatrix() const; | |||||
PheromoneMatrix* getRecruitmentMatrix(); | |||||
private: | |||||
// Rendering | |||||
Model* antModel; | |||||
const Animation* tripodGaitAnimation; | |||||
// Locomotion | |||||
float walkSpeed; | |||||
float turnSpeed; | |||||
Gait* tripodGait; | |||||
Gait* rippleGait; | |||||
Gait* slowWaveGait; | |||||
std::vector<Ant*> ants; | |||||
Octree<Agent*>* antOctree; | |||||
PheromoneMatrix* homingMatrix; | |||||
PheromoneMatrix* recruitmentMatrix; | |||||
}; | |||||
inline const Model* Colony::getAntModel() const | |||||
{ | |||||
return antModel; | |||||
} | |||||
inline Model* Colony::getAntModel() | |||||
{ | |||||
return antModel; | |||||
} | |||||
inline const Animation* Colony::getTripodGaitAnimation() const | |||||
{ | |||||
return tripodGaitAnimation; | |||||
} | |||||
inline std::size_t Colony::getAntCount() const | |||||
{ | |||||
return ants.size(); | |||||
} | |||||
inline const Ant* Colony::getAnt(std::size_t index) const | |||||
{ | |||||
return ants[index]; | |||||
} | |||||
inline Ant* Colony::getAnt(std::size_t index) | |||||
{ | |||||
return ants[index]; | |||||
} | |||||
inline const Octree<Agent*>* Colony::getAntOctree() const | |||||
{ | |||||
return antOctree; | |||||
} | |||||
inline const PheromoneMatrix* Colony::getHomingMatrix() const | |||||
{ | |||||
return homingMatrix; | |||||
} | |||||
inline PheromoneMatrix* Colony::getHomingMatrix() | |||||
{ | |||||
return homingMatrix; | |||||
} | |||||
inline const PheromoneMatrix* Colony::getRecruitmentMatrix() const | |||||
{ | |||||
return recruitmentMatrix; | |||||
} | |||||
inline PheromoneMatrix* Colony::getRecruitmentMatrix() | |||||
{ | |||||
return recruitmentMatrix; | |||||
} | |||||
#endif // COLONY_HPP |
@ -0,0 +1,40 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "curl-noise.hpp" | |||||
inline static Vector3 gradient(const Vector3& p, float frequency) | |||||
{ | |||||
const float epsilon = 0.0001f; | |||||
float n0 = glm::perlin(p * frequency); | |||||
float nx = glm::perlin((p + Vector3(epsilon, 0, 0)) * frequency); | |||||
float ny = glm::perlin((p + Vector3(0, epsilon, 0)) * frequency); | |||||
float nz = glm::perlin((p + Vector3(0, 0, epsilon)) * frequency); | |||||
return Vector3(nx - n0, ny - n0, nz - n0) * (1.0f / epsilon); | |||||
} | |||||
Vector3 curl(const Vector3& p, const Vector3& offset, float frequency) | |||||
{ | |||||
Vector3 g1 = gradient(p, frequency); | |||||
Vector3 g2 = gradient(p + offset, frequency); | |||||
return glm::cross(g1, g2); | |||||
} | |||||
@ -0,0 +1,28 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef CURL_NOISE_HPP | |||||
#define CURL_NOISE_HPP | |||||
#include <emergent/emergent.hpp> | |||||
using namespace Emergent; | |||||
Vector3 curl(const Vector3& p, const Vector3& offset, float frequency); | |||||
#endif // CURL_NOISE_HPP |
@ -0,0 +1,396 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "forceps.hpp" | |||||
#include "camera-rig.hpp" | |||||
#include <stdexcept> | |||||
Forceps::Forceps(const Model* model, Animator* animator): | |||||
wasActive(false) | |||||
{ | |||||
// Allocate pose and initialize to bind pose | |||||
pose = new Pose(model->getSkeleton()); | |||||
pose->reset(); | |||||
// Setup model instance | |||||
modelInstance.setModel(model); | |||||
modelInstance.setPose(pose); | |||||
// Find pinch animation | |||||
pinchClip = model->getSkeleton()->getAnimationClip("pinch"); | |||||
if (!pinchClip) | |||||
{ | |||||
throw std::runtime_error("Forceps pinch animation clip not found."); | |||||
} | |||||
// Find release animation | |||||
releaseClip = model->getSkeleton()->getAnimationClip("release"); | |||||
if (!releaseClip) | |||||
{ | |||||
throw std::runtime_error("Forceps release animation clip not found."); | |||||
} | |||||
// Scale animation speed | |||||
float pinchDuration = 0.1f; | |||||
float releaseDuration = 0.05f; | |||||
float pinchSpeed = std::get<1>(pinchClip->getTimeFrame()) / pinchDuration; | |||||
float releaseSpeed = std::get<1>(releaseClip->getTimeFrame()) / releaseDuration; | |||||
std::cout << std::get<1>(pinchClip->getTimeFrame()) << std::endl; | |||||
std::cout << std::get<1>(releaseClip->getTimeFrame()) << std::endl; | |||||
// Setup pinch animation callbacks | |||||
pinchAnimation.setSpeed(pinchSpeed); | |||||
pinchAnimation.setTimeFrame(pinchClip->getTimeFrame()); | |||||
pinchAnimation.setClip(pinchClip); | |||||
pinchAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, const Transform& transform) | |||||
{ | |||||
this->pose->setRelativeTransform(id, transform); | |||||
} | |||||
); | |||||
pinchAnimation.setEndCallback | |||||
( | |||||
[this]() | |||||
{ | |||||
this->pinched = true; | |||||
} | |||||
); | |||||
// Setup release animation callbacks | |||||
releaseAnimation.setSpeed(releaseSpeed); | |||||
releaseAnimation.setTimeFrame(releaseClip->getTimeFrame()); | |||||
releaseAnimation.setClip(releaseClip); | |||||
releaseAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, const Transform& transform) | |||||
{ | |||||
this->pose->setRelativeTransform(id, transform); | |||||
} | |||||
); | |||||
hoverDistance = 1.0f; | |||||
// Setup timing | |||||
float descentDuration = 0.125f; | |||||
float ascentDuration = 0.125f; | |||||
/* | |||||
// Allocate tweener and and setup tweens | |||||
tweener = new Tweener(); | |||||
descentTween = new Tween<float>(EaseFunction::OUT_CUBIC, 0.0f, descentDuration, hoverDistance, -hoverDistance); | |||||
ascentTween = new Tween<float>(EaseFunction::IN_CUBIC, 0.0f, ascentDuration, 0.0f, hoverDistance); | |||||
descentTween->setEndCallback(std::bind(&TweenBase::start, ascentTween)); | |||||
tweener->addTween(descentTween); | |||||
tweener->addTween(ascentTween); | |||||
*/ | |||||
// Setup initial state | |||||
state = Forceps::State::RELEASED; | |||||
for (std::size_t i = 0; i < pinchClip->getChannelCount(); ++i) | |||||
{ | |||||
const AnimationChannel<Transform>* channel = pinchClip->getChannelByIndex(i); | |||||
pose->setRelativeTransform(channel->getChannelID(), *std::get<1>(channel->getKeyframe(0))); | |||||
} | |||||
pose->concatenate(); | |||||
animator->addAnimation(&pinchAnimation); | |||||
animator->addAnimation(&releaseAnimation); | |||||
} | |||||
Forceps::~Forceps() | |||||
{ | |||||
delete pose; | |||||
} | |||||
void Forceps::update(float dt) | |||||
{ | |||||
// Determine distance from pick point | |||||
float forcepsDistance = hoverDistance; | |||||
Quaternion alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0)); | |||||
Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1)); | |||||
tilt = tilt * glm::angleAxis(glm::radians(-70.0f), tilt * Vector3(0, 1, 0)); | |||||
Quaternion rotation = glm::normalize(alignment * tilt); | |||||
Vector3 translation = pick + rotation * Vector3(0, forcepsDistance, 0); | |||||
// Set tool position | |||||
modelInstance.setTranslation(translation); | |||||
modelInstance.setRotation(rotation); | |||||
pose->concatenate(); | |||||
if (active && !wasActive) | |||||
{ | |||||
modelInstance.resetTweens(); | |||||
modelInstance.setActive(true); | |||||
} | |||||
else if (!active && wasActive) | |||||
{ | |||||
modelInstance.setActive(false); | |||||
} | |||||
wasActive = active; | |||||
/* | |||||
if (state == Forceps::State::RELEASED) | |||||
{ | |||||
} | |||||
else if (state == Forceps::State::RELEASING) | |||||
{ | |||||
// Perform release animation | |||||
releaseAnimation->animate(pose, animationTime); | |||||
pose->concatenate(); | |||||
// If release animation is finished | |||||
if (animationTime >= releaseAnimation->getEndTime()) | |||||
{ | |||||
// Changed to released state | |||||
state = Forceps::State::RELEASED; | |||||
} | |||||
} | |||||
else if (state == Forceps::State::PINCHED) | |||||
{ | |||||
if (!ascentTween->isStopped()) | |||||
{ | |||||
// Calculate interpolation factor | |||||
float interpolationFactor = (ascentTween->getTweenValue() - ascentTween->getStartValue()) / ascentTween->getDeltaValue(); | |||||
// Form tilt quaternion | |||||
//Quaternion tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1)); | |||||
tilt = glm::angleAxis(glm::radians(15.0f), Vector3(0, 0, -1)); | |||||
// Project camera forward onto XZ plane | |||||
Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward(); | |||||
cameraForwardXZ.y = 0.0f; | |||||
cameraForwardXZ = glm::normalize(cameraForwardXZ); | |||||
// Form alignment quaternion | |||||
//Quaternion alignment = glm::rotation(Vector3(0, 0, -1), cameraForwardXZ); | |||||
alignment = glm::angleAxis(orbitCam->getAzimuth(), Vector3(0, 1, 0)); | |||||
// Calculate target rotation at the top of the ascentTween | |||||
rotationTop = glm::normalize(alignment * tilt); | |||||
// Interpolate between bottom and top rotations | |||||
Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationBottom, rotationTop, interpolationFactor)); | |||||
// Set target translation at the top of the ascent | |||||
translationTop = pick + rotationTop * Vector3(0, hoverDistance, 0); | |||||
// Interpolate between bottom and top translations | |||||
Vector3 interpolatedTranslation = glm::lerp(translationBottom, translationTop, interpolationFactor); | |||||
// Update model instance transform | |||||
modelInstance.setTranslation(interpolatedTranslation); | |||||
modelInstance.setRotation(interpolatedRotation); | |||||
} | |||||
if (suspendedAnt != nullptr) | |||||
{ | |||||
// Project forceps forward vector onto XZ plane | |||||
Vector3 forward = glm::normalize(modelInstance.getRotation() * Vector3(0, 0, -1)); | |||||
forward.y = 0.0f; | |||||
forward = glm::normalize(forward); | |||||
// Calculate suspension quaternion | |||||
Quaternion suspensionRotation = glm::normalize(glm::rotation(Vector3(0, 0, -1), ((flipRotation) ? -forward : forward))); | |||||
// Suspend ant | |||||
suspendedAnt->suspend(modelInstance.getTranslation(), suspensionRotation); | |||||
} | |||||
} | |||||
else if (state == Forceps::State::PINCHING) | |||||
{ | |||||
// Perform pinch animation | |||||
pinchAnimation->animate(pose, animationTime); | |||||
pose->concatenate(); | |||||
// Rotate to align forceps with ant | |||||
if (targetedAnt != nullptr) | |||||
{ | |||||
// Calculate interpolation factor | |||||
float interpolationFactor = (descentTween->getTweenValue() - descentTween->getStartValue()) / descentTween->getDeltaValue(); | |||||
// Set target translation at the bottom of the descent | |||||
translationBottom = targetedAnt->getPosition(); | |||||
// Interpolate between top and bottom translations | |||||
Vector3 interpolatedTranslation = glm::lerp(translationTop, translationBottom, interpolationFactor); | |||||
// Project camera forward onto XZ plane | |||||
Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward(); | |||||
cameraForwardXZ.y = 0.0f; | |||||
cameraForwardXZ = glm::normalize(cameraForwardXZ); | |||||
// Form tilt quaternion | |||||
tilt = glm::angleAxis(glm::radians(15.0f), -cameraForwardXZ); | |||||
// Project ant forward onto XZ plane | |||||
Vector3 antForwardXZ = targetedAnt->getForward(); | |||||
antForwardXZ.y = 0.0f; | |||||
antForwardXZ = glm::normalize(antForwardXZ); | |||||
// Form alignment quaternion | |||||
alignment = glm::rotation(Vector3(0, 0, -1), (flipRotation) ? antForwardXZ : -antForwardXZ); | |||||
// Calculate target rotation at the bottom of the descent | |||||
rotationBottom = glm::normalize(tilt * alignment); | |||||
// Interpolate between top and bottom rotations | |||||
Quaternion interpolatedRotation = glm::normalize(glm::slerp(rotationTop, rotationBottom, interpolationFactor)); | |||||
// Update model instance transform | |||||
modelInstance.setTranslation(interpolatedTranslation); | |||||
modelInstance.setRotation(interpolatedRotation); | |||||
} | |||||
// If pinch animation is finished | |||||
if (animationTime >= pinchAnimation->getEndTime() && descentTween->isStopped()) | |||||
{ | |||||
// If an ant was targeted | |||||
if (targetedAnt != nullptr) | |||||
{ | |||||
// Suspend targeted ant | |||||
suspendedAnt = targetedAnt; | |||||
suspendedAnt->setState(Ant::State::SUSPENDED); | |||||
//suspendedAnt->suspend(modelInstance.getTranslation()); | |||||
targetedAnt = nullptr; | |||||
} | |||||
// Change to pinched state | |||||
state = Forceps::State::PINCHED; | |||||
} | |||||
} | |||||
*/ | |||||
} | |||||
void Forceps::pinch() | |||||
{ | |||||
releaseAnimation.stop(); | |||||
pinchAnimation.rewind(); | |||||
pinchAnimation.play(); | |||||
/* | |||||
// Change state to pinching | |||||
state = Forceps::State::PINCHING; | |||||
animationTime = 0.0f; | |||||
if (colony != nullptr) | |||||
{ | |||||
// Target nearest ant in pinching radius | |||||
Sphere pinchingBounds = Sphere(pick, 0.35f); | |||||
// Build a list of ants which intersect the pinching bounds | |||||
std::list<Agent*> ants; | |||||
colony->queryAnts(pinchingBounds, &ants); | |||||
// Target ant closest to the center of the pinching bounds | |||||
float closestDistance = std::numeric_limits<float>::infinity(); | |||||
for (Agent* agent: ants) | |||||
{ | |||||
Ant* ant = static_cast<Ant*>(agent); | |||||
Vector3 difference = ant->getPosition() - pinchingBounds.getCenter(); | |||||
float distanceSquared = glm::dot(difference, difference); | |||||
if (distanceSquared < closestDistance) | |||||
{ | |||||
closestDistance = distanceSquared; | |||||
targetedAnt = ant; | |||||
} | |||||
} | |||||
if (targetedAnt != nullptr) | |||||
{ | |||||
// Start descent tweener | |||||
descentTween->start(); | |||||
// Save translation & rotation | |||||
translationTop = modelInstance.getTranslation(); | |||||
rotationTop = modelInstance.getRotation(); | |||||
// Project ant forward onto XZ plane | |||||
Vector3 antForwardXZ = targetedAnt->getForward(); | |||||
antForwardXZ.y = 0.0f; | |||||
antForwardXZ = glm::normalize(antForwardXZ); | |||||
// Project camera forward onto XZ plane | |||||
Vector3 cameraForwardXZ = orbitCam->getCamera()->getForward(); | |||||
cameraForwardXZ.y = 0.0f; | |||||
cameraForwardXZ = glm::normalize(cameraForwardXZ); | |||||
// Find angle between ant and camera on XZ plane | |||||
float angle = std::acos(glm::dot(cameraForwardXZ, antForwardXZ)); | |||||
// Determine direction to rotate | |||||
flipRotation = (angle > glm::radians(90.0f)); | |||||
} | |||||
} | |||||
*/ | |||||
} | |||||
void Forceps::release() | |||||
{ | |||||
pinchAnimation.stop(); | |||||
releaseAnimation.rewind(); | |||||
releaseAnimation.play(); | |||||
/* | |||||
// Change state to releasing | |||||
state = Forceps::State::RELEASING; | |||||
animationTime = 0.0f; | |||||
targetedAnt = nullptr; | |||||
if (suspendedAnt != nullptr) | |||||
{ | |||||
Ray pickingRay; | |||||
pickingRay.origin = pick + Vector3(0, 1, 0); | |||||
pickingRay.direction = Vector3(0, -1, 0); | |||||
const std::vector<Navmesh::Triangle*>* navmeshTriangles = navmesh->getTriangles(); | |||||
for (Navmesh::Triangle* triangle: *navmeshTriangles) | |||||
{ | |||||
auto result = intersects(pickingRay, triangle); | |||||
if (std::get<0>(result)) | |||||
{ | |||||
Vector3 barycentricPosition = Vector3(std::get<2>(result), std::get<3>(result), 1.0f - std::get<2>(result) - std::get<3>(result)); | |||||
suspendedAnt->setPosition(triangle, barycentricPosition); | |||||
break; | |||||
} | |||||
} | |||||
// Release suspended ant | |||||
suspendedAnt->setState(Ant::State::WANDER); | |||||
suspendedAnt = nullptr; | |||||
} | |||||
// Reset tweens | |||||
descentTween->reset(); | |||||
descentTween->stop(); | |||||
ascentTween->reset(); | |||||
ascentTween->stop(); | |||||
*/ | |||||
} | |||||
@ -0,0 +1,95 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef FORCEPS_HPP | |||||
#define FORCEPS_HPP | |||||
#include "tool.hpp" | |||||
/** | |||||
* The forceps tool can pick up ants and place them anywhere in the world. | |||||
*/ | |||||
class Forceps: public Tool | |||||
{ | |||||
public: | |||||
enum class State | |||||
{ | |||||
RELEASED, | |||||
RELEASING, | |||||
PINCHED, | |||||
PINCHING | |||||
}; | |||||
/** | |||||
* Creates an instance of Forceps. | |||||
* | |||||
* @param model Forceps model | |||||
*/ | |||||
Forceps(const Model* model, Animator* animator); | |||||
/** | |||||
* Destroys an instance of Forceps. | |||||
*/ | |||||
~Forceps(); | |||||
/** | |||||
* Updates the forceps. | |||||
* | |||||
* @param dt Application timestep. | |||||
*/ | |||||
virtual void update(float dt); | |||||
/** | |||||
* Pinches the forceps. | |||||
*/ | |||||
void pinch(); | |||||
/** | |||||
* Releases the forceps. | |||||
*/ | |||||
void release(); | |||||
/** | |||||
* Returns the current state of the forceps. | |||||
*/ | |||||
Forceps::State getState() const; | |||||
private: | |||||
Forceps::State state; | |||||
Pose* pose; | |||||
const AnimationClip<Transform>* pinchClip; | |||||
const AnimationClip<Transform>* releaseClip; | |||||
Animation<Transform> pinchAnimation; | |||||
Animation<Transform> releaseAnimation; | |||||
float hoverDistance; | |||||
Vector3 translationBottom; | |||||
Vector3 translationTop; | |||||
Quaternion rotationTop; | |||||
Quaternion rotationBottom; | |||||
bool flipRotation; | |||||
bool pinched; | |||||
bool wasActive; | |||||
}; | |||||
inline Forceps::State Forceps::getState() const | |||||
{ | |||||
return state; | |||||
} | |||||
#endif // FORCEPS_HPP |
@ -0,0 +1,176 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#include "lens.hpp" | |||||
#include "camera-rig.hpp" | |||||
#include "../entity/systems/particle-system.hpp" | |||||
Lens::Lens(const Model* model, Animator* animator): | |||||
wasActive(false), | |||||
particleSystem(nullptr) | |||||
{ | |||||
// Setup model instance | |||||
modelInstance.setModel(model); | |||||
modelInstance.setCullingEnabled(false); | |||||
// Setup spotlight | |||||
spotlight.setColor(Vector3(1.0f)); | |||||
spotlight.setIntensity(1000.0f); | |||||
spotlight.setAttenuation(Vector3(1, 0, 1)); | |||||
spotlight.setCutoff(std::cos(glm::radians(45.0f))); | |||||
spotlight.setExponent(150.0f); | |||||
spotlight.setActive(false); | |||||
unfocusedDistance = 18.0f; | |||||
unfocusDuration = 0.25f; | |||||
focusedDistance = 12.0f; | |||||
focusDuration = 0.75f; | |||||
lensDistance = unfocusedDistance; | |||||
focused = false; | |||||
lastDistance = unfocusedDistance; | |||||
sunDirection = Vector3(0, -1, 0); | |||||
// Construct focus animation clip | |||||
AnimationChannel<float>* channel; | |||||
focusClip.setInterpolator(easeOutCubic<float>); | |||||
channel = focusClip.addChannel(0); | |||||
channel->insertKeyframe(0.0f, 0.0f); | |||||
channel->insertKeyframe(focusDuration, 1.0f); | |||||
// Construct unfocus animation clip | |||||
unfocusClip.setInterpolator(easeOutCubic<float>); | |||||
channel = unfocusClip.addChannel(0); | |||||
channel->insertKeyframe(0.0f, 0.0f); | |||||
channel->insertKeyframe(unfocusDuration, 1.0f); | |||||
// Setup focus animation callbacks | |||||
focusAnimation.setTimeFrame(focusClip.getTimeFrame()); | |||||
focusAnimation.setClip(&focusClip); | |||||
focusAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, float distance) | |||||
{ | |||||
this->lensDistance = lerp(lastDistance, focusedDistance, distance); | |||||
} | |||||
); | |||||
focusAnimation.setEndCallback | |||||
( | |||||
[this]() | |||||
{ | |||||
this->focused = true; | |||||
} | |||||
); | |||||
// Setup unfocus animation callbacks | |||||
unfocusAnimation.setTimeFrame(unfocusClip.getTimeFrame()); | |||||
unfocusAnimation.setClip(&unfocusClip); | |||||
unfocusAnimation.setAnimateCallback | |||||
( | |||||
[this](std::size_t id, float distance) | |||||
{ | |||||
this->lensDistance = lerp(lastDistance, unfocusedDistance, distance); | |||||
} | |||||
); | |||||
// Add animations to animator | |||||
animator->addAnimation(&focusAnimation); | |||||
animator->addAnimation(&unfocusAnimation); | |||||
} | |||||
Lens::~Lens() | |||||
{} | |||||
void Lens::update(float dt) | |||||
{ | |||||
//Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(glm::radians(90.0f), Vector3(0, 1, 0)); | |||||
Quaternion alignment = glm::rotation(Vector3(0, 1, 0), -sunDirection) * glm::angleAxis(orbitCam->getAzimuth() + glm::radians(90.0f), Vector3(0, 1, 0)); | |||||
Quaternion rotation = glm::normalize(alignment); | |||||
Vector3 translation = pick + sunDirection * -lensDistance; | |||||
modelInstance.setTranslation(translation); | |||||
modelInstance.setRotation(rotation); | |||||
float t = (1.0 - (lensDistance - focusedDistance) / (unfocusedDistance - focusedDistance)); | |||||
float unfocusedIntensity = 250.0f * 2.0f; | |||||
float focusedIntensity = 1000.0f * 2.0f; | |||||
float intensity = easeInExpo(unfocusedIntensity, focusedIntensity, t); | |||||
float unfocusedExponent = 100.0f; | |||||
float focusedExponent = 5000.0f; | |||||
float exponent = easeInExpo(unfocusedExponent, focusedExponent, t); | |||||
spotlight.setIntensity(intensity); | |||||
spotlight.setExponent(exponent); | |||||
spotlight.setTranslation(pick + sunDirection * -lensDistance); | |||||
spotlight.setDirection(sunDirection); | |||||
if (active && !wasActive) | |||||
{ | |||||
modelInstance.resetTweens(); | |||||
spotlight.resetTweens(); | |||||
modelInstance.setActive(true); | |||||
spotlight.setActive(true); | |||||
} | |||||
else if (!active && wasActive) | |||||
{ | |||||
modelInstance.setActive(false); | |||||
spotlight.setActive(false); | |||||
} | |||||
if (active && focused) | |||||
{ | |||||
int count = 10; | |||||
for (int i = 0; i < count; ++i) | |||||
particleSystem->emit(pick); | |||||
} | |||||
wasActive = active; | |||||
} | |||||
void Lens::focus() | |||||
{ | |||||
lastDistance = lensDistance; | |||||
unfocusAnimation.stop(); | |||||
focusAnimation.rewind(); | |||||
focusAnimation.play(); | |||||
} | |||||
void Lens::unfocus() | |||||
{ | |||||
lastDistance = lensDistance; | |||||
focusAnimation.stop(); | |||||
unfocusAnimation.rewind(); | |||||
unfocusAnimation.play(); | |||||
focused = false; | |||||
} | |||||
void Lens::setSunDirection(const Vector3& direction) | |||||
{ | |||||
sunDirection = direction; | |||||
} | |||||
void Lens::setParticleSystem(ParticleSystem* particleSystem) | |||||
{ | |||||
this->particleSystem = particleSystem; | |||||
} | |||||
@ -0,0 +1,96 @@ | |||||
/* | |||||
* Copyright (C) 2017-2019 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 <http://www.gnu.org/licenses/>. | |||||
*/ | |||||
#ifndef LENS_HPP | |||||
#define LENS_HPP | |||||
#include "tool.hpp" | |||||
class ParticleSystem; | |||||
/** | |||||
* The lens tool can be used to burn ants. | |||||
* | |||||
* @see https://taylorpetrick.com/blog/post/dispersion-opengl | |||||
* @see https://taylorpetrick.com/portfolio/webgl/lense | |||||
*/ | |||||
class Lens: public Tool | |||||
{ | |||||
public: | |||||
/** | |||||
* Creates an instance of Lens. | |||||
* | |||||
* @param model Lens model | |||||
*/ | |||||
Lens(const Model* model, Animator* animator); | |||||
/** | |||||
* Destroys an instance of Lens. | |||||
*/ | |||||
~Lens(); | |||||
/** | |||||
* Updates the lens. | |||||
* | |||||
* @param dt Application timestep. | |||||
*/ | |||||
virtual void update(float dt); | |||||
void focus(); | |||||
void unfocus(); | |||||
void setSunDirection(const Vector3& direction); | |||||
void setParticleSystem(ParticleSystem* particleSystem); | |||||
/** | |||||
* Returns the spotlight. | |||||
*/ | |||||
const Spotlight* getSpotlight() const; | |||||
Spotlight* getSpotlight(); | |||||
private: | |||||
Spotlight spotlight; | |||||
float focusedDistance; | |||||
float unfocusedDistance; | |||||
float focusDuration; | |||||
float unfocusDuration; | |||||
float lensDistance; | |||||
float lastDistance; | |||||
bool focused; | |||||
Vector3 sunDirection; | |||||
Animation<float> focusAnimation; | |||||
Animation<float> unfocusAnimation; | |||||
AnimationClip<float> focusClip; | |||||
AnimationClip<float> unfocusClip; | |||||
bool wasActive; | |||||
ParticleSystem* particleSystem; | |||||
}; | |||||
inline const Spotlight* Lens::getSpotlight() const | |||||
{ | |||||
return &spotlight; | |||||
} | |||||
inline Spotlight* Lens::getSpotlight() | |||||
{ | |||||
return &spotlight; | |||||
} | |||||
#endif // LENS_HPP |
@ -1,149 +0,0 @@ | |||||
#include "level.hpp" | |||||
#include "../settings.hpp" | |||||
#include "../configuration.hpp" | |||||
#include <dirent.h> | |||||
#include <iostream> | |||||
#include <sstream> | |||||
LevelParameterSet::LevelParameterSet() | |||||
{} | |||||
LevelParameterSet::~LevelParameterSet() | |||||
{} | |||||
bool LevelParameterSet::load(const std::string& filename) | |||||
{ | |||||
this->filename = filename; | |||||
ParameterDict parameters; | |||||
if (!parameters.load(filename)) | |||||
{ | |||||
return false; | |||||
} | |||||
parameters.get("biome", &biome); | |||||
parameters.get("heightmap", &heightmap); | |||||
return true; | |||||
} | |||||
Level::Level() | |||||
{ | |||||
terrain.create(255, 255, Vector3(ANTKEEPER_TERRAIN_WIDTH, ANTKEEPER_TERRAIN_BASE_HEIGHT, ANTKEEPER_TERRAIN_DEPTH)); | |||||
} | |||||
Level::~Level() | |||||
{} | |||||
bool Level::load(const LevelParameterSet& params) | |||||
{ | |||||
// Load terrain from heightmap | |||||
std::string heightmapFilename = std::string("data/textures/") + params.heightmap; | |||||
if (!terrain.load(heightmapFilename)) | |||||
{ | |||||
std::cerr << "Failed to load terrain from heightmap file \"" << heightmapFilename << "\" for level \"" << params.filename << "\"" << std::endl; | |||||
return false; | |||||
} | |||||
//application->currentLevelTerrain->getSurfaceModel()->getGroup(0)->material = application->materialLoader->load("data/materials/debug-terrain-surface.mtl"); | |||||
// Setup terrain surface model instance | |||||
terrainSurface.setModel(terrain.getSurfaceModel()); | |||||
terrainSurface.setTranslation(Vector3(0, 0, 0)); | |||||
// Setup terrain subsurface model instance | |||||
terrainSubsurface.setModel(terrain.getSubsurfaceModel()); | |||||
terrainSubsurface.setTranslation(Vector3(0, 0, 0)); | |||||
return true; | |||||
} | |||||
Campaign::Campaign() | |||||
{} | |||||
Campaign::~Campaign() | |||||
{} | |||||
bool Campaign::load(const std::string& directory) | |||||
{ | |||||
// Open levels directory | |||||
DIR* dir = opendir(directory.c_str()); | |||||
if (dir == nullptr) | |||||
{ | |||||
std::cout << "Failed to open levels directory \"" << directory << "\"" << std::endl; | |||||
return false; | |||||
} | |||||
// Scan directory for .lvl files | |||||
for (struct dirent* entry = readdir(dir); entry != nullptr; entry = readdir(dir)) | |||||
{ | |||||
if (entry->d_type == DT_DIR || *entry->d_name == '.') | |||||
{ | |||||
continue; | |||||
} | |||||
std::string filename = entry->d_name; | |||||
std::string::size_type delimeter = filename.find_last_of('.'); | |||||
if (delimeter == std::string::npos) | |||||
{ | |||||
continue; | |||||
} | |||||
std::string extension = filename.substr(delimeter + 1); | |||||
if (extension != "lvl") | |||||
{ | |||||
continue; | |||||
} | |||||
std::string worldIndexString = filename.substr(0, 2); | |||||
std::string levelIndexString = filename.substr(3, 2); | |||||
int worldIndex = -1; | |||||
int levelIndex = -1; | |||||
std::stringstream stream; | |||||
stream << worldIndexString; | |||||
stream >> worldIndex; | |||||
worldIndex -= 1; | |||||
stream.str(std::string()); | |||||
stream.clear(); | |||||
stream << levelIndexString; | |||||
stream >> levelIndex; | |||||
levelIndex -= 1; | |||||
if (worldIndex < 0 || levelIndex < 0) | |||||
{ | |||||
std::cout << "Invalid level parameters file \"" << filename << "\"" << std::endl; | |||||
continue; | |||||
} | |||||
// Resize vector to accommodate maximum world index | |||||
if (worldIndex >= static_cast<int>(levelParameterSets.size())) | |||||
{ | |||||
levelParameterSets.resize(worldIndex + 1); | |||||
} | |||||
// Resize vector to accommodate maximum level file index | |||||
if (levelIndex >= static_cast<int>(levelParameterSets[worldIndex].size())) | |||||
{ | |||||
levelParameterSets[worldIndex].resize(levelIndex + 1); | |||||
} | |||||
// Load level parameters | |||||
LevelParameterSet* levelParams = &levelParameterSets[worldIndex][levelIndex]; | |||||
if (!levelParams->load(directory + filename)) | |||||
{ | |||||
std::cout << "Failed to load parameters for level " << (worldIndex + 1) << "-" << (levelIndex + 1) << std::endl; | |||||
} | |||||
else | |||||
{ | |||||
std::cout << "Loaded level parameters for level " << (worldIndex + 1) << "-" << (levelIndex + 1) << std::endl; | |||||
} | |||||
} | |||||
// Close levels directory | |||||
closedir(dir); | |||||
return true; | |||||
} |