Browse Source

Rename biome to ecoregion. Add ecoregion loader.

master
C. J. Howard 1 year ago
parent
commit
f54989f5d7
16 changed files with 970 additions and 212 deletions
  1. +1
    -1
      src/game/ant/cladogenesis.cpp
  2. +1
    -1
      src/game/ant/cladogenesis.hpp
  3. +8
    -4
      src/game/ant/gene-frequency-table.hpp
  4. +57
    -0
      src/game/ant/gene/loader/diet-loader.cpp
  5. +57
    -0
      src/game/ant/gene/loader/founding-mode-loader.cpp
  6. +57
    -0
      src/game/ant/gene/loader/nest-site-loader.cpp
  7. +3
    -0
      src/game/context.hpp
  8. +554
    -0
      src/game/ecoregion-loader.cpp
  9. +66
    -0
      src/game/ecoregion.hpp
  10. +0
    -170
      src/game/load.cpp
  11. +0
    -5
      src/game/load.hpp
  12. +1
    -0
      src/game/state/boot.cpp
  13. +2
    -1
      src/game/state/main-menu.cpp
  14. +20
    -16
      src/game/state/nest-selection.cpp
  15. +134
    -14
      src/game/world.cpp
  16. +9
    -0
      src/game/world.hpp

+ 1
- 1
src/game/ant/cladogenesis.cpp View File

