💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

214 lines
6.1 KiB

/*
* 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 "resource-loader.hpp"
#include "resource-manager.hpp"
#include "string-table.hpp"
#include "../entity/components/ant-hill-component.hpp"
#include "../entity/components/collision-component.hpp"
#include "../entity/components/model-component.hpp"
#include "../entity/components/terrain-patch-component.hpp"
#include "../entity/components/tool-component.hpp"
#include "../entity/components/transform-component.hpp"
#include "../entity/entity-template.hpp"
#include <sstream>
#include <stdexcept>
static ComponentBase* loadAntHillComponent(const std::vector<std::string>& parameters)
{
if (parameters.size() != 1)
{
throw std::runtime_error("loadAntHillComponent(): Invalid parameter count.");
}
AntHillComponent* component = new AntHillComponent();
return component;
}
static ComponentBase* loadCollisionComponent(ResourceManager* resourceManager, const std::vector<std::string>& parameters)
{
if (parameters.size() != 2)
{
throw std::runtime_error("loadCollisionComponent(): Invalid parameter count.");
}
CollisionComponent* component = new CollisionComponent();
component->mesh = resourceManager->load<TriangleMesh>(parameters[1]);
return component;
}
static ComponentBase* loadModelComponent(ResourceManager* resourceManager, const std::vector<std::string>& parameters)
{
if (parameters.size() != 2)
{
throw std::runtime_error("loadModelComponent(): Invalid parameter count.");
}
std::string filename = parameters[1];
Model* model = resourceManager->load<Model>(filename);
if (!model)
{
std::string message = std::string("loadModelComponent(): Failed to load model \"") + filename + std::string("\"");
throw std::runtime_error(message);
}
ModelComponent* component = new ModelComponent();
component->model.setModel(model);
component->model.setPose(nullptr);
return component;
}
static ComponentBase* loadTerrainPatchComponent(const std::vector<std::string>& parameters)
{
if (parameters.size() != 4)
{
throw std::runtime_error("loadTerrainPatchComponent(): Invalid parameter count.");
}
int subdivisions;
std::tuple<int, int> position;
float size;
std::stringstream stream;
for (std::size_t i = 1; i < parameters.size(); ++i)
{
stream << parameters[i];
if (i < parameters.size() - 1)
stream << ' ';
}
stream >> subdivisions;
stream >> std::get<0>(position);
stream >> std::get<1>(position);
TerrainPatchComponent* component = new TerrainPatchComponent();
component->subdivisions = subdivisions;
component->position = position;
return component;
}
static ComponentBase* loadToolComponent(const std::vector<std::string>& parameters)
{
if (parameters.size() != 1)
{
throw std::runtime_error("loadToolComponent(): Invalid parameter count.");
}
ToolComponent* component = new ToolComponent();
component->active = true;
return component;
}
static ComponentBase* loadTransformComponent(const std::vector<std::string>& parameters)
{
if (parameters.size() != 11)
{
throw std::runtime_error("loadTransformComponent(): Invalid parameter count.");
}
Vector3 translation;
Quaternion rotation;
Vector3 scale;
std::stringstream stream;
for (std::size_t i = 1; i < parameters.size(); ++i)
{
stream << parameters[i];
if (i < parameters.size() - 1)
stream << ' ';
}
stream >> translation.x;
stream >> translation.y;
stream >> translation.z;
stream >> rotation.w;
stream >> rotation.x;
stream >> rotation.y;
stream >> rotation.z;
stream >> scale.x;
stream >> scale.y;
stream >> scale.z;
TransformComponent* component = new TransformComponent();
component->transform.translation = translation;
component->transform.rotation = rotation;
component->transform.scale = scale;
return component;
}
static ComponentBase* loadComponent(ResourceManager* resourceManager, const std::vector<std::string>& parameters)
{
if (parameters[0] == "ant-hill") return loadAntHillComponent(parameters);
if (parameters[0] == "collision") return loadCollisionComponent(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] == "transform") return loadTransformComponent(parameters);
std::string message = std::string("loadComponent(): Unknown component type \"") + parameters[0] + std::string("\"");
throw std::runtime_error(message);
}
template <>
EntityTemplate* ResourceLoader<EntityTemplate>::load(ResourceManager* resourceManager, std::istream* is)
{
std::list<ComponentBase*> components;
EntityTemplate* entityTemplate = nullptr;
// Load string table from input stream
StringTable* table = ResourceLoader<StringTable>::load(resourceManager, is);
// Ensure table is not empty.
if (!table || table->empty())
{
delete table;
return nullptr;
}
// Load components from table rows
for (const StringTableRow& row: *table)
{
// Skip empty rows and comments
if (row.empty() || row[0].empty() || row[0][0] == '#')
{
continue;
}
ComponentBase* component = loadComponent(resourceManager, row);
if (component != nullptr)
{
components.push_back(component);
}
}
// Create entity template and free loaded components
entityTemplate = new EntityTemplate(components);
for (ComponentBase* component: components)
{
delete component;
}
return entityTemplate;
}