Browse Source

Add initial terrain system and terrain patch component

master
C. J. Howard 5 years ago
parent
commit
ce4973b9a1
Signed by: cjhoward GPG Key ID: 03E1FABA9C3EC195
10 changed files with 633 additions and 89 deletions
  1. +1
    -0
      src/entity/components/component-type.hpp
  2. +29
    -0
      src/entity/components/terrain-patch-component.cpp
  3. +37
    -0
      src/entity/components/terrain-patch-component.hpp
  4. +360
    -0
      src/entity/systems/terrain-system.cpp
  5. +103
    -0
      src/entity/systems/terrain-system.hpp
  6. +64
    -86
      src/game.cpp
  7. +11
    -2
      src/game.hpp
  8. +26
    -0
      src/resources/entity-template-loader.cpp
  9. +1
    -0
      src/resources/resource-manager.hpp
  10. +1
    -1
      src/states/sandbox-state.cpp

+ 1
- 0
src/entity/components/component-type.hpp View File

@ -31,6 +31,7 @@ enum class ComponentType
MODEL, MODEL,
STEERING, STEERING,
SOUND_SOURCE, SOUND_SOURCE,
TERRAIN_PATCH,
TOOL, TOOL,
TRANSFORM TRANSFORM
}; };

+ 29
- 0
src/entity/components/terrain-patch-component.cpp View File

@ -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 "terrain-patch-component.hpp"
ComponentBase* TerrainPatchComponent::clone() const
{
TerrainPatchComponent* component = new TerrainPatchComponent();
component->position = position;
return component;
}

+ 37
- 0
src/entity/components/terrain-patch-component.hpp View File

@ -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 TERRAIN_PATCH_COMPONENT_HPP
#define TERRAIN_PATCH_COMPONENT_HPP
#include "../component.hpp"
#include "component-type.hpp"
#include <tuple>
class TerrainPatchComponent: public Component<ComponentType::TERRAIN_PATCH>
{
public:
virtual ComponentBase* clone() const;
// Position in integer terrain coordinates
std::tuple<int, int> position;
};
#endif // TERRAIN_PATCH_COMPONENT_HPP

+ 360
- 0
src/entity/systems/terrain-system.cpp View File