@ -22,7 +22,7 @@
namespace game {
namespace ant {
genome* cladogenesis(gene_pool& pool, std::random_device& rng)
genome* cladogenesis(const gene_pool& pool, std::random_device& rng)
{
// Allocate genome
ant::genome* genome = new ant::genome();

+ 1
- 1
src/game/ant/cladogenesis.hpp View File

@ -35,7 +35,7 @@ namespace ant {
*
* @return New genome.
*/
genome* cladogenesis(gene_pool& pool, std::random_device& rng);
genome* cladogenesis(const gene_pool& pool, std::random_device& rng);
} // namespace ant
} // namespace game

+ 8
- 4
src/game/ant/gene-frequency-table.hpp View File

@ -25,7 +25,7 @@
namespace game {
namespace ant {
/**
* Gene frequency table.
*
@ -37,8 +37,8 @@ struct gene_frequency_table
/// Gene array.
std::vector<const T*> genes;
/// Gene discrete probability distribution.
std::discrete_distribution<std::size_t> distribution;
/// Weight array
std::vector<float> weights;
/**
* Samples a gene from the frequency table.
@ -50,8 +50,12 @@ struct gene_frequency_table
* @return Randomly sampled gene.
*/
template <class Generator>
const T* sample(Generator& g)
const T* sample(Generator& g) const
{
if (genes.empty())
return nullptr;
std::discrete_distribution<std::size_t> distribution(weights.begin(), weights.end());
return genes[distribution(g)];
}
};

+ 57
- 0
src/game/ant/gene/loader/diet-loader.cpp View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 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 "game/ant/gene/loader/gene-loader.hpp"
#include "resources/resource-loader.hpp"
#include "resources/resource-manager.hpp"
#include "resources/json.hpp"
#include "game/ant/gene/diet.hpp"
#include "math/angles.hpp"
#include "math/constants.hpp"
#include <stdexcept>
using namespace game::ant;
static void deserialize_diet_phene(phene::diet& phene, const json& phene_element, resource_manager* resource_manager)
{
}
template <>
gene::diet* resource_loader<gene::diet>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{
// Load JSON data
json* data = resource_loader<json>::load(resource_manager, file, path);
// Validate gene file
auto diet_element = data->find("diet");
if (diet_element == data->end())
throw std::runtime_error("Invalid diet gene.");
// Allocate gene
gene::diet* diet = new gene::diet();
// Deserialize gene
gene::deserialize_gene(*diet, &deserialize_diet_phene, *diet_element, resource_manager);
// Free JSON data
delete data;
return diet;
}

+ 57
- 0
src/game/ant/gene/loader/founding-mode-loader.cpp View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 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 "game/ant/gene/loader/gene-loader.hpp"
#include "resources/resource-loader.hpp"
#include "resources/resource-manager.hpp"
#include "resources/json.hpp"
#include "game/ant/gene/founding-mode.hpp"
#include "math/angles.hpp"
#include "math/constants.hpp"
#include <stdexcept>
using namespace game::ant;
static void deserialize_founding_mode_phene(phene::founding_mode& phene, const json& phene_element, resource_manager* resource_manager)
{
}
template <>
gene::founding_mode* resource_loader<gene::founding_mode>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{
// Load JSON data
json* data = resource_loader<json>::load(resource_manager, file, path);
// Validate gene file
auto founding_mode_element = data->find("founding_mode");
if (founding_mode_element == data->end())
throw std::runtime_error("Invalid founding mode gene.");
// Allocate gene
gene::founding_mode* founding_mode = new gene::founding_mode();
// Deserialize gene
gene::deserialize_gene(*founding_mode, &deserialize_founding_mode_phene, *founding_mode_element, resource_manager);
// Free JSON data
delete data;
return founding_mode;
}

+ 57
- 0
src/game/ant/gene/loader/nest-site-loader.cpp View File

@ -0,0 +1,57 @@
/*
* Copyright (C) 2021 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 "game/ant/gene/loader/gene-loader.hpp"
#include "resources/resource-loader.hpp"
#include "resources/resource-manager.hpp"
#include "resources/json.hpp"
#include "game/ant/gene/nest-site.hpp"
#include "math/angles.hpp"
#include "math/constants.hpp"
#include <stdexcept>
using namespace game::ant;
static void deserialize_nest_site_phene(phene::nest_site& phene, const json& phene_element, resource_manager* resource_manager)
{
}
template <>
gene::nest_site* resource_loader<gene::nest_site>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{
// Load JSON data
json* data = resource_loader<json>::load(resource_manager, file, path);
// Validate gene file
auto nest_site_element = data->find("nest_site");
if (nest_site_element == data->end())
throw std::runtime_error("Invalid nest site gene.");
// Allocate gene
gene::nest_site* nest_site = new gene::nest_site();
// Deserialize gene
gene::deserialize_gene(*nest_site, &deserialize_nest_site_phene, *nest_site_element, resource_manager);
// Free JSON data
delete data;
return nest_site;
}

+ 3
- 0
src/game/context.hpp View File

@ -54,6 +54,7 @@
#include "application.hpp"
#include "game/state/base.hpp"
#include "game/loop.hpp"
#include "game/ecoregion.hpp"
#include "state-machine.hpp"
#include "debug/performance-sampler.hpp"
#include <filesystem>
@ -293,6 +294,8 @@ struct context
game::system::proteome* proteome_system;
double3 rgb_wavelengths;
const ecoregion* active_ecoregion;
};
} // namespace game

+ 554
- 0
src/game/ecoregion-loader.cpp View File

@ -0,0 +1,554 @@
/*
* Copyright (C) 2021 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 "game/ecoregion.hpp"
#include "resources/resource-loader.hpp"
#include "resources/resource-manager.hpp"
#include "resources/json.hpp"
#include <stdexcept>
template <>
game::ecoregion* resource_loader<game::ecoregion>::load(resource_manager* resource_manager, PHYSFS_File* file, const std::filesystem::path& path)
{
// Load JSON data
json* data = resource_loader<json>::load(resource_manager, file, path);
// Validate ecoregion file
auto ecoregion_element = data->find("ecoregion");
if (ecoregion_element == data->end())
throw std::runtime_error("Invalid ecoregion file.");
// Allocate and init ecoregion
game::ecoregion* ecoregion = new game::ecoregion();
ecoregion->elevation = 0.0f;
ecoregion->latitude = 0.0f;
ecoregion->longitude = 0.0f;
ecoregion->terrain_material = nullptr;
ecoregion->horizon_material = nullptr;
if (auto element = ecoregion_element->find("name"); element != ecoregion_element->end())
ecoregion->name = element->get<std::string>();
if (auto location_element = ecoregion_element->find("location"); location_element != ecoregion_element->end())
{
if (auto element = location_element->find("elevation"); element != location_element->end())
ecoregion->elevation = element->get<float>();
if (auto element = location_element->find("latitude"); element != location_element->end())
ecoregion->latitude = math::radians(element->get<float>());
if (auto element = location_element->find("longitude"); element != location_element->end())
ecoregion->longitude = math::radians(element->get<float>());
}
if (auto terrain_element = ecoregion_element->find("terrain"); terrain_element != ecoregion_element->end())
{
if (auto element = terrain_element->find("material"); element != terrain_element->end())
ecoregion->terrain_material = resource_manager->load<render::material>(element->get<std::string>());
if (auto element = terrain_element->find("albedo"); element != terrain_element->end())
ecoregion->terrain_albedo = {(*element)[0].get<float>(), (*element)[1].get<float>(), (*element)[2].get<float>()};
if (auto element = terrain_element->find("horizon_material"); element != terrain_element->end())
ecoregion->horizon_material = resource_manager->load<render::material>(element->get<std::string>());
}
// Load gene pools
if (auto gene_pools_element = ecoregion_element->find("gene_pools"); gene_pools_element != ecoregion_element->end())
{
// For each gene pool
for (auto gene_pool_element = gene_pools_element->begin(); gene_pool_element != gene_pools_element->end(); ++gene_pool_element)
{
// Allocate gene pool
ecoregion->gene_pools.resize(ecoregion->gene_pools.size() + 1);
game::ant::gene_pool& gene_pool = ecoregion->gene_pools.back();
// Read gene pool name
if (auto name_element = gene_pool_element->find("name"); name_element != gene_pool_element->end())
gene_pool.name = name_element->get<std::string>();
// Load genes
if (auto genes_element = gene_pool_element->find("genes"); genes_element != gene_pool_element->end())
{
// Load antennae genes
if (auto antennae_elements = genes_element->find("antennae"); antennae_elements != genes_element->end())
{
for (auto antennae_element = antennae_elements->begin(); antennae_element != antennae_elements->end(); ++antennae_element)
{
float weight = 0.0f;
const game::ant::gene::antennae* gene = nullptr;
if (auto weight_element = antennae_element->find("weight"); weight_element != antennae_element->end())
weight = weight_element->get<float>();
if (auto gene_element = antennae_element->find("gene"); gene_element != antennae_element->end())
gene = resource_manager->load<game::ant::gene::antennae>(gene_element->get<std::string>());
if (gene)
{
gene_pool.antennae.weights.push_back(weight);
gene_pool.antennae.genes.push_back(gene);
}
}
}
// Load body size genes
if (auto body_size_elements = genes_element->find("body_size"); body_size_elements != genes_element->end())
{
for (auto body_size_element = body_size_elements->begin(); body_size_element != body_size_elements->end(); ++body_size_element)
{
float weight = 0.0f;
const game::ant::gene::body_size* gene = nullptr;
if (auto weight_element = body_size_element->find("weight"); weight_element != body_size_element->end())
weight = weight_element->get<float>();
if (auto gene_element = body_size_element->find("gene"); gene_element != body_size_element->end())
gene = resource_manager->load<game::ant::gene::body_size>(gene_element->get<std::string>());
if (gene)
{
gene_pool.body_size.weights.push_back(weight);
gene_pool.body_size.genes.push_back(gene);
}
}
}
// Load cocoon genes
if (auto cocoon_elements = genes_element->find("cocoon"); cocoon_elements != genes_element->end())
{
for (auto cocoon_element = cocoon_elements->begin(); cocoon_element != cocoon_elements->end(); ++cocoon_element)
{
float weight = 0.0f;
const game::ant::gene::cocoon* gene = nullptr;
if (auto weight_element = cocoon_element->find("weight"); weight_element != cocoon_element->end())
weight = weight_element->get<float>();
if (auto gene_element = cocoon_element->find("gene"); gene_element != cocoon_element->end())
gene = resource_manager->load<game::ant::gene::cocoon>(gene_element->get<std::string>());
if (gene)
{
gene_pool.cocoon.weights.push_back(weight);
gene_pool.cocoon.genes.push_back(gene);
}
}
}
// Load diet genes
if (auto diet_elements = genes_element->find("diet"); diet_elements != genes_element->end())
{
for (auto diet_element = diet_elements->begin(); diet_element != diet_elements->end(); ++diet_element)
{
float weight = 0.0f;
const game::ant::gene::diet* gene = nullptr;
if (auto weight_element = diet_element->find("weight"); weight_element != diet_element->end())
weight = weight_element->get<float>();
if (auto gene_element = diet_element->find("gene"); gene_element != diet_element->end())
gene = resource_manager->load<game::ant::gene::diet>(gene_element->get<std::string>());
if (gene)
{
gene_pool.diet.weights.push_back(weight);
gene_pool.diet.genes.push_back(gene);
}
}
}
// Load egg genes
if (auto egg_elements = genes_element->find("egg"); egg_elements != genes_element->end())
{
for (auto egg_element = egg_elements->begin(); egg_element != egg_elements->end(); ++egg_element)
{
float weight = 0.0f;
const game::ant::gene::egg* gene = nullptr;
if (auto weight_element = egg_element->find("weight"); weight_element != egg_element->end())
weight = weight_element->get<float>();
if (auto gene_element = egg_element->find("gene"); gene_element != egg_element->end())
gene = resource_manager->load<game::ant::gene::egg>(gene_element->get<std::string>());
if (gene)
{
gene_pool.egg.weights.push_back(weight);
gene_pool.egg.genes.push_back(gene);
}
}
}
// Load eyes genes
if (auto eyes_elements = genes_element->find("eyes"); eyes_elements != genes_element->end())
{
for (auto eyes_element = eyes_elements->begin(); eyes_element != eyes_elements->end(); ++eyes_element)
{
float weight = 0.0f;
const game::ant::gene::eyes* gene = nullptr;
if (auto weight_element = eyes_element->find("weight"); weight_element != eyes_element->end())
weight = weight_element->get<float>();
if (auto gene_element = eyes_element->find("gene"); gene_element != eyes_element->end())
gene = resource_manager->load<game::ant::gene::eyes>(gene_element->get<std::string>());
if (gene)
{
gene_pool.eyes.weights.push_back(weight);
gene_pool.eyes.genes.push_back(gene);
}
}
}
// Load foraging time genes
if (auto foraging_time_elements = genes_element->find("foraging_time"); foraging_time_elements != genes_element->end())
{
for (auto foraging_time_element = foraging_time_elements->begin(); foraging_time_element != foraging_time_elements->end(); ++foraging_time_element)
{
float weight = 0.0f;
const game::ant::gene::foraging_time* gene = nullptr;
if (auto weight_element = foraging_time_element->find("weight"); weight_element != foraging_time_element->end())
weight = weight_element->get<float>();
if (auto gene_element = foraging_time_element->find("gene"); gene_element != foraging_time_element->end())
gene = resource_manager->load<game::ant::gene::foraging_time>(gene_element->get<std::string>());
if (gene)
{
gene_pool.foraging_time.weights.push_back(weight);
gene_pool.foraging_time.genes.push_back(gene);
}
}
}
// Load founding mode genes
if (auto founding_mode_elements = genes_element->find("founding_mode"); founding_mode_elements != genes_element->end())
{
for (auto founding_mode_element = founding_mode_elements->begin(); founding_mode_element != founding_mode_elements->end(); ++founding_mode_element)
{
float weight = 0.0f;
const game::ant::gene::founding_mode* gene = nullptr;
if (auto weight_element = founding_mode_element->find("weight"); weight_element != founding_mode_element->end())
weight = weight_element->get<float>();
if (auto gene_element = founding_mode_element->find("gene"); gene_element != founding_mode_element->end())
gene = resource_manager->load<game::ant::gene::founding_mode>(gene_element->get<std::string>());
if (gene)
{
gene_pool.founding_mode.weights.push_back(weight);
gene_pool.founding_mode.genes.push_back(gene);
}
}
}
// Load gaster genes
if (auto gaster_elements = genes_element->find("gaster"); gaster_elements != genes_element->end())
{
for (auto gaster_element = gaster_elements->begin(); gaster_element != gaster_elements->end(); ++gaster_element)
{
float weight = 0.0f;
const game::ant::gene::gaster* gene = nullptr;
if (auto weight_element = gaster_element->find("weight"); weight_element != gaster_element->end())
weight = weight_element->get<float>();
if (auto gene_element = gaster_element->find("gene"); gene_element != gaster_element->end())
gene = resource_manager->load<game::ant::gene::gaster>(gene_element->get<std::string>());
if (gene)
{
gene_pool.gaster.weights.push_back(weight);
gene_pool.gaster.genes.push_back(gene);
}
}
}
// Load head genes
if (auto head_elements = genes_element->find("head"); head_elements != genes_element->end())
{
for (auto head_element = head_elements->begin(); head_element != head_elements->end(); ++head_element)
{
float weight = 0.0f;
const game::ant::gene::head* gene = nullptr;
if (auto weight_element = head_element->find("weight"); weight_element != head_element->end())
weight = weight_element->get<float>();
if (auto gene_element = head_element->find("gene"); gene_element != head_element->end())
gene = resource_manager->load<game::ant::gene::head>(gene_element->get<std::string>());
if (gene)
{
gene_pool.head.weights.push_back(weight);
gene_pool.head.genes.push_back(gene);
}
}
}
// Load larva genes
if (auto larva_elements = genes_element->find("larva"); larva_elements != genes_element->end())
{
for (auto larva_element = larva_elements->begin(); larva_element != larva_elements->end(); ++larva_element)
{
float weight = 0.0f;
const game::ant::gene::larva* gene = nullptr;
if (auto weight_element = larva_element->find("weight"); weight_element != larva_element->end())
weight = weight_element->get<float>();
if (auto gene_element = larva_element->find("gene"); gene_element != larva_element->end())
gene = resource_manager->load<game::ant::gene::larva>(gene_element->get<std::string>());
if (gene)
{
gene_pool.larva.weights.push_back(weight);
gene_pool.larva.genes.push_back(gene);
}
}
}
// Load legs genes
if (auto legs_elements = genes_element->find("legs"); legs_elements != genes_element->end())
{
for (auto legs_element = legs_elements->begin(); legs_element != legs_elements->end(); ++legs_element)
{
float weight = 0.0f;
const game::ant::gene::legs* gene = nullptr;
if (auto weight_element = legs_element->find("weight"); weight_element != legs_element->end())
weight = weight_element->get<float>();
if (auto gene_element = legs_element->find("gene"); gene_element != legs_element->end())
gene = resource_manager->load<game::ant::gene::legs>(gene_element->get<std::string>());
if (gene)
{
gene_pool.legs.weights.push_back(weight);
gene_pool.legs.genes.push_back(gene);
}
}
}
// Load mandibles genes
if (auto mandibles_elements = genes_element->find("mandibles"); mandibles_elements != genes_element->end())
{
for (auto mandibles_element = mandibles_elements->begin(); mandibles_element != mandibles_elements->end(); ++mandibles_element)
{
float weight = 0.0f;
const game::ant::gene::mandibles* gene = nullptr;
if (auto weight_element = mandibles_element->find("weight"); weight_element != mandibles_element->end())
weight = weight_element->get<float>();
if (auto gene_element = mandibles_element->find("gene"); gene_element != mandibles_element->end())
gene = resource_manager->load<game::ant::gene::mandibles>(gene_element->get<std::string>());
if (gene)
{
gene_pool.mandibles.weights.push_back(weight);
gene_pool.mandibles.genes.push_back(gene);
}
}
}
// Load mesosoma genes
if (auto mesosoma_elements = genes_element->find("mesosoma"); mesosoma_elements != genes_element->end())
{
for (auto mesosoma_element = mesosoma_elements->begin(); mesosoma_element != mesosoma_elements->end(); ++mesosoma_element)
{
float weight = 0.0f;
const game::ant::gene::mesosoma* gene = nullptr;
if (auto weight_element = mesosoma_element->find("weight"); weight_element != mesosoma_element->end())
weight = weight_element->get<float>();
if (auto gene_element = mesosoma_element->find("gene"); gene_element != mesosoma_element->end())
gene = resource_manager->load<game::ant::gene::mesosoma>(gene_element->get<std::string>());
if (gene)
{
gene_pool.mesosoma.weights.push_back(weight);
gene_pool.mesosoma.genes.push_back(gene);
}
}
}
// Load nest site genes
if (auto nest_site_elements = genes_element->find("nest_site"); nest_site_elements != genes_element->end())
{
for (auto nest_site_element = nest_site_elements->begin(); nest_site_element != nest_site_elements->end(); ++nest_site_element)
{
float weight = 0.0f;
const game::ant::gene::nest_site* gene = nullptr;
if (auto weight_element = nest_site_element->find("weight"); weight_element != nest_site_element->end())
weight = weight_element->get<float>();
if (auto gene_element = nest_site_element->find("gene"); gene_element != nest_site_element->end())
gene = resource_manager->load<game::ant::gene::nest_site>(gene_element->get<std::string>());
if (gene)
{
gene_pool.nest_site.weights.push_back(weight);
gene_pool.nest_site.genes.push_back(gene);
}
}
}
// Load ocelli genes
if (auto ocelli_elements = genes_element->find("ocelli"); ocelli_elements != genes_element->end())
{
for (auto ocelli_element = ocelli_elements->begin(); ocelli_element != ocelli_elements->end(); ++ocelli_element)
{
float weight = 0.0f;
const game::ant::gene::ocelli* gene = nullptr;
if (auto weight_element = ocelli_element->find("weight"); weight_element != ocelli_element->end())
weight = weight_element->get<float>();
if (auto gene_element = ocelli_element->find("gene"); gene_element != ocelli_element->end())
gene = resource_manager->load<game::ant::gene::ocelli>(gene_element->get<std::string>());
if (gene)
{
gene_pool.ocelli.weights.push_back(weight);
gene_pool.ocelli.genes.push_back(gene);
}
}
}
// Load pigmentation genes
if (auto pigmentation_elements = genes_element->find("pigmentation"); pigmentation_elements != genes_element->end())
{
for (auto pigmentation_element = pigmentation_elements->begin(); pigmentation_element != pigmentation_elements->end(); ++pigmentation_element)
{
float weight = 0.0f;
const game::ant::gene::pigmentation* gene = nullptr;
if (auto weight_element = pigmentation_element->find("weight"); weight_element != pigmentation_element->end())
weight = weight_element->get<float>();
if (auto gene_element = pigmentation_element->find("gene"); gene_element != pigmentation_element->end())
gene = resource_manager->load<game::ant::gene::pigmentation>(gene_element->get<std::string>());
if (gene)
{
gene_pool.pigmentation.weights.push_back(weight);
gene_pool.pigmentation.genes.push_back(gene);
}
}
}
// Load pilosity genes
if (auto pilosity_elements = genes_element->find("pilosity"); pilosity_elements != genes_element->end())
{
for (auto pilosity_element = pilosity_elements->begin(); pilosity_element != pilosity_elements->end(); ++pilosity_element)
{
float weight = 0.0f;
const game::ant::gene::pilosity* gene = nullptr;
if (auto weight_element = pilosity_element->find("weight"); weight_element != pilosity_element->end())
weight = weight_element->get<float>();
if (auto gene_element = pilosity_element->find("gene"); gene_element != pilosity_element->end())
gene = resource_manager->load<game::ant::gene::pilosity>(gene_element->get<std::string>());
if (gene)
{
gene_pool.pilosity.weights.push_back(weight);
gene_pool.pilosity.genes.push_back(gene);
}
}
}
// Load sculpturing genes
if (auto sculpturing_elements = genes_element->find("sculpturing"); sculpturing_elements != genes_element->end())
{
for (auto sculpturing_element = sculpturing_elements->begin(); sculpturing_element != sculpturing_elements->end(); ++sculpturing_element)
{
float weight = 0.0f;
const game::ant::gene::sculpturing* gene = nullptr;
if (auto weight_element = sculpturing_element->find("weight"); weight_element != sculpturing_element->end())
weight = weight_element->get<float>();
if (auto gene_element = sculpturing_element->find("gene"); gene_element != sculpturing_element->end())
gene = resource_manager->load<game::ant::gene::sculpturing>(gene_element->get<std::string>());
if (gene)
{
gene_pool.sculpturing.weights.push_back(weight);
gene_pool.sculpturing.genes.push_back(gene);
}
}
}
// Load sting genes
if (auto sting_elements = genes_element->find("sting"); sting_elements != genes_element->end())
{
for (auto sting_element = sting_elements->begin(); sting_element != sting_elements->end(); ++sting_element)
{
float weight = 0.0f;
const game::ant::gene::sting* gene = nullptr;
if (auto weight_element = sting_element->find("weight"); weight_element != sting_element->end())
weight = weight_element->get<float>();
if (auto gene_element = sting_element->find("gene"); gene_element != sting_element->end())
gene = resource_manager->load<game::ant::gene::sting>(gene_element->get<std::string>());
if (gene)
{
gene_pool.sting.weights.push_back(weight);
gene_pool.sting.genes.push_back(gene);
}
}
}
// Load waist genes
if (auto waist_elements = genes_element->find("waist"); waist_elements != genes_element->end())
{
for (auto waist_element = waist_elements->begin(); waist_element != waist_elements->end(); ++waist_element)
{
float weight = 0.0f;
const game::ant::gene::waist* gene = nullptr;
if (auto weight_element = waist_element->find("weight"); weight_element != waist_element->end())
weight = weight_element->get<float>();
if (auto gene_element = waist_element->find("gene"); gene_element != waist_element->end())
gene = resource_manager->load<game::ant::gene::waist>(gene_element->get<std::string>());
if (gene)
{
gene_pool.waist.weights.push_back(weight);
gene_pool.waist.genes.push_back(gene);
}
}
}
// Load wings genes
if (auto wings_elements = genes_element->find("wings"); wings_elements != genes_element->end())
{
for (auto wings_element = wings_elements->begin(); wings_element != wings_elements->end(); ++wings_element)
{
float weight = 0.0f;
const game::ant::gene::wings* gene = nullptr;
if (auto weight_element = wings_element->find("weight"); weight_element != wings_element->end())
weight = weight_element->get<float>();
if (auto gene_element = wings_element->find("gene"); gene_element != wings_element->end())
gene = resource_manager->load<game::ant::gene::wings>(gene_element->get<std::string>());
if (gene)
{
gene_pool.wings.weights.push_back(weight);
gene_pool.wings.genes.push_back(gene);
}
}
}
}
}
}
// Free JSON data
delete data;
return ecoregion;
}

+ 66
- 0
src/game/ecoregion.hpp View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2021 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 ANTKEEPER_GAME_ECOREGION_HPP
#define ANTKEEPER_GAME_ECOREGION_HPP
#include "utility/fundamental-types.hpp"
#include "render/material.hpp"
#include "game/ant/gene-pool.hpp"
#include <string>
#include <random>
namespace game {
/**
*
*/
struct ecoregion
{
/// Ecoregion name.
std::string name;
/// Elevation, in meters.
float elevation;
/// Latitude, in radians.
float latitude;
/// Longitude, in radians.
float longitude;
/// Terrain material.
render::material* terrain_material;
/// Terrain albedo.
float3 terrain_albedo;
/// Horizon material.
render::material* horizon_material;
/// Array of gene pools.
std::vector<ant::gene_pool> gene_pools;
/// Discrete probability distribution of gene pools.
std::discrete_distribution<std::size_t> gene_pool_distribution;
};
} // namespace game
#endif // ANTKEEPER_GAME_ECOREGION_HPP

+ 0
- 170
src/game/load.cpp View File

@ -43,176 +43,6 @@
namespace game {
namespace load {
void biome(game::context& ctx, const std::filesystem::path& path)
{
ctx.logger->push_task("Loading biome from \"" + path.string() + "\"");
/*
image img;
img.format(1, 4);
img.resize(2048, 2048);
auto width = img.get_width();
auto height = img.get_height();
unsigned char* pixels = (unsigned char*)img.data();
const float frequency = 400.0f;
float scale_x = 1.0f / static_cast<float>(width - 1) * frequency;
float scale_y = 1.0f / static_cast<float>(height - 1) * frequency;
std::for_each
(
std::execution::par_unseq,
img.begin<math::vector<unsigned char, 4>>(),
img.end<math::vector<unsigned char, 4>>(),
[pixels, width, height, scale_x, scale_y, frequency](auto& pixel)
{
const std::size_t i = &pixel - (math::vector<unsigned char, 4>*)pixels;
const std::size_t y = i / width;
const std::size_t x = i % width;
const float2 position =
{
static_cast<float>(x) * scale_x,
static_cast<float>(y) * scale_y
};
const auto
[
f1_sqr_distance,
f1_displacement,
f1_id
] = math::noise::voronoi::f1<float, 2>(position, 1.0f, {frequency, frequency});
const float f1_distance = std::sqrt(f1_sqr_distance);
const float2 uv = (position + f1_displacement) / frequency;
pixel =
{
static_cast<unsigned char>(std::min(255.0f, f1_distance * 255.0f)),
static_cast<unsigned char>(std::min(255.0f, uv[0] * 255.0f)),
static_cast<unsigned char>(std::min(255.0f, uv[1] * 255.0f)),
static_cast<unsigned char>(f1_id % 256)
};
}
);
stbi_flip_vertically_on_write(1);
stbi_write_tga((ctx.config_path / "gallery" / "voronoi-f1-400-nc8-2k.tga").string().c_str(), img.get_width(), img.get_height(), img.get_channel_count(), img.data());
*/
try
{
json* data = ctx.resource_manager->load<json>(path);
// Load location
if (auto location = data->find("location"); location != data->end())
{
double elevation = 0.0;
double latitude = 0.0;
double longitude = 0.0;
if (auto location_ele = location->find("elevation"); location_ele != location->end())
elevation = location_ele->get<double>();
else
ctx.logger->warning("Biome elevation undefined");
if (auto location_lat = location->find("latitude"); location_lat != location->end())
latitude = math::radians<double>(location_lat->get<double>());
else
ctx.logger->warning("Biome latitude undefined");
if (auto location_lon = location->find("longitude"); location_lon != location->end())
longitude = math::radians<double>(location_lon->get<double>());
else
ctx.logger->warning("Biome longitude undefined");
// Set location
game::world::set_location(ctx, elevation, latitude, longitude);
}
else
{
ctx.logger->warning("Biome location undefined");
}
// Setup sky
ctx.sky_pass->set_sky_model(ctx.resource_manager->load<render::model>("celestial-hemisphere.mdl"));
// Load terrain
if (auto terrain = data->find("terrain"); terrain != data->end())
{
if (auto material = terrain->find("material"); material != terrain->end())
{
render::material* terrain_material = ctx.resource_manager->load<render::material>(material->get<std::string>());
ctx.terrain_system->set_patch_material(terrain_material);
}
else
{
ctx.logger->warning("Biome terrain material undefined");
}
if (auto material = terrain->find("horizon_material"); material != terrain->end())
{
render::model* terrestrial_hemisphere_model = ctx.resource_manager->load<render::model>("terrestrial-hemisphere.mdl");
(*terrestrial_hemisphere_model->get_groups())[0]->set_material(ctx.resource_manager->load<render::material>(material->get<std::string>()));
ctx.ground_pass->set_ground_model(terrestrial_hemisphere_model);
}
else
{
ctx.logger->warning("Biome terrain horizon material undefined");
}
// Terrain elevation function
ctx.terrain_system->set_elevation_function
(
[](float x, float z) -> float
{
const float2 position = float2{x, z};
const std::size_t octaves = 3;
const float lacunarity = 1.5f;
const float gain = 0.5f;
const float fbm = math::noise::fbm
(
position * 0.005f,
octaves,
lacunarity,
gain
);
float y = fbm * 4.0f;
return y;
}
);
// Setup lighting
double3 terrain_albedo = {0, 0, 0};
if (terrain->contains("albedo"))
{
const auto& albedo_element = (*terrain)["albedo"];
terrain_albedo[0] = albedo_element[0].get<double>();
terrain_albedo[1]= albedo_element[1].get<double>();
terrain_albedo[2] = albedo_element[2].get<double>();
}
ctx.astronomy_system->set_bounce_albedo(terrain_albedo);
}
else
{
ctx.logger->warning("Biome terrain undefined");
}
}
catch (...)
{
ctx.logger->pop_task(EXIT_FAILURE);
}
ctx.logger->pop_task(EXIT_SUCCESS);
}
void colony(game::context& ctx, const std::filesystem::path& path)
{
ctx.logger->push_task("Loading colony from \"" + path.string() + "\"");

+ 0
- 5
src/game/load.hpp View File

@ -25,11 +25,6 @@
namespace game {
namespace load {
/**
* Loads a biome.
*/
void biome(game::context& ctx, const std::filesystem::path& path);
/**
* Loads a colony
*/

+ 1
- 0
src/game/state/boot.cpp View File

@ -133,6 +133,7 @@ boot::boot(game::context& ctx, int argc, char** argv):
setup_ui();
setup_debugging();
setup_loop();
ctx.active_ecoregion = nullptr;
}
catch (const std::exception& e)
{

+ 2
- 1
src/game/state/main-menu.cpp View File

@ -24,6 +24,7 @@
#include "game/world.hpp"
#include "game/load.hpp"
#include "game/menu.hpp"
#include "game/ecoregion.hpp"
#include "game/ant/swarm.hpp"
#include "render/passes/clear-pass.hpp"
#include "render/passes/ground-pass.hpp"
@ -247,7 +248,7 @@ main_menu::main_menu(game::context& ctx, bool fade_in):
{
game::world::cosmogenesis(ctx);
game::world::create_observer(ctx);
game::load::biome(ctx, "desert-scrub.bio");
game::world::enter_ecoregion(ctx, *ctx.resource_manager->load<game::ecoregion>("seedy-scrub.eco"));
}
// Set world time

+ 20
- 16
src/game/state/nest-selection.cpp View File

@ -56,6 +56,7 @@
#include "game/ant/morphogenesis.hpp"
#include "game/ant/phenome.hpp"
#include "game/ant/genome.hpp"
#include "game/ant/cladogenesis.hpp"
using namespace game::ant;
@ -68,25 +69,28 @@ nest_selection::nest_selection(game::context& ctx):
ctx.logger->push_task("Entering nest selection state");
ctx.logger->push_task("Loading genome");
ant::genome genome;
genome.antennae = ctx.resource_manager->load<ant::gene::antennae>("pogonomyrmex-antennae.dna");
genome.eyes = ctx.resource_manager->load<ant::gene::eyes>("pogonomyrmex-eyes.dna");
genome.gaster = ctx.resource_manager->load<ant::gene::gaster>("pogonomyrmex-gaster.dna");
genome.head = ctx.resource_manager->load<ant::gene::head>("pogonomyrmex-head.dna");
genome.legs = ctx.resource_manager->load<ant::gene::legs>("pogonomyrmex-legs.dna");
genome.mandibles = ctx.resource_manager->load<ant::gene::mandibles>("pogonomyrmex-mandibles.dna");
genome.mesosoma = ctx.resource_manager->load<ant::gene::mesosoma>("pogonomyrmex-mesosoma.dna");
genome.ocelli = ctx.resource_manager->load<ant::gene::ocelli>("ocelli-absent.dna");
genome.pigmentation = ctx.resource_manager->load<ant::gene::pigmentation>("rust-pigmentation.dna");
genome.sculpturing = ctx.resource_manager->load<ant::gene::sculpturing>("politus-sculpturing.dna");
genome.sting = ctx.resource_manager->load<ant::gene::sting>("pogonomyrmex-sting.dna");
genome.waist = ctx.resource_manager->load<ant::gene::waist>("pogonomyrmex-waist.dna");
genome.wings = ctx.resource_manager->load<ant::gene::wings>("wings-absent.dna");
ctx.logger->push_task("Generating genome");
std::random_device rng;
ant::genome* genome = ant::cladogenesis(ctx.active_ecoregion->gene_pools[0], rng);
// genome.antennae = ctx.resource_manager->load<ant::gene::antennae>("pogonomyrmex-antennae.dna");
// genome.eyes = ctx.resource_manager->load<ant::gene::eyes>("pogonomyrmex-eyes.dna");
// genome.gaster = ctx.resource_manager->load<ant::gene::gaster>("pogonomyrmex-gaster.dna");
// genome.head = ctx.resource_manager->load<ant::gene::head>("pogonomyrmex-head.dna");
// genome.legs = ctx.resource_manager->load<ant::gene::legs>("pogonomyrmex-legs.dna");
// genome.mandibles = ctx.resource_manager->load<ant::gene::mandibles>("pogonomyrmex-mandibles.dna");
// genome.mesosoma = ctx.resource_manager->load<ant::gene::mesosoma>("pogonomyrmex-mesosoma.dna");
// genome.ocelli = ctx.resource_manager->load<ant::gene::ocelli>("ocelli-absent.dna");
// genome.pigmentation = ctx.resource_manager->load<ant::gene::pigmentation>("rust-pigmentation.dna");
// genome.sculpturing = ctx.resource_manager->load<ant::gene::sculpturing>("politus-sculpturing.dna");
// genome.sting = ctx.resource_manager->load<ant::gene::sting>("pogonomyrmex-sting.dna");
// genome.waist = ctx.resource_manager->load<ant::gene::waist>("pogonomyrmex-waist.dna");
// genome.wings = ctx.resource_manager->load<ant::gene::wings>("wings-absent.dna");
ctx.logger->pop_task(EXIT_SUCCESS);
ctx.logger->push_task("Building worker phenome");
ant::phenome worker_phenome = ant::phenome(genome, ant::caste::worker);
ant::phenome worker_phenome = ant::phenome(*genome, ant::caste::worker);
ctx.logger->pop_task(EXIT_SUCCESS);
ctx.logger->push_task("Generating worker model");

+ 134
- 14
src/game/world.cpp View File

@ -17,46 +17,59 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/world.hpp"
#include "scene/text.hpp"
#include "physics/light/vmag.hpp"
#include "application.hpp"
#include "color/color.hpp"
#include "config.hpp"
#include "debug/logger.hpp"
#include "entity/archetype.hpp"
#include "entity/commands.hpp"
#include "game/component/atmosphere.hpp"
#include "game/component/blackbody.hpp"
#include "game/component/celestial-body.hpp"
#include "game/component/observer.hpp"
#include "game/component/orbit.hpp"
#include "game/component/terrain.hpp"
#include "game/component/transform.hpp"
#include "game/component/observer.hpp"
#include "game/system/astronomy.hpp"
#include "game/system/orbit.hpp"
#include "game/system/atmosphere.hpp"
#include "entity/commands.hpp"
#include "entity/archetype.hpp"
#include "game/system/orbit.hpp"
#include "game/system/terrain.hpp"
#include "game/world.hpp"
#include "geom/solid-angle.hpp"
#include "geom/spherical.hpp"
#include "gl/drawing-mode.hpp"
#include "gl/texture-filter.hpp"
#include "gl/texture-wrapping.hpp"
#include "gl/vertex-array.hpp"
#include "gl/vertex-attribute.hpp"
#include "gl/vertex-buffer.hpp"
#include "math/hash/hash.hpp"
#include "math/noise/noise.hpp"
#include "physics/light/photometry.hpp"
#include "physics/orbit/orbit.hpp"
#include "physics/light/vmag.hpp"
#include "physics/orbit/ephemeris.hpp"
#include "physics/time/gregorian.hpp"
#include "physics/orbit/orbit.hpp"
#include "physics/time/constants.hpp"
#include "physics/time/gregorian.hpp"
#include "physics/time/utc.hpp"
#include "render/material-flags.hpp"
#include "render/material.hpp"
#include "render/model.hpp"
#include "render/passes/ground-pass.hpp"
#include "render/passes/shadow-map-pass.hpp"
#include "render/passes/sky-pass.hpp"
#include "render/vertex-attribute.hpp"
#include "resources/image.hpp"
#include "resources/json.hpp"
#include "resources/resource-manager.hpp"
#include "scene/ambient-light.hpp"
#include "scene/directional-light.hpp"
#include "gl/texture-wrapping.hpp"
#include "gl/texture-filter.hpp"
#include "render/material-flags.hpp"
#include "geom/solid-angle.hpp"
#include "config.hpp"
#include "scene/text.hpp"
#include <algorithm>
#include <execution>
#include <fstream>
#include <iostream>
#include <stb/stb_image_write.h>
namespace game {
namespace world {
@ -524,5 +537,112 @@ void create_moon(game::context& ctx)
ctx.logger->pop_task(EXIT_SUCCESS);
}
void enter_ecoregion(game::context& ctx, const ecoregion& ecoregion)
{
/*
image img;
img.format(1, 4);
img.resize(2048, 2048);
auto width = img.get_width();
auto height = img.get_height();
unsigned char* pixels = (unsigned char*)img.data();
const float frequency = 400.0f;
float scale_x = 1.0f / static_cast<float>(width - 1) * frequency;
float scale_y = 1.0f / static_cast<float>(height - 1) * frequency;
std::for_each
(
std::execution::par_unseq,
img.begin<math::vector<unsigned char, 4>>(),
img.end<math::vector<unsigned char, 4>>(),
[pixels, width, height, scale_x, scale_y, frequency](auto& pixel)
{
const std::size_t i = &pixel - (math::vector<unsigned char, 4>*)pixels;
const std::size_t y = i / width;
const std::size_t x = i % width;
const float2 position =
{
static_cast<float>(x) * scale_x,
static_cast<float>(y) * scale_y
};
const auto
[
f1_sqr_distance,
f1_displacement,
f1_id
] = math::noise::voronoi::f1<float, 2>(position, 1.0f, {frequency, frequency});
const float f1_distance = std::sqrt(f1_sqr_distance);
const float2 uv = (position + f1_displacement) / frequency;
pixel =
{
static_cast<unsigned char>(std::min(255.0f, f1_distance * 255.0f)),
static_cast<unsigned char>(std::min(255.0f, uv[0] * 255.0f)),
static_cast<unsigned char>(std::min(255.0f, uv[1] * 255.0f)),
static_cast<unsigned char>(f1_id % 256)
};
}
);
stbi_flip_vertically_on_write(1);
stbi_write_tga((ctx.config_path / "gallery" / "voronoi-f1-400-nc8-2k.tga").string().c_str(), img.get_width(), img.get_height(), img.get_channel_count(), img.data());
*/
ctx.logger->push_task("Entering ecoregion " + ecoregion.name);
try
{
// Set active ecoregion
ctx.active_ecoregion = &ecoregion;
// Set location
game::world::set_location(ctx, ecoregion.elevation, ecoregion.latitude, ecoregion.longitude);
// Setup sky
ctx.sky_pass->set_sky_model(ctx.resource_manager->load<render::model>("celestial-hemisphere.mdl"));
render::model* terrestrial_hemisphere_model = ctx.resource_manager->load<render::model>("terrestrial-hemisphere.mdl");
(*terrestrial_hemisphere_model->get_groups())[0]->set_material(ecoregion.horizon_material);
ctx.ground_pass->set_ground_model(terrestrial_hemisphere_model);
// Setup terrain
ctx.terrain_system->set_patch_material(ecoregion.terrain_material);
ctx.terrain_system->set_elevation_function
(
[](float x, float z) -> float
{
const float2 position = float2{x, z};
const std::size_t octaves = 3;
const float lacunarity = 1.5f;
const float gain = 0.5f;
const float fbm = math::noise::fbm
(
position * 0.005f,
octaves,
lacunarity,
gain
);
float y = fbm * 4.0f;
return y;
}
);
ctx.astronomy_system->set_bounce_albedo(double3(ecoregion.terrain_albedo));
}
catch (...)
{
ctx.logger->pop_task(EXIT_FAILURE);
}
ctx.logger->pop_task(EXIT_SUCCESS);
}
} // namespace world
} // namespace game

+ 9
- 0
src/game/world.hpp View File

@ -21,6 +21,7 @@
#define ANTKEEPER_GAME_WORLD_HPP
#include "game/context.hpp"
#include "game/ecoregion.hpp"
namespace game {
@ -72,6 +73,14 @@ void set_time(game::context& ctx, int year, int month, int day, int hour, int mi
*/
void set_time_scale(game::context& ctx, double scale);
/**
* Enters a ecoregion.
*
* @param ctx Game context.
* @param ecoregion Ecoregion to enter.
*/
void enter_ecoregion(game::context& ctx, const ecoregion& ecoregion);
} // namespace menu
} // namespace game

Loading…
Cancel
Save