@ -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; | |||
} |