@ -0,0 +1,360 @@
/*
* 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 "terrain-system.hpp"
#include "graphics/vertex-format.hpp"
TerrainSystem::TerrainSystem(ComponentManager* componentManager):
System(componentManager),
terrainCreationGroup(componentManager),
terrainGroup(componentManager)
{
terrainCreationGroup.addGroupObserver(this);
terrainGroup.addGroupObserver(this);
patchSize = 100.0f;
}
TerrainSystem::~TerrainSystem()
{}
void TerrainSystem::update(float t, float dt)
{
auto members = terrainGroup.getMembers();
for (const TerrainGroup::Member* member: *members)
{
ModelComponent* model = std::get<0>(member->components);
TerrainPatchComponent* patch = std::get<1>(member->components);
TransformComponent* transform = std::get<2>(member->components);
}
}
void TerrainSystem::memberRegistered(const TerrainCreationGroup::Member* member)
{
TerrainPatchComponent* patch = std::get<0>(member->components);
TransformComponent* transform = std::get<1>(member->components);
// Generate a subdivided plane mesh
TriangleMesh* patchMesh = generatePlane(5);
// Generate a model from the subdivided plane
Model* patchModel = generateModel(patchMesh);
// Add model component to the entity
ModelComponent* model = new ModelComponent();
model->model.setModel(patchModel);
componentManager->addComponent(member->entity, model);
// Set scale of the transform component
transform->transform.scale = Vector3(patchSize);
transform->transform.translation = Vector3(std::get<0>(patch->position), 0.0f, std::get<1>(patch->position)) * patchSize;
}
void TerrainSystem::memberUnregistered(const TerrainCreationGroup::Member* member)
{}
void TerrainSystem::memberRegistered(const TerrainGroup::Member* member)
{
// Add terrain patch to the patch map
TerrainPatchComponent* patch = std::get<1>(member->components);
patchMap[patch->position] = member;
}
void TerrainSystem::memberUnregistered(const TerrainGroup::Member* member)
{
// Remove terrain patch from the patch map
TerrainPatchComponent* patch = std::get<1>(member->components);
auto it = patchMap.find(patch->position);
if (it != patchMap.end())
{
patchMap.erase(it);
}
// TODO: free created terrain patch model
}
TriangleMesh* TerrainSystem::generatePlane(int subdivisions)
{
//std::size_t quadCount = std::pow(4, subdivisions);
//std::size_t triangleCount = quadCount * 2;
std::size_t columns = std::pow(2, subdivisions);
std::size_t rows = columns;
std::size_t vertexCount = (columns + 1) * (rows + 1);
float vertexIncrement = 1.0f / static_cast<float>(columns);
// Generate vertices
std::vector<Vector3> vertices;
Vector3 position(0.0f);
position.z = -0.5f;
for (std::size_t i = 0; i <= rows; ++i)
{
position.x = -0.5f;
for (std::size_t j = 0; j <= columns; ++j)
{
vertices.push_back(position);
position.x += vertexIncrement;
}
position.z += vertexIncrement;
}
// Generate indices
std::vector<std::size_t> indices;
for (std::size_t i = 0; i < rows; ++i)
{
for (std::size_t j = 0; j < columns; ++j)
{
unsigned int a = i * (columns + 1) + j;
unsigned int b = (i + 1) * (columns + 1) + j;
unsigned int c = i * (columns + 1) + j + 1;
unsigned int d = (i + 1) * (columns + 1) + j + 1;
indices.push_back(a);
indices.push_back(b);
indices.push_back(c);
indices.push_back(c);
indices.push_back(b);
indices.push_back(d);
}
}
return new TriangleMesh(vertices, indices);
/*
// Generate navmesh
surfaceNavmesh.create(surfaceVertices, surfaceIndices);
// Calculate vertex normals
calculateSurfaceNormals();
// Create and load VAO, VBO, and IBO
glGenVertexArrays(1, &surfaceVAO);
glBindVertexArray(surfaceVAO);
glGenBuffers(1, &surfaceVBO);
glBindBuffer(GL_ARRAY_BUFFER, surfaceVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * surfaceVertexSize * surfaceVertexCount, surfaceVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(EMERGENT_VERTEX_POSITION);
glVertexAttribPointer(EMERGENT_VERTEX_POSITION, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 0 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_NORMAL);
glVertexAttribPointer(EMERGENT_VERTEX_NORMAL, 3, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 3 * sizeof(float));
glEnableVertexAttribArray(EMERGENT_VERTEX_TEXCOORD);
glVertexAttribPointer(EMERGENT_VERTEX_TEXCOORD, 2, GL_FLOAT, GL_FALSE, surfaceVertexSize * sizeof(float), (char*)0 + 6 * sizeof(float));
glGenBuffers(1, &surfaceIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surfaceIBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * surfaceIndexCount, surfaceIndexData, GL_STATIC_DRAW);
// Setup material
//surfaceMaterial.flags = static_cast<unsigned int>(PhysicalMaterial::Flags::OBJECT);
// Setup buffers
surfaceModel.setVAO(surfaceVAO);
surfaceModel.setVBO(surfaceVBO);
surfaceModel.setIBO(surfaceIBO);
// Create model group
Model::Group* group = new Model::Group();
group->name = "default";
group->material = nullptr;//&surfaceMaterial;
group->indexOffset = 0;
group->triangleCount = surfaceTriangleCount;
// Add group to the model
surfaceModel.addGroup(group);
// Set model bounds
surfaceModel.setBounds(surfaceNavmesh.getBounds());
*/
}
Model* TerrainSystem::generateModel(TriangleMesh* mesh)
{
std::size_t triangleCount = mesh->getTriangles()->size();
// Vertex position + vertex normal
std::size_t vertexSize = 3 + 3;
std::size_t vertexCount = triangleCount * 3;
#if defined(DEBUG)
const Vector3 barycentricCoordinates[3] =
{
Vector3(1, 0, 0),
Vector3(0, 1, 0),
Vector3(0, 0, 1)
};
vertexSize += 3;
#endif // DEBUG
// Generate vertex data
float* vertexData = new float[vertexSize * vertexCount];
float* v = vertexData;
for (std::size_t i = 0; i < triangleCount; ++i)
{
const TriangleMesh::Triangle* triangle = (*mesh->getTriangles())[i];
const TriangleMesh::Vertex* a = triangle->edge->vertex;
const TriangleMesh::Vertex* b = triangle->edge->next->vertex;
const TriangleMesh::Vertex* c = triangle->edge->previous->vertex;
const TriangleMesh::Vertex* abc[] = {a, b, c};
const Vector3& normal = triangle->normal;
for (std::size_t j = 0; j < 3; ++j)
{
*(v++) = abc[j]->position[0];
*(v++) = abc[j]->position[1];
*(v++) = abc[j]->position[2];
*(v++) = normal.x;
*(v++) = normal.y;
*(v++) = normal.z;
#if defined(DEBUG)
{
*(v++) = barycentricCoordinates[j].x;
*(v++) = barycentricCoordinates[j].y;
*(v++) = barycentricCoordinates[j].z;
}
#endif // DEBUG
}
// Calculate smoothed vertex normal
/*
Vector3 normal(0.0f);
TriangleMesh::Edge* start = vertex->edge;
TriangleMesh::Edge* e = start;
do
{
normal += e->triangle->normal;
e = e->previous->symmetric;
}
while (e != start && e != nullptr);
normal = glm::normalize(normal);
*/
}
// Generate index data
std::size_t indexCount = triangleCount * 3;
std::uint32_t* indexData = new std::uint32_t[indexCount];
std::uint32_t* index = indexData;
for (std::size_t i = 0; i < triangleCount; ++i)
{
*(index++) = i * 3;
*(index++) = i * 3 + 1;
*(index++) = i * 3 + 2;
}
// Calculate AABB bounds
AABB bounds;
bounds.setMin(mesh->getVertices()->front()->position);
bounds.setMax(mesh->getVertices()->front()->position);
for (TriangleMesh::Vertex* vertex: *mesh->getVertices())
{
bounds.add(vertex->position);
}
GLuint vao;
GLuint vbo;
GLuint ibo;
// Generate and bind VAO
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Generate and bind VBO, then upload vertex data
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertexCount, vertexData, GL_STATIC_DRAW);
// Setup vertex attribute arrays
std::size_t attribOffset = 0;
std::size_t attribSize = 0;
// Vertex position attribute
attribSize = 3;
glEnableVertexAttribArray(VERTEX_POSITION);
glVertexAttribPointer(VERTEX_POSITION, attribSize, GL_FLOAT, GL_FALSE, sizeof(float) * vertexSize, (char*)0 + attribOffset * sizeof(float));
attribOffset += attribSize;
// Vertex normal attribute
attribSize = 3;
glEnableVertexAttribArray(VERTEX_NORMAL);
glVertexAttribPointer(VERTEX_NORMAL, attribSize, GL_FLOAT, GL_FALSE, sizeof(float) * vertexSize, (char*)0 + attribOffset * sizeof(float));
attribOffset += attribSize;
#if defined(DEBUG)
{
// Vertex barycentric coordinates attribute
attribSize = 3;
glEnableVertexAttribArray(VERTEX_BARYCENTRIC);
glVertexAttribPointer(VERTEX_BARYCENTRIC, attribSize, GL_FLOAT, GL_FALSE, sizeof(float) * vertexSize, (char*)0 + attribOffset * sizeof(float));
attribOffset += attribSize;
}
#endif // DEBUG
// Generate and bind IBO, then upload index data
glGenBuffers(1, &ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(std::uint32_t) * indexCount, indexData, GL_STATIC_DRAW);
// Delete vertex and index data
delete[] vertexData;
delete[] indexData;
// Create model
Model* model = new Model();
// Set model buffers
model->setVAO(vao);
model->setVBO(vbo);
model->setIBO(ibo);
// Set model bounds
model->setBounds(bounds);
// Create model material
Material* material = new Material();
material->setShader(nullptr);
ShaderVariable<Vector3>* albedo = material->addVariable<Vector3>("albedo");
ShaderVariable<float>* roughness = material->addVariable<float>("roughness");
ShaderVariable<float>* metalness = material->addVariable<float>("metalness");
ShaderVariable<float>* opacity = material->addVariable<float>("opacity");
albedo->setValue(Vector3(0.8f));
roughness->setValue(0.5f);
metalness->setValue(0.0f);
opacity->setValue(1.0f);
// Create model group
Model::Group* group = new Model::Group();
group->name = std::string();
group->material = material;
group->indexOffset = 0;
group->triangleCount = triangleCount;
// Add model group to the model
model->addGroup(group);
return model;
}
void TerrainSystem::projectMesh(TriangleMesh* mesh)
{
}

+ 103
- 0
src/entity/systems/terrain-system.hpp View File

@ -0,0 +1,103 @@
/*
* 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 TERRAIN_SYSTEM_HPP
#define TERRAIN_SYSTEM_HPP
#include "../entity-group.hpp"
#include "../components/model-component.hpp"
#include "../components/terrain-patch-component.hpp"
#include "../components/transform-component.hpp"
#include "../system.hpp"
#include <map>
// The terrain system creates a model and adds the model component to new members of this group.
typedef EntityGroup<TerrainPatchComponent, TransformComponent> TerrainCreationGroup;
typedef EntityGroup<ModelComponent, TerrainPatchComponent, TransformComponent> TerrainGroup;
class TerrainSystem:
public System,
public TerrainCreationGroup::Observer,
public TerrainGroup::Observer
{
public:
TerrainSystem(ComponentManager* componentManager);
virtual ~TerrainSystem();
virtual void update(float t, float dt);
private:
virtual void memberRegistered(const TerrainCreationGroup::Member* member);
virtual void memberUnregistered(const TerrainCreationGroup::Member* member);
virtual void memberRegistered(const TerrainGroup::Member* member);
virtual void memberUnregistered(const TerrainGroup::Member* member);
/**
* Generates a subdivided plane triangle mesh.
*
* 0 subdivisions:
* +---+
* | / |
* +---+
*
* 1 subdivision:
* +---+---+
* | / | / |
* +---+---+
* | / | / |
* +---+---+
*
* 2 subdivisions:
* +---+---+---+---+
* | / | / | / | / |
* +---+---+---+---+
* | / | / | / | / |
* +---+---+---+---+
* | / | / | / | / |
* +---+---+---+---+
* | / | / | / | / |
* +---+---+---+---+
*
* @param subdivisions Number of subdivisions.
* @return Generated triangle mesh.
*/
TriangleMesh* generatePlane(int subdivisions);
/**
* Generates a model from a triangle mesh.
*
* @param mesh Triangle mesh from which a model will be generated.
* @return Generated model.
*/
Model* generateModel(TriangleMesh* mesh);
/**
* Projects the vertices of a triangle mesh onto terrain brush geometry.
*/
void projectMesh(TriangleMesh* mesh);
TerrainCreationGroup terrainCreationGroup;
TerrainGroup terrainGroup;
std::map<std::tuple<int, int>, const TerrainGroup::Member*> patchMap;
float patchSize;
};
#endif // TERRAIN_SYSTEM_HPP

+ 64
- 86
src/game.cpp View File

@ -52,6 +52,7 @@
#include "entity/systems/behavior-system.hpp" #include "entity/systems/behavior-system.hpp"
#include "entity/systems/steering-system.hpp" #include "entity/systems/steering-system.hpp"
#include "entity/systems/particle-system.hpp" #include "entity/systems/particle-system.hpp"
#include "entity/systems/terrain-system.hpp"
#include "stb/stb_image_write.h" #include "stb/stb_image_write.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@ -158,20 +159,30 @@ Game::Game(int argc, char* argv[]):
currentState(nullptr), currentState(nullptr),
window(nullptr) window(nullptr)
{ {
// Get paths
// Form resource paths
dataPath = getDataPath(); dataPath = getDataPath();
configPath = getConfigPath(); configPath = getConfigPath();
controlsPath = configPath + "/controls/";
// Create config path if it doesn't exist
if (!pathExists(configPath))
// Create nonexistent config directories
std::vector<std::string> configPaths;
configPaths.push_back(configPath);
configPaths.push_back(controlsPath);
for (const std::string& path: configPaths)
{ {
createDirectory(configPath);
if (!pathExists(path))
{
createDirectory(path);
}
} }
// Setup resource manager // Setup resource manager
resourceManager = new ResourceManager(); resourceManager = new ResourceManager();
resourceManager->include(dataPath);
// Include resource search paths in order of priority
resourceManager->include(controlsPath);
resourceManager->include(configPath); resourceManager->include(configPath);
resourceManager->include(dataPath);
splashState = new SplashState(this); splashState = new SplashState(this);
sandboxState = new SandboxState(this); sandboxState = new SandboxState(this);
@ -251,6 +262,10 @@ void Game::setup()
setupControls(); setupControls();
setupGameplay(); setupGameplay();
#if defined(DEBUG)
toggleWireframe();
#endif // DEBUG
screenshotQueued = false; screenshotQueued = false;
@ -318,6 +333,7 @@ void Game::setup()
behaviorSystem = new BehaviorSystem(componentManager); behaviorSystem = new BehaviorSystem(componentManager);
steeringSystem = new SteeringSystem(componentManager); steeringSystem = new SteeringSystem(componentManager);
locomotionSystem = new LocomotionSystem(componentManager); locomotionSystem = new LocomotionSystem(componentManager);
terrainSystem = new TerrainSystem(componentManager);
particleSystem = new ParticleSystem(componentManager); particleSystem = new ParticleSystem(componentManager);
particleSystem->resize(1000); particleSystem->resize(1000);
particleSystem->setMaterial(smokeMaterial); particleSystem->setMaterial(smokeMaterial);
@ -335,10 +351,12 @@ void Game::setup()
systemManager->addSystem(locomotionSystem); systemManager->addSystem(locomotionSystem);
systemManager->addSystem(collisionSystem); systemManager->addSystem(collisionSystem);
systemManager->addSystem(toolSystem); systemManager->addSystem(toolSystem);
systemManager->addSystem(terrainSystem);
systemManager->addSystem(particleSystem); systemManager->addSystem(particleSystem);
systemManager->addSystem(cameraSystem); systemManager->addSystem(cameraSystem);
systemManager->addSystem(renderSystem); systemManager->addSystem(renderSystem);
/*
EntityID sidewalkPanel; EntityID sidewalkPanel;
sidewalkPanel = createInstanceOf("sidewalk-panel"); sidewalkPanel = createInstanceOf("sidewalk-panel");
@ -351,6 +369,7 @@ void Game::setup()
EntityID lollipop = createInstanceOf("lollipop"); EntityID lollipop = createInstanceOf("lollipop");
setTranslation(lollipop, Vector3(30.0f, 3.5f * 0.5f, -30.0f)); setTranslation(lollipop, Vector3(30.0f, 3.5f * 0.5f, -30.0f));
setRotation(lollipop, glm::angleAxis(glm::radians(8.85f), Vector3(1.0f, 0.0f, 0.0f))); setRotation(lollipop, glm::angleAxis(glm::radians(8.85f), Vector3(1.0f, 0.0f, 0.0f)));
*/
// Load navmesh // Load navmesh
TriangleMesh* navmesh = resourceManager->load<TriangleMesh>("sidewalk.mesh"); TriangleMesh* navmesh = resourceManager->load<TriangleMesh>("sidewalk.mesh");
@ -392,9 +411,11 @@ void Game::setup()
} }
EntityID tool0 = createInstanceOf("lens");
//EntityID tool0 = createInstanceOf("lens");
EntityID patch0 = createInstanceOf("terrain-patch");
changeState(splashState);
changeState(sandboxState);
} }
void Game::update(float t, float dt) void Game::update(float t, float dt)
@ -459,9 +480,7 @@ void Game::render()
} }
void Game::exit() void Game::exit()
{
saveControlProfile();
}
{}
void Game::handleEvent(const WindowResizedEvent& event) void Game::handleEvent(const WindowResizedEvent& event)
{ {
@ -484,7 +503,7 @@ void Game::handleEvent(const WindowResizedEvent& event)
void Game::handleEvent(const GamepadConnectedEvent& event) void Game::handleEvent(const GamepadConnectedEvent& event)
{ {
// Unmap all controls // Unmap all controls
inputMapper->reset();
inputRouter->reset();
// Reload control profile // Reload control profile
loadControlProfile(); loadControlProfile();
@ -668,7 +687,7 @@ void Game::setupGraphics()
defaultCompositor.addPass(lightingPass); defaultCompositor.addPass(lightingPass);
defaultCompositor.addPass(clearSilhouettePass); defaultCompositor.addPass(clearSilhouettePass);
defaultCompositor.addPass(silhouettePass); defaultCompositor.addPass(silhouettePass);
defaultCompositor.addPass(finalPass);
//defaultCompositor.addPass(finalPass);
defaultCompositor.load(nullptr); defaultCompositor.load(nullptr);
// Setup UI render pass // Setup UI render pass
@ -1281,40 +1300,12 @@ void Game::setupControls()
// Load control profile // Load control profile
loadControlProfile(); loadControlProfile();
/*
controlProfile.registerControl("exit", &exitControl);
controlProfile.registerControl("toggle-fullscreen", &toggleFullscreenControl);
controlProfile.registerControl("open-tool-menu", &openToolMenuControl);
controlProfile.registerControl("move-forward", &moveForwardControl);
controlProfile.registerControl("move-back", &moveBackControl);
controlProfile.registerControl("move-left", &moveLeftControl);
controlProfile.registerControl("move-right", &moveRightControl);
controlProfile.registerControl("orbit-ccw", &orbitCCWControl);
controlProfile.registerControl("orbit-cw", &orbitCWControl);
controlProfile.registerControl("zoom-in", &zoomInControl);
controlProfile.registerControl("zoom-out", &zoomOutControl);
controlProfile.registerControl("adjust-camera", &adjustCameraControl);
controlProfile.registerControl("drag-camera", &dragCameraControl);
controlProfile.registerControl("toggle-wireframe", &toggleWireframeControl);
controlProfile.registerControl("screenshot", &screenshotControl);
controlProfile.registerControl("toggle-edit-mode", &toggleEditModeControl);
*/
/*
// Save default control bindings
std::string bindingsPath = getConfigPath() + "/bindings/";
if (!pathExists(bindingsPath))
{
createDirectory(bindingsPath);
}
controlProfile.save(bindingsPath + "default.csv");
// Load control bindings
std::string controlProfileFilename = getConfigPath() + "/bindings/" + controlProfileName + ".csv";
controlProfile.load(controlProfileFilename, deviceManager);
*/
// Setup input mapper
inputMapper = new InputMapper(&eventDispatcher);
inputMapper->setCallback(std::bind(&Game::mapInput, this, std::placeholders::_1));
inputMapper->setControl(nullptr);
inputMapper->setEnabled(false);
} }
void Game::setupGameplay() void Game::setupGameplay()
@ -1332,7 +1323,6 @@ void Game::setupGameplay()
orbitCam->attachCamera(&camera); orbitCam->attachCamera(&camera);
freeCam = new FreeCam(); freeCam = new FreeCam();
freeCam->attachCamera(&camera); freeCam->attachCamera(&camera);
} }
void Game::resetSettings() void Game::resetSettings()
@ -1360,7 +1350,7 @@ void Game::resetSettings()
fontSizePT = 14.0f; fontSizePT = 14.0f;
// Set default control profile name // Set default control profile name
controlProfileName = "default";
controlProfileName = "default-controls";
} }
void Game::loadSettings() void Game::loadSettings()
@ -1413,7 +1403,7 @@ void Game::loadStrings()
void Game::loadControlProfile() void Game::loadControlProfile()
{ {
// Load control profile // Load control profile
std::string controlProfilePath = "/controls/" + controlProfileName + ".csv";
std::string controlProfilePath = controlProfileName + ".csv";
CSVTable* controlProfile = resourceManager->load<CSVTable>(controlProfilePath); CSVTable* controlProfile = resourceManager->load<CSVTable>(controlProfilePath);
for (const CSVRow& row: *controlProfile) for (const CSVRow& row: *controlProfile)
@ -1451,7 +1441,7 @@ void Game::loadControlProfile()
// Map control // Map control
if (scancode != Scancode::UNKNOWN) if (scancode != Scancode::UNKNOWN)
{ {
inputMapper->map(control, keyboard, scancode);
inputRouter->addMapping(KeyMapping(control, keyboard, scancode));
} }
} }
else if (deviceType == "mouse") else if (deviceType == "mouse")
@ -1480,7 +1470,7 @@ void Game::loadControlProfile()
} }
// Map control // Map control
inputMapper->map(control, mouse, axis);
inputRouter->addMapping(MouseMotionMapping(control, mouse, axis));
} }
else if (eventType == "wheel") else if (eventType == "wheel")
{ {
@ -1504,7 +1494,7 @@ void Game::loadControlProfile()
} }
// Map control // Map control
inputMapper->map(control, mouse, axis);
inputRouter->addMapping(MouseWheelMapping(control, mouse, axis));
} }
else if (eventType == "button") else if (eventType == "button")
{ {
@ -1517,7 +1507,7 @@ void Game::loadControlProfile()
stream >> button; stream >> button;
// Map control // Map control
inputMapper->map(control, mouse, button);
inputRouter->addMapping(MouseButtonMapping(control, mouse, button));
} }
else else
{ {
@ -1557,7 +1547,7 @@ void Game::loadControlProfile()
const std::list<Gamepad*>* gamepads = deviceManager->getGamepads(); const std::list<Gamepad*>* gamepads = deviceManager->getGamepads();
for (Gamepad* gamepad: *gamepads) for (Gamepad* gamepad: *gamepads)
{ {
inputMapper->map(control, gamepad, axis, negative);
inputRouter->addMapping(GamepadAxisMapping(control, gamepad, axis, negative));
} }
} }
else if (eventType == "button") else if (eventType == "button")
@ -1574,7 +1564,7 @@ void Game::loadControlProfile()
const std::list<Gamepad*>* gamepads = deviceManager->getGamepads(); const std::list<Gamepad*>* gamepads = deviceManager->getGamepads();
for (Gamepad* gamepad: *gamepads) for (Gamepad* gamepad: *gamepads)
{ {
inputMapper->map(control, gamepad, button);
inputRouter->addMapping(GamepadButtonMapping(control, gamepad, button));
} }
} }
else else
@ -1589,28 +1579,6 @@ void Game::loadControlProfile()
continue; continue;
} }
} }
// Map controls
/*
inputMapper->map(&exitControl, keyboard, Scancode::ESC);
inputMapper->map(&toggleFullscreenControl, keyboard, Scancode::F11);
inputMapper->map(&screenshotControl, keyboard, Scancode::F12);
inputMapper->map(&openToolMenuControl, keyboard, Scancode::LEFT_SHIFT);
inputMapper->map(&moveForwardControl, keyboard, Scancode::W);
inputMapper->map(&moveBackControl, keyboard, Scancode::S);
inputMapper->map(&moveLeftControl, keyboard, Scancode::A);
inputMapper->map(&moveRightControl, keyboard, Scancode::D);
inputMapper->map(&orbitCCWControl, keyboard, Scancode::Q);
inputMapper->map(&orbitCWControl, keyboard, Scancode::E);
inputMapper->map(&zoomInControl, mouse, MouseWheelAxis::POSITIVE_Y);
inputMapper->map(&zoomInControl, keyboard, Scancode::EQUAL);
inputMapper->map(&zoomOutControl, mouse, MouseWheelAxis::NEGATIVE_Y);
inputMapper->map(&zoomOutControl, keyboard, Scancode::MINUS);
inputMapper->map(&adjustCameraControl, mouse, 2);
inputMapper->map(&dragCameraControl, mouse, 3);
inputMapper->map(&toggleWireframeControl, keyboard, Scancode::V);
inputMapper->map(&toggleEditModeControl, keyboard, Scancode::TAB);
*/
} }
void Game::saveControlProfile() void Game::saveControlProfile()
@ -1626,7 +1594,7 @@ void Game::saveControlProfile()
Control* control = it->second; Control* control = it->second;
// Look up list of mappings for the control // Look up list of mappings for the control
const std::list<InputMapping*>* mappings = inputMapper->getMappings(control);
const std::list<InputMapping*>* mappings = inputRouter->getMappings(control);
if (!mappings) if (!mappings)
{ {
continue; continue;
@ -1772,13 +1740,6 @@ void Game::saveControlProfile()
} }
} }
} }
// Create controls directory if it doesn't exist
std::string controlsPath = getConfigPath() + "/controls/";
if (!pathExists(controlsPath))
{
createDirectory(controlsPath);
}
// Form full path to control profile file // Form full path to control profile file
std::string controlProfilePath = controlsPath + controlProfileName + ".csv"; std::string controlProfilePath = controlsPath + controlProfileName + ".csv";
@ -2104,6 +2065,25 @@ void Game::screenshot()
window->swapBuffers(); window->swapBuffers();
} }
void Game::mapInput(const InputMapping& mapping)
{
// Skip mouse motion events
if (mapping.getType() == InputMappingType::MOUSE_MOTION)
{
return;
}
// Add input mapping to input router
if (mapping.control != nullptr)
{
inputRouter->addMapping(mapping);
}
// Disable input mapping generation
inputMapper->setControl(nullptr);
inputMapper->setEnabled(false);
}
void Game::boxSelect(float x, float y, float w, float h) void Game::boxSelect(float x, float y, float w, float h)
{ {
boxSelectionContainer->setTranslation(Vector2(x, y)); boxSelectionContainer->setTranslation(Vector2(x, y));
@ -2116,8 +2096,6 @@ void Game::boxSelect(float x, float y, float w, float h)
boxSelectionContainer->setVisible(true); boxSelectionContainer->setVisible(true);
} }
void Game::fadeIn(float duration, const Vector3& color, std::function<void()> callback) void Game::fadeIn(float duration, const Vector3& color, std::function<void()> callback)
{ {
if (fadeInAnimation.isPlaying()) if (fadeInAnimation.isPlaying())

+ 11
- 2
src/game.hpp View File

@ -62,6 +62,7 @@ class ToolSystem;
class BehaviorSystem; class BehaviorSystem;
class SteeringSystem; class SteeringSystem;
class LocomotionSystem; class LocomotionSystem;
class TerrainSystem;
class ComponentBase; class ComponentBase;
enum class ComponentType; enum class ComponentType;
typedef std::vector<std::vector<std::string>> CSVTable; typedef std::vector<std::vector<std::string>> CSVTable;
@ -155,8 +156,11 @@ private:
void setTimeOfDay(float time); void setTimeOfDay(float time);
void toggleWireframe(); void toggleWireframe();
void screenshot();
void queueScreenshot(); void queueScreenshot();
void screenshot();
// Callback for the input mapper
void mapInput(const InputMapping& mapping);
public: public:
@ -184,6 +188,7 @@ public:
// Paths // Paths
std::string dataPath; std::string dataPath;
std::string configPath; std::string configPath;
std::string controlsPath;
// Settings // Settings
CSVTable* settingsTable; CSVTable* settingsTable;
@ -252,6 +257,9 @@ public:
// Map of control names // Map of control names
std::map<std::string, Control*> controlNameMap; std::map<std::string, Control*> controlNameMap;
// Input mapper
InputMapper* inputMapper;
// Logic // Logic
float time; float time;
float timestep; float timestep;
@ -380,7 +388,6 @@ public:
Lens* lens; Lens* lens;
Forceps* forceps; Forceps* forceps;
Brush* brush; Brush* brush;
ParticleSystem* particleSystem;
// ECS // ECS
EntityManager* entityManager; EntityManager* entityManager;
@ -394,6 +401,8 @@ public:
BehaviorSystem* behaviorSystem; BehaviorSystem* behaviorSystem;
SteeringSystem* steeringSystem; SteeringSystem* steeringSystem;
LocomotionSystem* locomotionSystem; LocomotionSystem* locomotionSystem;
ParticleSystem* particleSystem;
TerrainSystem* terrainSystem;
bool screenshotQueued; bool screenshotQueued;

+ 26
- 0
src/resources/entity-template-loader.cpp View File

@ -23,6 +23,7 @@
#include "../entity/components/ant-hill-component.hpp" #include "../entity/components/ant-hill-component.hpp"
#include "../entity/components/collision-component.hpp" #include "../entity/components/collision-component.hpp"
#include "../entity/components/model-component.hpp" #include "../entity/components/model-component.hpp"
#include "../entity/components/terrain-patch-component.hpp"
#include "../entity/components/tool-component.hpp" #include "../entity/components/tool-component.hpp"
#include "../entity/components/transform-component.hpp" #include "../entity/components/transform-component.hpp"
#include "../entity/entity-template.hpp" #include "../entity/entity-template.hpp"
@ -77,6 +78,30 @@ static ComponentBase* loadModelComponent(ResourceManager* resourceManager, const
return component; return component;
} }
static ComponentBase* loadTerrainPatchComponent(const std::vector<std::string>& parameters)
{
if (parameters.size() != 3)
{
throw std::runtime_error("loadTerrainPatchComponent(): Invalid parameter count.");
}
std::tuple<int, int> position;
std::stringstream stream;
for (std::size_t i = 1; i < parameters.size(); ++i)
{
stream << parameters[i];
if (i < parameters.size() - 1)
stream << ' ';
}
stream >> std::get<0>(position);
stream >> std::get<1>(position);
TerrainPatchComponent* component = new TerrainPatchComponent();
component->position = position;
return component;
}
static ComponentBase* loadToolComponent(const std::vector<std::string>& parameters) static ComponentBase* loadToolComponent(const std::vector<std::string>& parameters)
{ {
if (parameters.size() != 1) if (parameters.size() != 1)
@ -133,6 +158,7 @@ static ComponentBase* loadComponent(ResourceManager* resourceManager, const std:
if (parameters[0] == "ant-hill") return loadAntHillComponent(parameters); if (parameters[0] == "ant-hill") return loadAntHillComponent(parameters);
if (parameters[0] == "collision") return loadCollisionComponent(resourceManager, parameters); if (parameters[0] == "collision") return loadCollisionComponent(resourceManager, parameters);
if (parameters[0] == "model") return loadModelComponent(resourceManager, parameters); if (parameters[0] == "model") return loadModelComponent(resourceManager, parameters);
if (parameters[0] == "terrain-patch") return loadTerrainPatchComponent(parameters);
if (parameters[0] == "tool") return loadToolComponent(parameters); if (parameters[0] == "tool") return loadToolComponent(parameters);
if (parameters[0] == "transform") return loadTransformComponent(parameters); if (parameters[0] == "transform") return loadTransformComponent(parameters);

+ 1
- 0
src/resources/resource-manager.hpp View File

@ -129,6 +129,7 @@ T* ResourceManager::load(const std::string& path)
opened = true; opened = true;
data = ResourceLoader<T>::load(this, &fs); data = ResourceLoader<T>::load(this, &fs);
fs.close(); fs.close();
break;
} }
if (!opened) if (!opened)

+ 1
- 1
src/states/sandbox-state.cpp View File

@ -72,7 +72,7 @@ void SandboxState::enter()
toolIndex = 0; toolIndex = 0;
game->selectTool(toolIndex); game->selectTool(toolIndex);
//game->currentTool->setActive(false);
game->currentTool->setActive(false);
//game->mouse->warp(game->window, game->w / 2, game->h / 2); //game->mouse->warp(game->window, game->w / 2, game->h / 2);
zoom = 0.5f; zoom = 0.5f;

Loading…
Cancel
Save