Browse Source

Replace ant gene JSON loaders with binary format loaders. Make string map file format little endian.

master
C. J. Howard 1 year ago
parent
commit
a017a8639a
65 changed files with 982 additions and 1026 deletions
  1. +1
    -0
      CMakeLists.txt
  2. +6
    -6
      src/engine/i18n/string-map.cpp
  3. +8
    -8
      src/game/ant/ant-caste-type.hpp
  4. +1
    -1
      src/game/ant/ant-cladogenesis.hpp
  5. +106
    -27
      src/game/ant/ant-morphogenesis.cpp
  6. +1
    -1
      src/game/ant/ant-morphogenesis.hpp
  7. +45
    -38
      src/game/ant/ant-phenome.cpp
  8. +2
    -2
      src/game/ant/ant-phenome.hpp
  9. +2
    -2
      src/game/ant/ant-species.hpp
  10. +1
    -1
      src/game/ant/ant-subcaste.hpp
  11. +2
    -2
      src/game/ant/ant-swarm.cpp
  12. +16
    -30
      src/game/ant/genes/ant-antennae-gene.cpp
  13. +13
    -7
      src/game/ant/genes/ant-antennae-gene.hpp
  14. +12
    -32
      src/game/ant/genes/ant-body-size-gene.cpp
  15. +11
    -5
      src/game/ant/genes/ant-body-size-gene.hpp
  16. +17
    -25
      src/game/ant/genes/ant-cocoon-gene.cpp
  17. +11
    -5
      src/game/ant/genes/ant-cocoon-gene.hpp
  18. +10
    -18
      src/game/ant/genes/ant-diet-gene.cpp
  19. +14
    -8
      src/game/ant/genes/ant-diet-gene.hpp
  20. +14
    -21
      src/game/ant/genes/ant-egg-gene.cpp
  21. +8
    -2
      src/game/ant/genes/ant-egg-gene.hpp
  22. +22
    -45
      src/game/ant/genes/ant-eyes-gene.cpp
  23. +17
    -11
      src/game/ant/genes/ant-eyes-gene.hpp
  24. +11
    -29
      src/game/ant/genes/ant-foraging-time-gene.cpp
  25. +12
    -6
      src/game/ant/genes/ant-foraging-time-gene.hpp
  26. +9
    -17
      src/game/ant/genes/ant-founding-mode-gene.cpp
  27. +9
    -3
      src/game/ant/genes/ant-founding-mode-gene.hpp
  28. +15
    -25
      src/game/ant/genes/ant-gaster-gene.cpp
  29. +11
    -5
      src/game/ant/genes/ant-gaster-gene.hpp
  30. +67
    -45
      src/game/ant/genes/ant-gene-loader.hpp
  31. +28
    -14
      src/game/ant/genes/ant-gene-type.hpp
  32. +26
    -10
      src/game/ant/genes/ant-gene.hpp
  33. +17
    -35
      src/game/ant/genes/ant-head-gene.cpp
  34. +15
    -9
      src/game/ant/genes/ant-head-gene.hpp
  35. +15
    -25
      src/game/ant/genes/ant-larva-gene.cpp
  36. +11
    -5
      src/game/ant/genes/ant-larva-gene.hpp
  37. +16
    -30
      src/game/ant/genes/ant-legs-gene.cpp
  38. +14
    -8
      src/game/ant/genes/ant-legs-gene.hpp
  39. +17
    -35
      src/game/ant/genes/ant-mandibles-gene.cpp
  40. +15
    -8
      src/game/ant/genes/ant-mandibles-gene.hpp
  41. +18
    -40
      src/game/ant/genes/ant-mesosoma-gene.cpp
  42. +15
    -9
      src/game/ant/genes/ant-mesosoma-gene.hpp
  43. +10
    -18
      src/game/ant/genes/ant-nest-site-gene.cpp
  44. +8
    -2
      src/game/ant/genes/ant-nest-site-gene.hpp
  45. +32
    -43
      src/game/ant/genes/ant-ocelli-gene.cpp
  46. +25
    -13
      src/game/ant/genes/ant-ocelli-gene.hpp
  47. +14
    -21
      src/game/ant/genes/ant-pigmentation-gene.cpp
  48. +8
    -2
      src/game/ant/genes/ant-pigmentation-gene.hpp
  49. +10
    -22
      src/game/ant/genes/ant-pilosity-gene.cpp
  50. +9
    -3
      src/game/ant/genes/ant-pilosity-gene.hpp
  51. +15
    -25
      src/game/ant/genes/ant-sculpturing-gene.cpp
  52. +10
    -4
      src/game/ant/genes/ant-sculpturing-gene.hpp
  53. +17
    -25
      src/game/ant/genes/ant-sting-gene.cpp
  54. +10
    -4
      src/game/ant/genes/ant-sting-gene.hpp
  55. +28
    -73
      src/game/ant/genes/ant-waist-gene.cpp
  56. +22
    -16
      src/game/ant/genes/ant-waist-gene.hpp
  57. +35
    -60
      src/game/ant/genes/ant-wings-gene.cpp
  58. +24
    -18
      src/game/ant/genes/ant-wings-gene.hpp
  59. +2
    -2
      src/game/components/ant-caste-component.hpp
  60. +1
    -1
      src/game/game.hpp
  61. +2
    -2
      src/game/spawn.cpp
  62. +2
    -2
      src/game/states/main-menu-state.cpp
  63. +5
    -3
      src/game/states/nest-selection-state.cpp
  64. +11
    -11
      src/game/states/nuptial-flight-state.cpp
  65. +1
    -1
      src/game/world.cpp

+ 1
- 0
CMakeLists.txt View File

@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.25)
option(APPLICATION_NAME "Application name" "Antkeeper")
option(APPLICATION_VERSION "Application version string" "0.0.0")
option(APPLICATION_AUTHOR "Application author" "C. J. Howard")

+ 6
- 6
src/engine/i18n/string-map.cpp View File

@ -39,17 +39,17 @@ void serializer::serialize(const i18n::string_map& map, serial
{
// Write number of entries
std::uint32_t size = static_cast<std::uint32_t>(map.size());
ctx.write32<std::endian::big>(reinterpret_cast<const std::byte*>(&size), 1);
ctx.write32<std::endian::little>(reinterpret_cast<const std::byte*>(&size), 1);
// Write entries
for (const auto& [key, value]: map)
{
// Write key
ctx.write32<std::endian::big>(reinterpret_cast<const std::byte*>(&key), 1);
ctx.write32<std::endian::little>(reinterpret_cast<const std::byte*>(&key), 1);
// Write string length
std::uint32_t length = static_cast<std::uint32_t>(value.length());
ctx.write32<std::endian::big>(reinterpret_cast<const std::byte*>(&length), 1);
ctx.write32<std::endian::little>(reinterpret_cast<const std::byte*>(&length), 1);
// Write string
ctx.write8(reinterpret_cast<const std::byte*>(value.data()), length);
@ -71,18 +71,18 @@ void deserializer::deserialize(i18n::string_map& map, deserial
// Read number of entries
std::uint32_t size = 0;
ctx.read32<std::endian::big>(reinterpret_cast<std::byte*>(&size), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&size), 1);
// Read entries
for (std::uint32_t i = 0; i < size; ++i)
{
// Read key
hash::fnv1a32_t key;
ctx.read32<std::endian::big>(reinterpret_cast<std::byte*>(&key), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&key), 1);
// Read string length
std::uint32_t length = 0;
ctx.read32<std::endian::big>(reinterpret_cast<std::byte*>(&length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&length), 1);
// Insert empty string into map
auto [iterator, inserted] = map.emplace

src/game/ant/ant-caste.hpp → src/game/ant/ant-caste-type.hpp View File

@ -17,8 +17,8 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GAME_ANT_CASTE_HPP
#define ANTKEEPER_GAME_ANT_CASTE_HPP
#ifndef ANTKEEPER_GAME_ANT_CASTE_TYPE_HPP
#define ANTKEEPER_GAME_ANT_CASTE_TYPE_HPP
#include <cstdint>
@ -27,19 +27,19 @@
*
* @see https://www.antwiki.org/wiki/Caste_Terminology
*/
enum class ant_caste: std::uint8_t
enum class ant_caste_type: std::uint8_t
{
/// Queen caste.
queen,
queen = 0b0001,
/// Worker caste.
worker,
worker = 0b0010,
/// Soldier caste.
soldier,
soldier = 0b0100,
/// Male caste.
male
male = 0b1000
};
#endif // ANTKEEPER_GAME_ANT_CASTE_HPP
#endif // ANTKEEPER_GAME_ANT_CASTE_TYPE_HPP

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

@ -33,6 +33,6 @@
*
* @return New genome.
*/
std::unique_ptr<ant_genome> ant_cladogenesis(const ant_gene_pool& pool, std::random_device& rng);
[[nodiscard]] std::unique_ptr<ant_genome> ant_cladogenesis(const ant_gene_pool& pool, std::random_device& rng);
#endif // ANTKEEPER_GAME_ANT_CLADOGENESIS_HPP

+ 106
- 27
src/game/ant/ant-morphogenesis.cpp View File

@ -22,6 +22,7 @@
#include <engine/render/vertex-attribute.hpp>
#include <engine/math/transform-operators.hpp>
#include <engine/math/quaternion.hpp>
#include <engine/debug/log.hpp>
#include <unordered_set>
static void reskin_vertices
@ -79,13 +80,13 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
std::shared_ptr<render::material> exoskeleton_material = build_exoskeleton_material(*phenome.pigmentation, *phenome.sculpturing);
// Determine presence of optional parts
bool eyes_present = phenome.eyes->present;
bool lateral_ocelli_present = phenome.ocelli->lateral_ocelli_present;
bool median_ocellus_present = phenome.ocelli->median_ocellus_present;
bool petiole_present = phenome.waist->petiole_present;
bool postpetiole_present = phenome.waist->postpetiole_present;
bool sting_present = phenome.sting->present;
bool wings_present = phenome.wings->present;
const bool eyes_present = phenome.eyes->present;
const bool lateral_ocelli_present = phenome.ocelli->lateral_ocelli_present;
const bool median_ocellus_present = phenome.ocelli->median_ocellus_present;
const bool petiole_present = phenome.waist->petiole_present;
const bool postpetiole_present = phenome.waist->postpetiole_present;
const bool sting_present = phenome.sting->present;
const bool wings_present = phenome.wings->present;
// Get body part models
const render::model* antennae_model = phenome.antennae->model.get();
@ -102,6 +103,56 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
const render::model* sting_model = phenome.sting->model.get();
const render::model* waist_model = phenome.waist->model.get();
// Check for presence of required part models
if (!antennae_model)
{
throw std::runtime_error("Ant phenome missing antennae model");
}
if (eyes_present && !eyes_model)
{
throw std::runtime_error("Ant phenome missing eyes model");
}
if (wings_present && !forewings_model)
{
throw std::runtime_error("Ant phenome missing forewings model");
}
if (!gaster_model)
{
throw std::runtime_error("Ant phenome missing gaster model");
}
if (wings_present && !hindwings_model)
{
throw std::runtime_error("Ant phenome missing hindwings model");
}
if (lateral_ocelli_present && !lateral_ocelli_model)
{
throw std::runtime_error("Ant phenome missing lateral ocelli model");
}
if (!legs_model)
{
throw std::runtime_error("Ant phenome missing legs model");
}
if (!mandibles_model)
{
throw std::runtime_error("Ant phenome missing mandibles model");
}
if (median_ocellus_present && !median_ocellus_model)
{
throw std::runtime_error("Ant phenome missing median ocellus model");
}
if (!mesosoma_model)
{
throw std::runtime_error("Ant phenome missing mesosoma model");
}
if (sting_present && !sting_model)
{
throw std::runtime_error("Ant phenome missing sting model");
}
if (!waist_model)
{
throw std::runtime_error("Ant phenome missing waist model");
}
// Get body part vertex buffers
const gl::vertex_buffer* antennae_vbo = antennae_model->get_vertex_buffer().get();
const gl::vertex_buffer* eyes_vbo = (eyes_present) ? eyes_model->get_vertex_buffer().get() : nullptr;
@ -109,10 +160,10 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
const gl::vertex_buffer* gaster_vbo = gaster_model->get_vertex_buffer().get();
const gl::vertex_buffer* head_vbo = head_model->get_vertex_buffer().get();
const gl::vertex_buffer* hindwings_vbo = (wings_present) ? hindwings_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* lateral_ocelli_vbo = (lateral_ocelli_model) ? lateral_ocelli_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* lateral_ocelli_vbo = (lateral_ocelli_present) ? lateral_ocelli_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* legs_vbo = legs_model->get_vertex_buffer().get();
const gl::vertex_buffer* mandibles_vbo = mandibles_model->get_vertex_buffer().get();
const gl::vertex_buffer* median_ocellus_vbo = (median_ocellus_model) ? median_ocellus_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* median_ocellus_vbo = (median_ocellus_present) ? median_ocellus_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* mesosoma_vbo = mesosoma_model->get_vertex_buffer().get();
const gl::vertex_buffer* sting_vbo = (sting_present) ? sting_model->get_vertex_buffer().get() : nullptr;
const gl::vertex_buffer* waist_vbo = waist_model->get_vertex_buffer().get();
@ -135,22 +186,34 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
vertex_buffer_size += gaster_vbo->size();
std::size_t sting_vbo_offset = vertex_buffer_size;
if (sting_present)
{
vertex_buffer_size += sting_vbo->size();
}
std::size_t eyes_vbo_offset = vertex_buffer_size;
if (eyes_present)
{
vertex_buffer_size += eyes_vbo->size();
}
std::size_t lateral_ocelli_vbo_offset = vertex_buffer_size;
if (lateral_ocelli_present)
{
vertex_buffer_size += lateral_ocelli_vbo->size();
}
std::size_t median_ocellus_vbo_offset = vertex_buffer_size;
if (median_ocellus_present)
{
vertex_buffer_size += median_ocellus_vbo->size();
}
std::size_t forewings_vbo_offset = vertex_buffer_size;
if (wings_present)
{
vertex_buffer_size += forewings_vbo->size();
}
std::size_t hindwings_vbo_offset = vertex_buffer_size;
if (wings_present)
{
vertex_buffer_size += hindwings_vbo->size();
}
// Allocate combined vertex buffer data
std::vector<std::byte> vertex_buffer_data(vertex_buffer_size);
@ -681,29 +744,45 @@ std::unique_ptr ant_morphogenesis(const ant_phenome& phenome)
reskin_vertices(vertex_buffer_data.data() + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere1_r_indices, antennomere1_r_bone_index, antenna_r_to_body);
// Reskin antennomere2+ bones
const std::vector<hash::fnv1a32_t> antennomere_bone_names =
{
"antennomere2",
"antennomere3",
"antennomere4",
"antennomere5",
"antennomere6",
"antennomere7",
"antennomere8",
"antennomere9",
"antennomere10",
"antennomere11",
"antennomere12",
"antennomere13"
const std::vector<hash::fnv1a32_t> antennomere_l_bone_keys =
{
"antennomere2_l",
"antennomere3_l",
"antennomere4_l",
"antennomere5_l",
"antennomere6_l",
"antennomere7_l",
"antennomere8_l",
"antennomere9_l",
"antennomere10_l",
"antennomere11_l",
"antennomere12_l",
"antennomere13_l"
};
const std::vector<hash::fnv1a32_t> antennomere_r_bone_keys =
{
"antennomere2_r",
"antennomere3_r",
"antennomere4_r",
"antennomere5_r",
"antennomere6_r",
"antennomere7_r",
"antennomere8_r",
"antennomere9_r",
"antennomere10_r",
"antennomere11_r",
"antennomere12_r",
"antennomere13_r"
};
std::unordered_set<std::uint8_t> old_antennomere_l_indices;
for (const auto& bone_name: antennomere_bone_names)
if (auto it = antennae_skeleton.bone_map.find(bone_name + "_l"); it != antennae_skeleton.bone_map.end())
for (const auto& bone_key: antennomere_l_bone_keys)
if (auto it = antennae_skeleton.bone_map.find(bone_key); it != antennae_skeleton.bone_map.end())
old_antennomere_l_indices.emplace(it->second);
reskin_vertices(vertex_buffer_data.data() + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere_l_indices, antennomere2_l_bone_index, antenna_l_to_body);
std::unordered_set<std::uint8_t> old_antennomere_r_indices;
for (const auto& bone_name: antennomere_bone_names)
if (auto it = antennae_skeleton.bone_map.find(bone_name + "_r"); it != antennae_skeleton.bone_map.end())
for (const auto& bone_key: antennomere_r_bone_keys)
if (auto it = antennae_skeleton.bone_map.find(bone_key); it != antennae_skeleton.bone_map.end())
old_antennomere_r_indices.emplace(it->second);
reskin_vertices(vertex_buffer_data.data() + antennae_vbo_offset, antennae_index_count, *position_attribute, *normal_attribute, *tangent_attribute, *bone_index_attribute, old_antennomere_r_indices, antennomere2_r_bone_index, antenna_r_to_body);

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

@ -31,6 +31,6 @@
*
* @return 3D model of the given phenome.
*/
std::unique_ptr<render::model> ant_morphogenesis(const ant_phenome& phenome);
[[nodiscard]] std::unique_ptr<render::model> ant_morphogenesis(const ant_phenome& phenome);
#endif // ANTKEEPER_GAME_ANT_MORPHOGENESIS_HPP

+ 45
- 38
src/game/ant/ant-phenome.cpp View File

@ -19,65 +19,72 @@
#include "game/ant/ant-phenome.hpp"
ant_phenome::ant_phenome(const ant_genome& genome, ant_caste caste)
ant_phenome::ant_phenome(const ant_genome& genome, ant_caste_type caste)
{
if (genome.antennae)
if (auto it = genome.antennae->phenes.find(caste); it != genome.antennae->phenes.end())
antennae = &it->second;
if (auto i = genome.antennae->phene_map.find(caste); i != genome.antennae->phene_map.end())
antennae = i->second;
if (genome.body_size)
if (auto it = genome.body_size->phenes.find(caste); it != genome.body_size->phenes.end())
body_size = &it->second;
if (auto i = genome.body_size->phene_map.find(caste); i != genome.body_size->phene_map.end())
body_size = i->second;
if (genome.cocoon)
cocoon = &genome.cocoon->phene;
if (auto i = genome.cocoon->phene_map.find(caste); i != genome.cocoon->phene_map.end())
cocoon = i->second;
if (genome.diet)
diet = &genome.diet->phene;
if (auto i = genome.diet->phene_map.find(caste); i != genome.diet->phene_map.end())
diet = i->second;
if (genome.egg)
egg = &genome.egg->phene;
if (auto i = genome.egg->phene_map.find(caste); i != genome.egg->phene_map.end())
egg = i->second;
if (genome.eyes)
if (auto it = genome.eyes->phenes.find(caste); it != genome.eyes->phenes.end())
eyes = &it->second;
if (auto i = genome.eyes->phene_map.find(caste); i != genome.eyes->phene_map.end())
eyes = i->second;
if (genome.foraging_time)
foraging_time = &genome.foraging_time->phene;
if (auto i = genome.foraging_time->phene_map.find(caste); i != genome.foraging_time->phene_map.end())
foraging_time = i->second;
if (genome.founding_mode)
founding_mode = &genome.founding_mode->phene;
if (auto i = genome.founding_mode->phene_map.find(caste); i != genome.founding_mode->phene_map.end())
founding_mode = i->second;
if (genome.gaster)
if (auto it = genome.gaster->phenes.find(caste); it != genome.gaster->phenes.end())
gaster = &it->second;
if (auto i = genome.gaster->phene_map.find(caste); i != genome.gaster->phene_map.end())
gaster = i->second;
if (genome.head)
if (auto it = genome.head->phenes.find(caste); it != genome.head->phenes.end())
head = &it->second;
if (auto i = genome.head->phene_map.find(caste); i != genome.head->phene_map.end())
head = i->second;
if (genome.larva)
larva = &genome.larva->phene;
if (auto i = genome.larva->phene_map.find(caste); i != genome.larva->phene_map.end())
larva = i->second;
if (genome.legs)
if (auto it = genome.legs->phenes.find(caste); it != genome.legs->phenes.end())
legs = &it->second;
if (auto i = genome.legs->phene_map.find(caste); i != genome.legs->phene_map.end())
legs = i->second;
if (genome.mandibles)
if (auto it = genome.mandibles->phenes.find(caste); it != genome.mandibles->phenes.end())
mandibles = &it->second;
if (auto i = genome.mandibles->phene_map.find(caste); i != genome.mandibles->phene_map.end())
mandibles = i->second;
if (genome.mesosoma)
if (auto it = genome.mesosoma->phenes.find(caste); it != genome.mesosoma->phenes.end())
mesosoma = &it->second;
if (auto i = genome.mesosoma->phene_map.find(caste); i != genome.mesosoma->phene_map.end())
mesosoma = i->second;
if (genome.nest_site)
nest_site = &genome.nest_site->phene;
if (auto i = genome.nest_site->phene_map.find(caste); i != genome.nest_site->phene_map.end())
nest_site = i->second;
if (genome.ocelli)
if (auto it = genome.ocelli->phenes.find(caste); it != genome.ocelli->phenes.end())
ocelli = &it->second;
if (auto i = genome.ocelli->phene_map.find(caste); i != genome.ocelli->phene_map.end())
ocelli = i->second;
if (genome.pigmentation)
if (auto it = genome.pigmentation->phenes.find(caste); it != genome.pigmentation->phenes.end())
pigmentation = &it->second;
if (auto i = genome.pigmentation->phene_map.find(caste); i != genome.pigmentation->phene_map.end())
pigmentation = i->second;
if (genome.pilosity)
if (auto it = genome.pilosity->phenes.find(caste); it != genome.pilosity->phenes.end())
pilosity = &it->second;
if (auto i = genome.pilosity->phene_map.find(caste); i != genome.pilosity->phene_map.end())
pilosity = i->second;
if (genome.sculpturing)
if (auto it = genome.sculpturing->phenes.find(caste); it != genome.sculpturing->phenes.end())
sculpturing = &it->second;
if (auto i = genome.sculpturing->phene_map.find(caste); i != genome.sculpturing->phene_map.end())
sculpturing = i->second;
if (genome.sting)
if (auto it = genome.sting->phenes.find(caste); it != genome.sting->phenes.end())
sting = &it->second;
if (auto i = genome.sting->phene_map.find(caste); i != genome.sting->phene_map.end())
sting = i->second;
if (genome.waist)
if (auto it = genome.waist->phenes.find(caste); it != genome.waist->phenes.end())
waist = &it->second;
if (auto i = genome.waist->phene_map.find(caste); i != genome.waist->phene_map.end())
waist = i->second;
if (genome.wings)
if (auto it = genome.wings->phenes.find(caste); it != genome.wings->phenes.end())
wings = &it->second;
if (auto i = genome.wings->phene_map.find(caste); i != genome.wings->phene_map.end())
wings = i->second;
}

+ 2
- 2
src/game/ant/ant-phenome.hpp View File

@ -43,7 +43,7 @@
#include "game/ant/genes/ant-waist-gene.hpp"
#include "game/ant/genes/ant-wings-gene.hpp"
#include "game/ant/ant-genome.hpp"
#include "game/ant/ant-caste.hpp"
#include "game/ant/ant-caste-type.hpp"
/**
* Complete set of ant phenes.
@ -56,7 +56,7 @@ struct ant_phenome
* @param genome Ant genome.
* @param caste Ant caste.
*/
ant_phenome(const ant_genome& genome, ant_caste caste);
ant_phenome(const ant_genome& genome, ant_caste_type caste);
/// Constructs an empty ant phenome.
ant_phenome() = default;

+ 2
- 2
src/game/ant/ant-species.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_SPECIES_HPP
#define ANTKEEPER_GAME_ANT_SPECIES_HPP
#include "game/ant/ant-caste.hpp"
#include "game/ant/ant-caste-type.hpp"
#include "game/ant/ant-phenome.hpp"
#include <engine/render/model.hpp>
#include <unordered_map>
@ -29,7 +29,7 @@
struct ant_species
{
/// Caste-specific phenomes
std::unordered_map<ant_caste, ant_phenome> phenomes;
std::unordered_map<ant_caste_type, ant_phenome> phenomes;
/// Caste-specific models
std::unordered_map<caste, std::shared_ptr<render::model>> models;

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

@ -28,7 +28,7 @@
enum class ant_subcaste: std::uint8_t
{
/// Worker from the queen's first batch of eggs, smaller than normal workers.
nanitic,
nanitic = 1,
/// Small worker or soldier.
minor,

+ 2
- 2
src/game/ant/ant-swarm.cpp View File

@ -114,11 +114,11 @@ entity::id create_ant_swarm(::game& ctx)
// Init queen caste component
ant_caste_component queen_caste;
queen_caste.type = ant_caste::queen;
queen_caste.caste_type = ant_caste_type::queen;
// Init male caste component
ant_caste_component male_caste;
male_caste.type = ant_caste::male;
male_caste.caste_type = ant_caste_type::male;
// Construct and seed random number generator
std::random_device seed;

+ 16
- 30
src/game/ant/genes/ant-antennae-gene.cpp View File

@ -17,49 +17,35 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-antennae-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include "game/ant/genes/ant-antennae-gene.hpp"
#include <engine/render/model.hpp>
#include <engine/utility/json.hpp>
#include <stdexcept>
static void deserialize_ant_antennae_phene(ant_antennae_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_antennae_phene(ant_antennae_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.total_antennomere_count = 0;
phene.club_antennomere_count = 0;
// Load antennae model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
ctx.read8(reinterpret_cast<std::byte*>(&phene.total_antennomere_count), 1);
ctx.read8(reinterpret_cast<std::byte*>(&phene.club_antennomere_count), 1);
// Parse total antennomere count
if (auto element = phene_element.find("total_antennomere_count"); element != phene_element.end())
phene.total_antennomere_count = element->get<std::uint8_t>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse club antennomere count
if (auto element = phene_element.find("club_antennomere_count"); element != phene_element.end())
phene.club_antennomere_count = element->get<std::uint8_t>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_antennae_gene> resource_loader<ant_antennae_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto antennae_element = json_data->find("antennae");
if (antennae_element == json_data->end())
throw std::runtime_error("Invalid antennae gene.");
// Allocate gene
std::unique_ptr<ant_antennae_gene> antennae = std::make_unique<ant_antennae_gene>();
std::unique_ptr<ant_antennae_gene> gene = std::make_unique<ant_antennae_gene>();
// Deserialize gene
deserialize_ant_gene(*antennae, &deserialize_ant_antennae_phene, *antennae_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_antennae_phene);
return antennae;
return gene;
}

+ 13
- 7
src/game/ant/genes/ant-antennae-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_ANTENNAE_GENE_HPP
#define ANTKEEPER_GAME_ANT_ANTENNAE_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
#include <cstdint>
@ -33,17 +33,23 @@
*/
struct ant_antennae_phene
{
/// 3D model of the antennae.
std::shared_ptr<render::model> model;
/// Total number of antennal segments per antenna.
std::uint8_t total_antennomere_count;
std::uint8_t total_antennomere_count{0};
/// Number of antennal segments that constitute a club.
std::uint8_t club_antennomere_count;
std::uint8_t club_antennomere_count{0};
/// 3D model of the antennae.
std::shared_ptr<render::model> model;
};
/// Ant antennae gene.
using ant_antennae_gene = polyphenic_ant_gene<ant_antennae_phene>;
using ant_antennae_gene = ant_gene<ant_antennae_phene>;
template <>
inline constexpr ant_gene_type ant_antennae_gene::type() const noexcept
{
return ant_gene_type::antennae;
}
#endif // ANTKEEPER_GAME_ANT_ANTENNAE_GENE_HPP

+ 12
- 32
src/game/ant/genes/ant-body-size-gene.cpp View File

@ -17,48 +17,28 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-body-size-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-body-size-gene.hpp"
#include <stdexcept>
static void deserialize_ant_body_size_phene(ant_body_size_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_body_size_phene(ant_body_size_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.min_mesosoma_length = 1.0f;
phene.max_mesosoma_length = 1.0f;
phene.mean_mesosoma_length = 1.0f;
// Parse min mesosoma length
if (auto element = phene_element.find("min_mesosoma_length"); element != phene_element.end())
phene.min_mesosoma_length = element->get<float>();
// Parse max mesosoma length
if (auto element = phene_element.find("max_mesosoma_length"); element != phene_element.end())
phene.max_mesosoma_length = element->get<float>();
// Parse mean mesosoma length
if (auto element = phene_element.find("mean_mesosoma_length"); element != phene_element.end())
phene.mean_mesosoma_length = element->get<float>();
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.min_mesosoma_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.max_mesosoma_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.mean_mesosoma_length), 1);
}
} // namespace
template <>
std::unique_ptr<ant_body_size_gene> resource_loader<ant_body_size_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto body_size_element = json_data->find("body_size");
if (body_size_element == json_data->end())
throw std::runtime_error("Invalid body_size gene.");
// Allocate gene
std::unique_ptr<ant_body_size_gene> body_size = std::make_unique<ant_body_size_gene>();
std::unique_ptr<ant_body_size_gene> gene = std::make_unique<ant_body_size_gene>();
// Deserialize gene
deserialize_ant_gene(*body_size, &deserialize_ant_body_size_phene, *body_size_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_body_size_phene);
return body_size;
return gene;
}

+ 11
- 5
src/game/ant/genes/ant-body-size-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_BODY_SIZE_GENE_HPP
#define ANTKEEPER_GAME_ANT_BODY_SIZE_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
/**
* Ant body size phene.
@ -30,16 +30,22 @@
struct ant_body_size_phene
{
/// Minimum mesosoma length (Weber's length), in centimeters.
float min_mesosoma_length;
float min_mesosoma_length{0.0f};
/// Maximum mesosoma length (Weber's length), in centimeters.
float max_mesosoma_length;
float max_mesosoma_length{0.0f};
/// Mean mesosoma length (Weber's length), in centimeters.
float mean_mesosoma_length;
float mean_mesosoma_length{0.0f};
};
/// Ant body size gene.
using ant_body_size_gene = polyphenic_ant_gene<ant_body_size_phene>;
using ant_body_size_gene = ant_gene<ant_body_size_phene>;
template <>
inline constexpr ant_gene_type ant_body_size_gene::type() const noexcept
{
return ant_gene_type::body_size;
}
#endif // ANTKEEPER_GAME_ANT_BODY_SIZE_GENE_HPP

+ 17
- 25
src/game/ant/genes/ant-cocoon-gene.cpp View File

@ -17,47 +17,39 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-cocoon-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-cocoon-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_cocoon_phene(ant_cocoon_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_cocoon_phene(ant_cocoon_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.present = false;
phene.model = nullptr;
std::uint8_t present{0};
ctx.read8(reinterpret_cast<std::byte*>(&present), 1);
phene.present = static_cast<bool>(present);
// Parse cocoon present
if (auto element = phene_element.find("present"); element != phene_element.end())
phene.present = element->get<bool>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Load cocoon model
if (phene.present)
{
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
phene.model = resource_manager.load<render::model>(model_filename);
}
}
} // namespace
template <>
std::unique_ptr<ant_cocoon_gene> resource_loader<ant_cocoon_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto cocoon_element = json_data->find("cocoon");
if (cocoon_element == json_data->end())
throw std::runtime_error("Invalid cocoon gene.");
// Allocate gene
std::unique_ptr<ant_cocoon_gene> cocoon = std::make_unique<ant_cocoon_gene>();
std::unique_ptr<ant_cocoon_gene> gene = std::make_unique<ant_cocoon_gene>();
// Deserialize gene
deserialize_ant_gene(*cocoon, &deserialize_ant_cocoon_phene, *cocoon_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_cocoon_phene);
return cocoon;
return gene;
}

+ 11
- 5
src/game/ant/genes/ant-cocoon-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_COCOON_GENE_HPP
#define ANTKEEPER_GAME_ANT_COCOON_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -29,14 +29,20 @@
*/
struct ant_cocoon_phene
{
/// Indicates whether a cocoon is formed by the larvae or not.
bool present{false};
/// 3D model of the cocoon, if present.
std::shared_ptr<render::model> model;
/// Indicates whether a cocoon is formed by the larvae or not.
bool present;
};
/// Ant cocoon gene.
using ant_cocoon_gene = monophenic_ant_gene<ant_cocoon_phene>;
using ant_cocoon_gene = ant_gene<ant_cocoon_phene>;
template <>
inline constexpr ant_gene_type ant_cocoon_gene::type() const noexcept
{
return ant_gene_type::cocoon;
}
#endif // ANTKEEPER_GAME_ANT_COCOON_GENE_HPP

+ 10
- 18
src/game/ant/genes/ant-diet-gene.cpp View File

@ -17,34 +17,26 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-diet-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-diet-gene.hpp"
#include <stdexcept>
static void deserialize_ant_diet_phene(ant_diet_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_diet_phene(ant_diet_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
}
} // namespace
template <>
std::unique_ptr<ant_diet_gene> resource_loader<ant_diet_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto diet_element = json_data->find("diet");
if (diet_element == json_data->end())
throw std::runtime_error("Invalid diet gene.");
// Allocate gene
std::unique_ptr<ant_diet_gene> diet = std::make_unique<ant_diet_gene>();
std::unique_ptr<ant_diet_gene> gene = std::make_unique<ant_diet_gene>();
// Deserialize gene
deserialize_ant_gene(*diet, &deserialize_ant_diet_phene, *diet_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_diet_phene);
return diet;
return gene;
}

+ 14
- 8
src/game/ant/genes/ant-diet-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_DIET_GENE_HPP
#define ANTKEEPER_GAME_ANT_DIET_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
/**
* Ant diet phene.
@ -28,25 +28,31 @@
struct ant_diet_phene
{
/// Preference for eating seeds.
float seeds;
float seeds{0.0f};
/// Preference for eating ant brood.
float ant_brood;
float ant_brood{0.0f};
/// Preference for eating arthropod eggs.
float arthropod_eggs;
float arthropod_eggs{0.0f};
/// Preference for eating nectar.
float nectar;
float nectar{0.0f};
/// Preference for eating fungi.
float fungi;
float fungi{0.0f};
/// Preference for eating carrion.
float carrion;
float carrion{0.0f};
};
/// Ant diet gene.
using ant_diet_gene = monophenic_ant_gene<ant_diet_phene>;
using ant_diet_gene = ant_gene<ant_diet_phene>;
template <>
inline constexpr ant_gene_type ant_diet_gene::type() const noexcept
{
return ant_gene_type::diet;
}
#endif // ANTKEEPER_GAME_ANT_DIET_GENE_HPP

+ 14
- 21
src/game/ant/genes/ant-egg-gene.cpp View File

@ -17,39 +17,32 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-egg-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-egg-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_egg_phene(ant_egg_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_egg_phene(ant_egg_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Load egg model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_egg_gene> resource_loader<ant_egg_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto egg_element = json_data->find("egg");
if (egg_element == json_data->end())
throw std::runtime_error("Invalid egg gene.");
// Allocate gene
std::unique_ptr<ant_egg_gene> egg = std::make_unique<ant_egg_gene>();
std::unique_ptr<ant_egg_gene> gene = std::make_unique<ant_egg_gene>();
// Deserialize gene
deserialize_ant_gene(*egg, &deserialize_ant_egg_phene, *egg_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_egg_phene);
return egg;
return gene;
}

+ 8
- 2
src/game/ant/genes/ant-egg-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_EGG_GENE_HPP
#define ANTKEEPER_GAME_ANT_EGG_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -34,6 +34,12 @@ struct ant_egg_phene
};
/// Ant egg gene.
using ant_egg_gene = monophenic_ant_gene<ant_egg_phene>;
using ant_egg_gene = ant_gene<ant_egg_phene>;
template <>
inline constexpr ant_gene_type ant_egg_gene::type() const noexcept
{
return ant_gene_type::egg;
}
#endif // ANTKEEPER_GAME_ANT_EGG_GENE_HPP

+ 22
- 45
src/game/ant/genes/ant-eyes-gene.cpp View File

@ -17,67 +17,44 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-eyes-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-eyes-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_eyes_phene(ant_eyes_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_eyes_phene(ant_eyes_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.present = false;
phene.model = nullptr;
phene.length = 0.0f;
phene.width = 0.0f;
phene.height = 0.0f;
phene.ommatidia_count = 0;
std::uint8_t present{0};
ctx.read8(reinterpret_cast<std::byte*>(&present), 1);
phene.present = static_cast<bool>(present);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.ommatidia_count), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.height), 1);
// Parse present
if (auto element = phene_element.find("present"); element != phene_element.end())
phene.present = element->get<bool>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
if (phene.present)
{
// Load eyes model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
// Parse length
if (auto element = phene_element.find("length"); element != phene_element.end())
phene.length = element->get<float>();
// Parse width
if (auto element = phene_element.find("width"); element != phene_element.end())
phene.width = element->get<float>();
// Parse height
if (auto element = phene_element.find("height"); element != phene_element.end())
phene.height = element->get<float>();
// Parse ommatidia count
if (auto element = phene_element.find("ommatidia_count"); element != phene_element.end())
phene.ommatidia_count = element->get<int>();
phene.model = resource_manager.load<render::model>(model_filename);
}
}
} // namespace
template <>
std::unique_ptr<ant_eyes_gene> resource_loader<ant_eyes_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto eyes_element = json_data->find("eyes");
if (eyes_element == json_data->end())
throw std::runtime_error("Invalid eyes gene.");
// Allocate gene
std::unique_ptr<ant_eyes_gene> eyes = std::make_unique<ant_eyes_gene>();
std::unique_ptr<ant_eyes_gene> gene = std::make_unique<ant_eyes_gene>();
// Deserialize gene
deserialize_ant_gene(*eyes, &deserialize_ant_eyes_phene, *eyes_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_eyes_phene);
return eyes;
return gene;
}

+ 17
- 11
src/game/ant/genes/ant-eyes-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_EYES_GENE_HPP
#define ANTKEEPER_GAME_ANT_EYES_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <cstdint>
#include <memory>
@ -32,26 +32,32 @@
*/
struct ant_eyes_phene
{
/// 3D model of the eyes, if present.
std::shared_ptr<render::model> model;
/// Indicates whether eyes are present.
bool present;
bool present{false};
/// Number of ommatidia.
std::uint32_t ommatidia_count{0};
/// Eye length, in mesosomal lengths.
float length;
float length{0.0f};
/// Eye width, in mesosomal lengths.
float width;
float width{0.0f};
/// Eye height, in mesosomal lengths.
float height;
float height{0.0f};
/// Number of ommatidia.
std::uint32_t ommatidia_count;
/// 3D model of the eyes, if present.
std::shared_ptr<render::model> model;
};
/// Ant eyes gene.
using ant_eyes_gene = polyphenic_ant_gene<ant_eyes_phene>;
using ant_eyes_gene = ant_gene<ant_eyes_phene>;
template <>
inline constexpr ant_gene_type ant_eyes_gene::type() const noexcept
{
return ant_gene_type::eyes;
}
#endif // ANTKEEPER_GAME_ANT_EYES_GENE_HPP

+ 11
- 29
src/game/ant/genes/ant-foraging-time-gene.cpp View File

@ -17,45 +17,27 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-foraging-time-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-foraging-time-gene.hpp"
#include <engine/math/angles.hpp>
#include <engine/math/numbers.hpp>
#include <stdexcept>
static void deserialize_ant_foraging_time_phene(ant_foraging_time_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_foraging_time_phene(ant_foraging_time_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.min_solar_altitude = -math::half_pi<float>;
phene.max_solar_altitude = math::half_pi<float>;
// Parse min solar altitude
if (auto element = phene_element.find("min_solar_altitude"); element != phene_element.end())
phene.min_solar_altitude = math::radians(element->get<float>());
// Parse max solar altitude
if (auto element = phene_element.find("max_solar_altitude"); element != phene_element.end())
phene.max_solar_altitude = math::radians(element->get<float>());
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.min_solar_altitude), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.max_solar_altitude), 1);
}
} // namespace
template <>
std::unique_ptr<ant_foraging_time_gene> resource_loader<ant_foraging_time_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto foraging_time_element = json_data->find("foraging_time");
if (foraging_time_element == json_data->end())
throw std::runtime_error("Invalid foraging_time gene.");
// Allocate gene
std::unique_ptr<ant_foraging_time_gene> foraging_time = std::make_unique<ant_foraging_time_gene>();
std::unique_ptr<ant_foraging_time_gene> gene = std::make_unique<ant_foraging_time_gene>();
// Deserialize gene
deserialize_ant_gene(*foraging_time, &deserialize_ant_foraging_time_phene, *foraging_time_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_foraging_time_phene);
return foraging_time;
return gene;
}

+ 12
- 6
src/game/ant/genes/ant-foraging-time-gene.hpp View File

@ -20,21 +20,27 @@
#ifndef ANTKEEPER_GAME_ANT_FORAGING_TIME_GENE_HPP
#define ANTKEEPER_GAME_ANT_FORAGING_TIME_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
/**
* Ant foraging time phene.
*/
struct ant_foraging_time_phene
{
/// Minimum solar altitude at which foraging occurs.
float min_solar_altitude;
/// Minimum solar altitude, in radians, at which foraging occurs.
float min_solar_altitude{0.0f};
/// Maximum solar alttiude at which foraging occurs.
float max_solar_altitude;
/// Maximum solar alttiude, in radians, at which foraging occurs.
float max_solar_altitude{0.0f};
};
/// Ant foraging time gene.
using ant_foraging_time_gene = monophenic_ant_gene<ant_foraging_time_phene>;
using ant_foraging_time_gene = ant_gene<ant_foraging_time_phene>;
template <>
inline constexpr ant_gene_type ant_foraging_time_gene::type() const noexcept
{
return ant_gene_type::foraging_time;
}
#endif // ANTKEEPER_GAME_ANT_FORAGING_TIME_GENE_HPP

+ 9
- 17
src/game/ant/genes/ant-founding-mode-gene.cpp View File

@ -17,34 +17,26 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-founding-mode-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-founding-mode-gene.hpp"
#include <stdexcept>
static void deserialize_ant_founding_mode_phene(ant_founding_mode_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_founding_mode_phene(ant_founding_mode_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
}
} // namespace
template <>
std::unique_ptr<ant_founding_mode_gene> resource_loader<ant_founding_mode_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto founding_mode_element = json_data->find("founding_mode");
if (founding_mode_element == json_data->end())
throw std::runtime_error("Invalid founding_mode gene.");
// Allocate gene
std::unique_ptr<ant_founding_mode_gene> founding_mode = std::make_unique<ant_founding_mode_gene>();
std::unique_ptr<ant_founding_mode_gene> gene = std::make_unique<ant_founding_mode_gene>();
// Deserialize gene
deserialize_ant_gene(*founding_mode, &deserialize_ant_founding_mode_phene, *founding_mode_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_founding_mode_phene);
return founding_mode;
return gene;
}

+ 9
- 3
src/game/ant/genes/ant-founding-mode-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_FOUNDING_MODE_GENE_HPP
#define ANTKEEPER_GAME_ANT_FOUNDING_MODE_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <cstdint>
/**
@ -40,7 +40,13 @@ enum class ant_founding_mode_phene: std::uint8_t
fission
};
/// Monophenic founding mode gene.
using ant_founding_mode_gene = monophenic_ant_gene<ant_founding_mode_phene>;
/// Ant founding mode gene.
using ant_founding_mode_gene = ant_gene<ant_founding_mode_phene>;
template <>
inline constexpr ant_gene_type ant_founding_mode_gene::type() const noexcept
{
return ant_gene_type::founding_mode;
}
#endif // ANTKEEPER_GAME_ANT_FOUNDING_MODE_GENE_HPP

+ 15
- 25
src/game/ant/genes/ant-gaster-gene.cpp View File

@ -17,44 +17,34 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-gaster-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-gaster-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_gaster_phene(ant_gaster_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_gaster_phene(ant_gaster_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.phragmosis = 0.0f;
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.phragmosis), 1);
// Load gaster model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse phragmosis
if (auto element = phene_element.find("phragmosis"); element != phene_element.end())
phene.phragmosis = element->get<float>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_gaster_gene> resource_loader<ant_gaster_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto gaster_element = json_data->find("gaster");
if (gaster_element == json_data->end())
throw std::runtime_error("Invalid gaster gene.");
// Allocate gene
std::unique_ptr<ant_gaster_gene> gaster = std::make_unique<ant_gaster_gene>();
std::unique_ptr<ant_gaster_gene> gene = std::make_unique<ant_gaster_gene>();
// Deserialize gene
deserialize_ant_gene(*gaster, &deserialize_ant_gaster_phene, *gaster_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_gaster_phene);
return gaster;
return gene;
}

+ 11
- 5
src/game/ant/genes/ant-gaster-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_GASTER_GENE_HPP
#define ANTKEEPER_GAME_ANT_GASTER_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -31,14 +31,20 @@
*/
struct ant_gaster_phene
{
/// Degree of phragmosis.
float phragmosis{0.0f};
/// 3D model of the gaster.
std::shared_ptr<render::model> model;
/// Degree of phragmosis.
float phragmosis;
};
/// Ant gaster gene.
using ant_gaster_gene = polyphenic_ant_gene<ant_gaster_phene>;
using ant_gaster_gene = ant_gene<ant_gaster_phene>;
template <>
inline constexpr ant_gene_type ant_gaster_gene::type() const noexcept
{
return ant_gene_type::gaster;
}
#endif // ANTKEEPER_GAME_ANT_GASTER_GENE_HPP

+ 67
- 45
src/game/ant/genes/ant-gene-loader.hpp View File

@ -20,74 +20,96 @@
#ifndef ANTKEEPER_GAME_ANT_GENE_LOADER_HPP
#define ANTKEEPER_GAME_ANT_GENE_LOADER_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-gene.hpp"
#include <engine/resources/resource-manager.hpp>
#include <engine/resources/deserialize-context.hpp>
#include <engine/resources/deserialize-error.hpp>
/**
* Deserializes an ant gene.
* Loads an ant gene.
*
* @tparam T Ant phene type.
* @tparam T Phene type.
*
* @param gene Ant gene to deserialize.
* @param deserialize_phene Ant phene deserialization function.
* @param gene_element JSON element containing an ant gene definition.
* @param gene Gene to load.
* @param resource_manager Resource manager.
* @param ctx Deserialize context.
* @param load_phene Pointer to phene load function.
*/
/// @{
template <class T>
void deserialize_ant_gene(monophenic_ant_gene<T>& gene, void (*deserialize_phene)(T&, const json&, resource_manager&), const json& gene_element, resource_manager& resource_manager)
void load_ant_gene(ant_gene<T>& gene, resource_manager& resource_manager, deserialize_context& ctx, void (*load_phene)(T&, ::resource_manager&, deserialize_context&))
{
// Read gene name
if (auto element = gene_element.find("name"); element != gene_element.end())
// Read file format identifier
std::uint32_t format_identifier{0};
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&format_identifier), 1);
// Validate file format identifier
if (format_identifier != 0xaca79ff0)
{
gene.name = element->get<std::string>();
throw deserialize_error("Invalid ant gene file");
}
// Deserialize phene
if (auto element = gene_element.find("phene"); element != gene_element.end())
// Read file format version
std::uint16_t format_version{0};
ctx.read16<std::endian::little>(reinterpret_cast<std::byte*>(&format_version), 1);
// Validate file format version
if (format_version != 1)
{
deserialize_phene(gene.phene, *element, resource_manager);
throw deserialize_error("Unsupported ant gene format");
}
}
template <class T>
void deserialize_ant_gene(polyphenic_ant_gene<T>& gene, void (*deserialize_phene)(T&, const json&, resource_manager&), const json& gene_element, resource_manager& resource_manager)
{
// Read gene name
if (auto element = gene_element.find("name"); element != gene_element.end())
// Read gene type
ant_gene_type gene_type{0};
ctx.read8(reinterpret_cast<std::byte*>(&gene_type), 1);
// Validate gene type
if (gene_type != gene.type())
{
gene.name = element->get<std::string>();
throw deserialize_error("Mismatched ant gene type");
}
// Deserialize phenes
if (auto phenes_element = gene_element.find("phenes"); phenes_element != gene_element.end())
// Read gene name
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&gene.name), 1);
// Read phene count
std::uint8_t phene_count{0};
ctx.read8(reinterpret_cast<std::byte*>(&phene_count), 1);
// Allocate phenes
gene.phenes.resize(phene_count);
// Load phenes
for (auto& phene: gene.phenes)
{
if (auto element = phenes_element->find("female"); element != phenes_element->end())
{
deserialize_phene(gene.phenes[ant_caste::queen], *element, resource_manager);
deserialize_phene(gene.phenes[ant_caste::worker], *element, resource_manager);
deserialize_phene(gene.phenes[ant_caste::soldier], *element, resource_manager);
}
if (auto element = phenes_element->find("male"); element != phenes_element->end())
{
deserialize_phene(gene.phenes[ant_caste::male], *element, resource_manager);
}
if (auto element = phenes_element->find("queen"); element != phenes_element->end())
{
deserialize_phene(gene.phenes[ant_caste::queen], *element, resource_manager);
}
if (auto element = phenes_element->find("worker"); element != phenes_element->end())
// Read phene caste flags
std::uint8_t caste_flags{0};
ctx.read8(reinterpret_cast<std::byte*>(&caste_flags), 1);
// Load phene
load_phene(phene, resource_manager, ctx);
// Map flagged castes to phene
int caste_count = std::popcount(caste_flags);
if (caste_count == 1)
{
deserialize_phene(gene.phenes[ant_caste::worker], *element, resource_manager);
gene.phene_map[static_cast<ant_caste_type>(caste_flags)] = &phene;
}
if (auto element = phenes_element->find("soldier"); element != phenes_element->end())
else
{
deserialize_phene(gene.phenes[ant_caste::soldier], *element, resource_manager);
for (std::uint8_t i = 0; i < 8; ++i)
{
const std::uint8_t caste_mask = 1 << i;
if (caste_flags & caste_mask)
{
gene.phene_map[static_cast<ant_caste_type>(caste_mask)] = &phene;
if (--caste_count; !caste_count)
{
break;
}
}
}
}
}
}
/// @}
#endif // ANTKEEPER_GAME_ANT_GENE_LOADER_HPP

src/game/ant/genes/monophenic-ant-gene.hpp → src/game/ant/genes/ant-gene-type.hpp View File

@ -17,24 +17,38 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GAME_MONOPHENIC_ANT_GENE_HPP
#define ANTKEEPER_GAME_MONOPHENIC_ANT_GENE_HPP
#ifndef ANTKEEPER_GAME_ANT_GENE_TYPE_HPP
#define ANTKEEPER_GAME_ANT_GENE_TYPE_HPP
#include <string>
#include <cstdint>
/**
* Ant gene with a single phene.
*
* @tparam T Ant phene type.
* Ant gene types.
*/
template <class T>
struct monophenic_ant_gene
enum class ant_gene_type: std::uint8_t
{
/// Gene name.
std::string name;
/// Phene definition.
T phene;
antennae = 1,
body_size,
cocoon,
diet,
egg,
eyes,
foraging_time,
founding_mode,
gaster,
head,
larva,
legs,
mandibles,
mesosoma,
nest_site,
ocelli,
pigmentation,
pilosity,
sculpturing,
sting,
waist,
wings
};
#endif // ANTKEEPER_GAME_MONOPHENIC_ANT_GENE_HPP
#endif // ANTKEEPER_GAME_ANT_GENE_TYPE_HPP

src/game/ant/genes/polyphenic-ant-gene.hpp → src/game/ant/genes/ant-gene.hpp View File

@ -17,12 +17,26 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ANTKEEPER_GAME_POLYPHENIC_ANT_GENE_HPP
#define ANTKEEPER_GAME_POLYPHENIC_ANT_GENE_HPP
#ifndef ANTKEEPER_GAME_ANT_GENE_HPP
#define ANTKEEPER_GAME_ANT_GENE_HPP
#include "game/ant/ant-caste.hpp"
#include <string>
#include "game/ant/ant-caste-type.hpp"
#include "game/ant/genes/ant-gene-type.hpp"
#include <vector>
#include <unordered_map>
#include <engine/utility/hash/fnv1a.hpp>
/**
* Abstract base class for ant genes.
*/
struct ant_gene_base
{
/// Returns the ant gene type.
[[nodiscard]] virtual constexpr ant_gene_type type() const noexcept = 0;
/// 32-bit FNV-1a hash of gene name.
hash::fnv1a32_t name;
};
/**
* Ant gene with caste-specific phenes.
@ -32,13 +46,15 @@
* @see https://en.wikipedia.org/wiki/Polyphenism
*/
template <class T>
struct polyphenic_ant_gene
struct ant_gene: public ant_gene_base
{
/// Gene name.
std::string name;
[[nodiscard]] constexpr ant_gene_type type() const noexcept override;
/// Phene definitions
std::vector<T> phenes;
/// Caste-specific phene definitions.
std::unordered_map<ant_caste, T> phenes;
/// Map of ant caste types to phenes.
std::unordered_map<ant_caste_type, T*> phene_map;
};
#endif // ANTKEEPER_GAME_POLYPHENIC_ANT_GENE_HPP
#endif // ANTKEEPER_GAME_ANT_GENE_HPP

+ 17
- 35
src/game/ant/genes/ant-head-gene.cpp View File

@ -17,54 +17,36 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-head-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-head-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_head_phene(ant_head_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_head_phene(ant_head_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.length = 0.0f;
phene.width = 0.0f;
phene.phragmosis = 0.0f;
// Load head model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.phragmosis), 1);
// Parse length
if (auto element = phene_element.find("length"); element != phene_element.end())
phene.length = element->get<float>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse width
if (auto element = phene_element.find("width"); element != phene_element.end())
phene.width = element->get<float>();
// Parse phragmosis
if (auto element = phene_element.find("phragmosis"); element != phene_element.end())
phene.phragmosis = element->get<float>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_head_gene> resource_loader<ant_head_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto head_element = json_data->find("head");
if (head_element == json_data->end())
throw std::runtime_error("Invalid head gene.");
// Allocate gene
std::unique_ptr<ant_head_gene> head = std::make_unique<ant_head_gene>();
std::unique_ptr<ant_head_gene> gene = std::make_unique<ant_head_gene>();
// Deserialize gene
deserialize_ant_gene(*head, &deserialize_ant_head_phene, *head_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_head_phene);
return head;
return gene;
}

+ 15
- 9
src/game/ant/genes/ant-head-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_HEAD_GENE_HPP
#define ANTKEEPER_GAME_ANT_HEAD_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -32,20 +32,26 @@
*/
struct ant_head_phene
{
/// 3D model of the head.
std::shared_ptr<render::model> model;
/// Head length, in mesosomal lengths.
float length;
float length{0.0f};
/// Head width, in mesosomal lengths.
float width;
float width{0.0f};
/// Degree of phragmosis.
float phragmosis;
float phragmosis{0.0f};
/// 3D model of the head.
std::shared_ptr<render::model> model;
};
/// Polyphenic head gene.
using ant_head_gene = polyphenic_ant_gene<ant_head_phene>;
/// Ant head gene.
using ant_head_gene = ant_gene<ant_head_phene>;
template <>
inline constexpr ant_gene_type ant_head_gene::type() const noexcept
{
return ant_gene_type::head;
}
#endif // ANTKEEPER_GAME_ANT_HEAD_GENE_HPP

+ 15
- 25
src/game/ant/genes/ant-larva-gene.cpp View File

@ -17,44 +17,34 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-larva-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-larva-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_larva_phene(ant_larva_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_larva_phene(ant_larva_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.instar_count = 0;
ctx.read8(reinterpret_cast<std::byte*>(&phene.instar_count), 1);
// Load larva model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse instar count
if (auto element = phene_element.find("instar_count"); element != phene_element.end())
phene.instar_count = element->get<int>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_larva_gene> resource_loader<ant_larva_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto larva_element = json_data->find("larva");
if (larva_element == json_data->end())
throw std::runtime_error("Invalid larva gene.");
// Allocate gene
std::unique_ptr<ant_larva_gene> larva = std::make_unique<ant_larva_gene>();
std::unique_ptr<ant_larva_gene> gene = std::make_unique<ant_larva_gene>();
// Deserialize gene
deserialize_ant_gene(*larva, &deserialize_ant_larva_phene, *larva_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_larva_phene);
return larva;
return gene;
}

+ 11
- 5
src/game/ant/genes/ant-larva-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_LARVA_GENE_HPP
#define ANTKEEPER_GAME_ANT_LARVA_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <cstdint>
#include <memory>
@ -30,14 +30,20 @@
*/
struct ant_larva_phene
{
/// Number of larval instars before pupation.
std::uint8_t instar_count{0};
/// 3D model of the larva.
std::shared_ptr<render::model> model;
/// Number of larval instars before pupation.
std::uint8_t instar_count;
};
/// Ant larva gene.
using ant_larva_gene = monophenic_ant_gene<ant_larva_phene>;
using ant_larva_gene = ant_gene<ant_larva_phene>;
template <>
inline constexpr ant_gene_type ant_larva_gene::type() const noexcept
{
return ant_gene_type::larva;
}
#endif // ANTKEEPER_GAME_ANT_LARVA_GENE_HPP

+ 16
- 30
src/game/ant/genes/ant-legs-gene.cpp View File

@ -17,49 +17,35 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-legs-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-legs-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_legs_phene(ant_legs_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_legs_phene(ant_legs_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.speed = 0.0f;
phene.grip = 0.0f;
// Load legs model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.speed), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.grip), 1);
// Parse speed
if (auto element = phene_element.find("speed"); element != phene_element.end())
phene.speed = element->get<float>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse grip
if (auto element = phene_element.find("grip"); element != phene_element.end())
phene.grip = element->get<float>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_legs_gene> resource_loader<ant_legs_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto legs_element = json_data->find("legs");
if (legs_element == json_data->end())
throw std::runtime_error("Invalid legs gene.");
// Allocate gene
std::unique_ptr<ant_legs_gene> legs = std::make_unique<ant_legs_gene>();
std::unique_ptr<ant_legs_gene> gene = std::make_unique<ant_legs_gene>();
// Deserialize gene
deserialize_ant_gene(*legs, &deserialize_ant_legs_phene, *legs_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_legs_phene);
return legs;
return gene;
}

+ 14
- 8
src/game/ant/genes/ant-legs-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_LEGS_GENE_HPP
#define ANTKEEPER_GAME_ANT_LEGS_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -31,17 +31,23 @@
*/
struct ant_legs_phene
{
/// 3D model of the legs.
std::shared_ptr<render::model> model;
/// Running speed, in mesosomal lengths per second.
float speed;
float speed{0.0f};
/// Grip factor.
float grip;
float grip{0.0f};
/// 3D model of the legs.
std::shared_ptr<render::model> model;
};
/// Polyphenic legs gene.
using ant_legs_gene = polyphenic_ant_gene<ant_legs_phene>;
/// Ant legs gene.
using ant_legs_gene = ant_gene<ant_legs_phene>;
template <>
inline constexpr ant_gene_type ant_legs_gene::type() const noexcept
{
return ant_gene_type::legs;
}
#endif // ANTKEEPER_GAME_ANT_LEGS_GENE_HPP

+ 17
- 35
src/game/ant/genes/ant-mandibles-gene.cpp View File

@ -17,54 +17,36 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-mandibles-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-mandibles-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_mandibles_phene(ant_mandibles_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_mandibles_phene(ant_mandibles_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.length = 0.0f;
phene.apical_dental_count = 0;
phene.basal_dental_count = 0;
// Load mandibles model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.length), 1);
ctx.read8(reinterpret_cast<std::byte*>(&phene.apical_dental_count), 1);
ctx.read8(reinterpret_cast<std::byte*>(&phene.basal_dental_count), 1);
// Parse length
if (auto element = phene_element.find("length"); element != phene_element.end())
phene.length = element->get<float>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse apical dental count count
if (auto element = phene_element.find("apical_dental_count"); element != phene_element.end())
phene.apical_dental_count = element->get<int>();
// Parse basal dental count count
if (auto element = phene_element.find("basal_dental_count"); element != phene_element.end())
phene.basal_dental_count = element->get<int>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_mandibles_gene> resource_loader<ant_mandibles_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto mandibles_element = json_data->find("mandibles");
if (mandibles_element == json_data->end())
throw std::runtime_error("Invalid mandibles gene.");
// Allocate gene
std::unique_ptr<ant_mandibles_gene> mandibles = std::make_unique<ant_mandibles_gene>();
std::unique_ptr<ant_mandibles_gene> gene = std::make_unique<ant_mandibles_gene>();
// Deserialize gene
deserialize_ant_gene(*mandibles, &deserialize_ant_mandibles_phene, *mandibles_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_mandibles_phene);
return mandibles;
return gene;
}

+ 15
- 8
src/game/ant/genes/ant-mandibles-gene.hpp View File

@ -20,9 +20,10 @@
#ifndef ANTKEEPER_GAME_ANT_MANDIBLES_GENE_HPP
#define ANTKEEPER_GAME_ANT_MANDIBLES_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
#include <cstdint>
/**
* Ant mandibles phene.
@ -33,20 +34,26 @@
*/
struct ant_mandibles_phene
{
/// 3D model of the mandibles.
std::shared_ptr<render::model> model;
/// Mandible length at closure, in mesosomal lengths.
float length;
float length{0.0f};
/// Number of teeth and denticles on the masticatory (apical) margin of the mandible.
int apical_dental_count;
std::uint8_t apical_dental_count{0};
/// Number of teeth and denticles on the basal margin of the mandible.
int basal_dental_count;
std::uint8_t basal_dental_count{0};
/// 3D model of the mandibles.
std::shared_ptr<render::model> model;
};
/// Ant mandibles gene.
using ant_mandibles_gene = polyphenic_ant_gene<ant_mandibles_phene>;
using ant_mandibles_gene = ant_gene<ant_mandibles_phene>;
template <>
inline constexpr ant_gene_type ant_mandibles_gene::type() const noexcept
{
return ant_gene_type::mandibles;
}
#endif // ANTKEEPER_GAME_ANT_MANDIBLES_GENE_HPP

+ 18
- 40
src/game/ant/genes/ant-mesosoma-gene.cpp View File

@ -17,59 +17,37 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-mesosoma-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-mesosoma-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_mesosoma_phene(ant_mesosoma_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_mesosoma_phene(ant_mesosoma_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.pronotum_width = 0.0f;
phene.pronotum_spinescence = 0.0f;
phene.mesonotum_spinescence = 0.0f;
phene.propodeum_spinescence = 0.0f;
// Load mesosoma model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
// Parse pronotum width
if (auto element = phene_element.find("pronotum_width"); element != phene_element.end())
phene.pronotum_width = element->get<float>();
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.pronotum_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.pronotum_spinescence), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.mesonotum_spinescence), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.propodeum_spinescence), 1);
// Parse pronotum spinescence
if (auto element = phene_element.find("pronotum_spinescence"); element != phene_element.end())
phene.pronotum_spinescence = element->get<float>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
// Parse mesonotum spinescence
if (auto element = phene_element.find("mesonotum_spinescence"); element != phene_element.end())
phene.mesonotum_spinescence = element->get<float>();
// Parse propodeum spinescence
if (auto element = phene_element.find("propodeum_spinescence"); element != phene_element.end())
phene.propodeum_spinescence = element->get<float>();
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_mesosoma_gene> resource_loader<ant_mesosoma_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto mesosoma_element = json_data->find("mesosoma");
if (mesosoma_element == json_data->end())
throw std::runtime_error("Invalid mesosoma gene.");
// Allocate gene
std::unique_ptr<ant_mesosoma_gene> mesosoma = std::make_unique<ant_mesosoma_gene>();
std::unique_ptr<ant_mesosoma_gene> gene = std::make_unique<ant_mesosoma_gene>();
// Deserialize gene
deserialize_ant_gene(*mesosoma, &deserialize_ant_mesosoma_phene, *mesosoma_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_mesosoma_phene);
return mesosoma;
return gene;
}

+ 15
- 9
src/game/ant/genes/ant-mesosoma-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_MESOSOMA_GENE_HPP
#define ANTKEEPER_GAME_ANT_MESOSOMA_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -31,23 +31,29 @@
*/
struct ant_mesosoma_phene
{
/// 3D model of the mesosoma.
std::shared_ptr<render::model> model;
/// Pronotum width, in mesosomal lengths.
float pronotum_width;
float pronotum_width{0.0f};
/// Degree of spinescence on the pronotum.
float pronotum_spinescence;
float pronotum_spinescence{0.0f};
/// Degree of spinescence on the mesonotum.
float mesonotum_spinescence;
float mesonotum_spinescence{0.0f};
/// Degree of spinescence on the propodeum.
float propodeum_spinescence;
float propodeum_spinescence{0.0f};
/// 3D model of the mesosoma.
std::shared_ptr<render::model> model;
};
/// Ant mesosoma gene.
using ant_mesosoma_gene = polyphenic_ant_gene<ant_mesosoma_phene>;
using ant_mesosoma_gene = ant_gene<ant_mesosoma_phene>;
template <>
inline constexpr ant_gene_type ant_mesosoma_gene::type() const noexcept
{
return ant_gene_type::mesosoma;
}
#endif // ANTKEEPER_GAME_ANT_MESOSOMA_GENE_HPP

+ 10
- 18
src/game/ant/genes/ant-nest-site-gene.cpp View File

@ -17,34 +17,26 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-nest-site-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-nest-site-gene.hpp"
#include <stdexcept>
static void deserialize_ant_nest_site_phene(ant_nest_site_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_nest_site_phene(ant_nest_site_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
}
} // namespace
template <>
std::unique_ptr<ant_nest_site_gene> resource_loader<ant_nest_site_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto nest_site_element = json_data->find("nest_site");
if (nest_site_element == json_data->end())
throw std::runtime_error("Invalid nest_site gene.");
// Allocate gene
std::unique_ptr<ant_nest_site_gene> nest_site = std::make_unique<ant_nest_site_gene>();
std::unique_ptr<ant_nest_site_gene> gene = std::make_unique<ant_nest_site_gene>();
// Deserialize gene
deserialize_ant_gene(*nest_site, &deserialize_ant_nest_site_phene, *nest_site_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_nest_site_phene);
return nest_site;
return gene;
}

+ 8
- 2
src/game/ant/genes/ant-nest-site-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_NEST_SITE_GENE_HPP
#define ANTKEEPER_GAME_ANT_NEST_SITE_GENE_HPP
#include "game/ant/genes/monophenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <cstdint>
/**
@ -33,6 +33,12 @@ enum class ant_nest_site_phene: std::uint8_t
};
/// Ant nest site gene.
using ant_nest_site_gene = monophenic_ant_gene<ant_nest_site_phene>;
using ant_nest_site_gene = ant_gene<ant_nest_site_phene>;
template <>
inline constexpr ant_gene_type ant_nest_site_gene::type() const noexcept
{
return ant_gene_type::nest_site;
}
#endif // ANTKEEPER_GAME_ANT_NEST_SITE_GENE_HPP

+ 32
- 43
src/game/ant/genes/ant-ocelli-gene.cpp View File

@ -17,70 +17,59 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-ocelli-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-ocelli-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_ocelli_phene(ant_ocelli_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_ocelli_phene(ant_ocelli_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.lateral_ocelli_present = false;
phene.median_ocellus_present = false;
phene.lateral_ocelli_model = nullptr;
phene.median_ocellus_model = nullptr;
phene.width = 0.0f;
phene.height = 0.0f;
std::uint8_t lateral_ocelli_present{0};
ctx.read8(reinterpret_cast<std::byte*>(&lateral_ocelli_present), 1);
phene.lateral_ocelli_present = static_cast<bool>(lateral_ocelli_present);
// Parse lateral ocelli present
if (auto element = phene_element.find("lateral_ocelli_present"); element != phene_element.end())
phene.lateral_ocelli_present = element->get<bool>();
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.lateral_ocelli_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.lateral_ocelli_height), 1);
// Parse median ocelli present
if (auto element = phene_element.find("median_ocellus_present"); element != phene_element.end())
phene.median_ocellus_present = element->get<bool>();
std::uint8_t lateral_ocelli_model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&lateral_ocelli_model_filename_length), 1);
std::string lateral_ocelli_model_filename(lateral_ocelli_model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(lateral_ocelli_model_filename.data()), lateral_ocelli_model_filename_length);
// Parse width
if (auto element = phene_element.find("width"); element != phene_element.end())
phene.width = element->get<float>();
// Parse height
if (auto element = phene_element.find("height"); element != phene_element.end())
phene.height = element->get<float>();
// Load lateral ocelli model, if present
if (phene.lateral_ocelli_present)
{
if (auto element = phene_element.find("lateral_ocelli_model"); element != phene_element.end())
phene.lateral_ocelli_model = resource_manager.load<render::model>(element->get<std::string>());
phene.lateral_ocelli_model = resource_manager.load<render::model>(lateral_ocelli_model_filename);
}
// Load median ocellus model, if present
std::uint8_t median_ocellus_present{0};
ctx.read8(reinterpret_cast<std::byte*>(&median_ocellus_present), 1);
phene.median_ocellus_present = static_cast<bool>(median_ocellus_present);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.median_ocellus_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.median_ocellus_height), 1);
std::uint8_t median_ocellus_model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&median_ocellus_model_filename_length), 1);
std::string median_ocellus_model_filename(median_ocellus_model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(median_ocellus_model_filename.data()), median_ocellus_model_filename_length);
if (phene.median_ocellus_present)
{
if (auto element = phene_element.find("median_ocellus_model"); element != phene_element.end())
phene.median_ocellus_model = resource_manager.load<render::model>(element->get<std::string>());
phene.median_ocellus_model = resource_manager.load<render::model>(median_ocellus_model_filename);
}
}
} // namespace
template <>
std::unique_ptr<ant_ocelli_gene> resource_loader<ant_ocelli_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto ocelli_element = json_data->find("ocelli");
if (ocelli_element == json_data->end())
throw std::runtime_error("Invalid ocelli gene.");
// Allocate gene
std::unique_ptr<ant_ocelli_gene> ocelli = std::make_unique<ant_ocelli_gene>();
std::unique_ptr<ant_ocelli_gene> gene = std::make_unique<ant_ocelli_gene>();
// Deserialize gene
deserialize_ant_gene(*ocelli, &deserialize_ant_ocelli_phene, *ocelli_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_ocelli_phene);
return ocelli;
return gene;
}

+ 25
- 13
src/game/ant/genes/ant-ocelli-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_PHENE_OCELLI_GENE_HPP
#define ANTKEEPER_GAME_ANT_PHENE_OCELLI_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -29,26 +29,38 @@
*/
struct ant_ocelli_phene
{
/// 3D model of the lateral ocelli, if present.
std::shared_ptr<render::model> lateral_ocelli_model;
/// Lateral ocelli present.
bool lateral_ocelli_present{false};
/// 3D model of the median ocellus, if present.
std::shared_ptr<render::model> median_ocellus_model;
/// Lateral ocelli width, in mesosomal lengths.
float lateral_ocelli_width{0.0f};
/// Lateral ocelli present.
bool lateral_ocelli_present;
/// Lateral ocelli height, in mesosomal lengths.
float lateral_ocelli_height{0.0f};
/// 3D model of the lateral ocelli, if present.
std::shared_ptr<render::model> lateral_ocelli_model;
/// Median ocellus present.
bool median_ocellus_present;
bool median_ocellus_present{false};
/// Ocellus width, in mesosomal lengths.
float width;
/// Median ocellus width, in mesosomal lengths.
float median_ocellus_width{0.0f};
/// Ocellus height, in mesosomal lengths.
float height;
/// Median ocellus height, in mesosomal lengths.
float median_ocellus_height{0.0f};
/// 3D model of the median ocellus, if present.
std::shared_ptr<render::model> median_ocellus_model;
};
/// Ant ocelli gene.
using ant_ocelli_gene = polyphenic_ant_gene<ant_ocelli_phene>;
using ant_ocelli_gene = ant_gene<ant_ocelli_phene>;
template <>
inline constexpr ant_gene_type ant_ocelli_gene::type() const noexcept
{
return ant_gene_type::ocelli;
}
#endif // ANTKEEPER_GAME_ANT_PHENE_OCELLI_GENE_HPP

+ 14
- 21
src/game/ant/genes/ant-pigmentation-gene.cpp View File

@ -17,39 +17,32 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-pigmentation-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-pigmentation-gene.hpp"
#include <engine/render/material.hpp>
#include <stdexcept>
static void deserialize_ant_pigmentation_phene(ant_pigmentation_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_pigmentation_phene(ant_pigmentation_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.material = nullptr;
std::uint8_t material_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&material_filename_length), 1);
std::string material_filename(material_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(material_filename.data()), material_filename_length);
// Load pigmentation material
if (auto element = phene_element.find("material"); element != phene_element.end())
phene.material = resource_manager.load<render::material>(element->get<std::string>());
phene.material = resource_manager.load<render::material>(material_filename);
}
} // namespace
template <>
std::unique_ptr<ant_pigmentation_gene> resource_loader<ant_pigmentation_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto pigmentation_element = json_data->find("pigmentation");
if (pigmentation_element == json_data->end())
throw std::runtime_error("Invalid pigmentation gene.");
// Allocate gene
std::unique_ptr<ant_pigmentation_gene> pigmentation = std::make_unique<ant_pigmentation_gene>();
std::unique_ptr<ant_pigmentation_gene> gene = std::make_unique<ant_pigmentation_gene>();
// Deserialize gene
deserialize_ant_gene(*pigmentation, &deserialize_ant_pigmentation_phene, *pigmentation_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_pigmentation_phene);
return pigmentation;
return gene;
}

+ 8
- 2
src/game/ant/genes/ant-pigmentation-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_PIGMENTATION_GENE_HPP
#define ANTKEEPER_GAME_ANT_PIGMENTATION_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/material.hpp>
#include <memory>
@ -34,6 +34,12 @@ struct ant_pigmentation_phene
};
/// Ant pigmentation gene.
using ant_pigmentation_gene = polyphenic_ant_gene<ant_pigmentation_phene>;
using ant_pigmentation_gene = ant_gene<ant_pigmentation_phene>;
template <>
inline constexpr ant_gene_type ant_pigmentation_gene::type() const noexcept
{
return ant_gene_type::pigmentation;
}
#endif // ANTKEEPER_GAME_ANT_PIGMENTATION_GENE_HPP

+ 10
- 22
src/game/ant/genes/ant-pilosity-gene.cpp View File

@ -17,38 +17,26 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-pilosity-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-pilosity-gene.hpp"
#include <stdexcept>
static void deserialize_ant_pilosity_phene(ant_pilosity_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_pilosity_phene(ant_pilosity_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.density = 0.0f;
// Parse density
if (auto element = phene_element.find("density"); element != phene_element.end())
phene.density = element->get<float>();
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.density), 1);
}
} // namespace
template <>
std::unique_ptr<ant_pilosity_gene> resource_loader<ant_pilosity_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto pilosity_element = json_data->find("pilosity");
if (pilosity_element == json_data->end())
throw std::runtime_error("Invalid pilosity gene.");
// Allocate gene
std::unique_ptr<ant_pilosity_gene> pilosity = std::make_unique<ant_pilosity_gene>();
std::unique_ptr<ant_pilosity_gene> gene = std::make_unique<ant_pilosity_gene>();
// Deserialize gene
deserialize_ant_gene(*pilosity, &deserialize_ant_pilosity_phene, *pilosity_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_pilosity_phene);
return pilosity;
return gene;
}

+ 9
- 3
src/game/ant/genes/ant-pilosity-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_PILOSITY_GENE_HPP
#define ANTKEEPER_GAME_ANT_PILOSITY_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
/**
* Ant pilosity phene.
@ -28,10 +28,16 @@
struct ant_pilosity_phene
{
/// Hair density.
float density;
float density{0.0f};
};
/// Ant pilosity gene.
using ant_pilosity_gene = polyphenic_ant_gene<ant_pilosity_phene>;
using ant_pilosity_gene = ant_gene<ant_pilosity_phene>;
template <>
inline constexpr ant_gene_type ant_pilosity_gene::type() const noexcept
{
return ant_gene_type::pilosity;
}
#endif // ANTKEEPER_GAME_ANT_PILOSITY_GENE_HPP

+ 15
- 25
src/game/ant/genes/ant-sculpturing-gene.cpp View File

@ -17,44 +17,34 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-sculpturing-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-sculpturing-gene.hpp"
#include <engine/gl/texture-2d.hpp>
#include <stdexcept>
static void deserialize_ant_sculpturing_phene(ant_sculpturing_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_sculpturing_phene(ant_sculpturing_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.normal_map = nullptr;
phene.roughness = 0.0f;
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.roughness), 1);
// Load normal map
if (auto element = phene_element.find("normal_map"); element != phene_element.end())
phene.normal_map = resource_manager.load<gl::texture_2d>(element->get<std::string>());
std::uint8_t normal_map_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&normal_map_filename_length), 1);
std::string normal_map_filename(normal_map_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(normal_map_filename.data()), normal_map_filename_length);
// Parse roughness
if (auto element = phene_element.find("roughness"); element != phene_element.end())
phene.roughness = element->get<float>();
phene.normal_map = resource_manager.load<gl::texture_2d>(normal_map_filename);
}
} // namespace
template <>
std::unique_ptr<ant_sculpturing_gene> resource_loader<ant_sculpturing_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto sculpturing_element = json_data->find("sculpturing");
if (sculpturing_element == json_data->end())
throw std::runtime_error("Invalid sculpturing gene.");
// Allocate gene
std::unique_ptr<ant_sculpturing_gene> sculpturing = std::make_unique<ant_sculpturing_gene>();
std::unique_ptr<ant_sculpturing_gene> gene = std::make_unique<ant_sculpturing_gene>();
// Deserialize gene
deserialize_ant_gene(*sculpturing, &deserialize_ant_sculpturing_phene, *sculpturing_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_sculpturing_phene);
return sculpturing;
return gene;
}

+ 10
- 4
src/game/ant/genes/ant-sculpturing-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_SCULPTURING_GENE_HPP
#define ANTKEEPER_GAME_ANT_SCULPTURING_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/gl/texture-2d.hpp>
#include <memory>
@ -30,13 +30,19 @@
struct ant_sculpturing_phene
{
/// Surface roughness.
float roughness;
float roughness{0.0f};
/// Surface culpturing normal map.
std::shared_ptr<gl::texture_2d> normal_map;
};
/// Polyphenic sculpturing gene.
using ant_sculpturing_gene = polyphenic_ant_gene<ant_sculpturing_phene>;
/// Ant sculpturing gene.
using ant_sculpturing_gene = ant_gene<ant_sculpturing_phene>;
template <>
inline constexpr ant_gene_type ant_sculpturing_gene::type() const noexcept
{
return ant_gene_type::sculpturing;
}
#endif // ANTKEEPER_GAME_ANT_SCULPTURING_GENE_HPP

+ 17
- 25
src/game/ant/genes/ant-sting-gene.cpp View File

@ -17,47 +17,39 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-sting-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-sting-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_sting_phene(ant_sting_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_sting_phene(ant_sting_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.present = false;
phene.model = nullptr;
std::uint8_t present{0};
ctx.read8(reinterpret_cast<std::byte*>(&present), 1);
phene.present = static_cast<bool>(present);
// Parse present
if (auto element = phene_element.find("present"); element != phene_element.end())
phene.present = element->get<bool>();
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
if (phene.present)
{
// Load sting model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
phene.model = resource_manager.load<render::model>(model_filename);
}
}
} // namespace
template <>
std::unique_ptr<ant_sting_gene> resource_loader<ant_sting_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto sting_element = json_data->find("sting");
if (sting_element == json_data->end())
throw std::runtime_error("Invalid sting gene.");
// Allocate gene
std::unique_ptr<ant_sting_gene> sting = std::make_unique<ant_sting_gene>();
std::unique_ptr<ant_sting_gene> gene = std::make_unique<ant_sting_gene>();
// Deserialize gene
deserialize_ant_gene(*sting, &deserialize_ant_sting_phene, *sting_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_sting_phene);
return sting;
return gene;
}

+ 10
- 4
src/game/ant/genes/ant-sting-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_STING_GENE_HPP
#define ANTKEEPER_GAME_ANT_STING_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -30,13 +30,19 @@
struct ant_sting_phene
{
/// Indicates whether a sting present or not.
bool present;
bool present{false};
/// 3D model of the sting.
std::shared_ptr<render::model> model;
};
/// Polyphenic sting gene.
using ant_sting_gene = polyphenic_ant_gene<ant_sting_phene>;
/// Ant sting gene.
using ant_sting_gene = ant_gene<ant_sting_phene>;
template <>
inline constexpr ant_gene_type ant_sting_gene::type() const noexcept
{
return ant_gene_type::sting;
}
#endif // ANTKEEPER_GAME_ANT_STING_GENE_HPP

+ 28
- 73
src/game/ant/genes/ant-waist-gene.cpp View File

@ -17,95 +17,50 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-waist-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-waist-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_waist_phene(ant_waist_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_waist_phene(ant_waist_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.model = nullptr;
phene.petiole_present = false;
phene.petiole_length = 0.0f;
phene.petiole_width = 0.0f;
phene.petiole_height = 0.0f;
phene.petiole_spinescence = 0.0f;
phene.postpetiole_present = false;
phene.postpetiole_length = 0.0f;
phene.postpetiole_width = 0.0f;
phene.postpetiole_height = 0.0f;
phene.postpetiole_spinescence = 0.0f;
std::uint8_t petiole_present{0};
ctx.read8(reinterpret_cast<std::byte*>(&petiole_present), 1);
phene.petiole_present = static_cast<bool>(petiole_present);
// Load waist model
if (auto element = phene_element.find("model"); element != phene_element.end())
phene.model = resource_manager.load<render::model>(element->get<std::string>());
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.petiole_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.petiole_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.petiole_height), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.petiole_spinescence), 1);
// Parse petiole present
if (auto element = phene_element.find("petiole_present"); element != phene_element.end())
phene.petiole_present = element->get<bool>();
std::uint8_t postpetiole_present{0};
ctx.read8(reinterpret_cast<std::byte*>(&postpetiole_present), 1);
phene.postpetiole_present = static_cast<bool>(postpetiole_present);
// Parse postpetiole present
if (auto element = phene_element.find("postpetiole_present"); element != phene_element.end())
phene.postpetiole_present = element->get<bool>();
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.postpetiole_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.postpetiole_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.postpetiole_height), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.postpetiole_spinescence), 1);
if (phene.petiole_present)
{
// Parse petiole length
if (auto element = phene_element.find("petiole_length"); element != phene_element.end())
phene.petiole_length = element->get<float>();
// Parse petiole width
if (auto element = phene_element.find("petiole_width"); element != phene_element.end())
phene.petiole_width = element->get<float>();
// Parse petiole height
if (auto element = phene_element.find("petiole_height"); element != phene_element.end())
phene.petiole_height = element->get<float>();
// Parse petiole spinescence
if (auto element = phene_element.find("petiole_spinescence"); element != phene_element.end())
phene.petiole_spinescence = element->get<float>();
}
std::uint8_t model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&model_filename_length), 1);
std::string model_filename(model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(model_filename.data()), model_filename_length);
if (phene.postpetiole_present)
{
// Parse postpetiole length
if (auto element = phene_element.find("postpetiole_length"); element != phene_element.end())
phene.postpetiole_length = element->get<float>();
// Parse postpetiole width
if (auto element = phene_element.find("postpetiole_width"); element != phene_element.end())
phene.postpetiole_width = element->get<float>();
// Parse postpetiole height
if (auto element = phene_element.find("postpetiole_height"); element != phene_element.end())
phene.postpetiole_height = element->get<float>();
// Parse postpetiole spinescence
if (auto element = phene_element.find("postpetiole_spinescence"); element != phene_element.end())
phene.postpetiole_spinescence = element->get<float>();
}
phene.model = resource_manager.load<render::model>(model_filename);
}
} // namespace
template <>
std::unique_ptr<ant_waist_gene> resource_loader<ant_waist_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto waist_element = json_data->find("waist");
if (waist_element == json_data->end())
throw std::runtime_error("Invalid waist gene.");
// Allocate gene
std::unique_ptr<ant_waist_gene> waist = std::make_unique<ant_waist_gene>();
std::unique_ptr<ant_waist_gene> gene = std::make_unique<ant_waist_gene>();
// Deserialize gene
deserialize_ant_gene(*waist, &deserialize_ant_waist_phene, *waist_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_waist_phene);
return waist;
return gene;
}

+ 22
- 16
src/game/ant/genes/ant-waist-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_WAIST_GENE_HPP
#define ANTKEEPER_GAME_ANT_WAIST_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -31,41 +31,47 @@
*/
struct ant_waist_phene
{
/// 3D model of the waist.
std::shared_ptr<render::model> model;
//// Petiole presence.
bool petiole_present;
bool petiole_present{false};
/// Petiole length, in mesosomal lengths.
float petiole_length;
float petiole_length{0.0f};
/// Petiole width, in mesosomal lengths.
float petiole_width;
float petiole_width{0.0f};
/// Petiole height, in mesosomal lengths.
float petiole_height;
float petiole_height{0.0f};
/// Degree of petiole spinescence.
float petiole_spinescence;
float petiole_spinescence{0.0f};
/// Postpetiole presence.
bool postpetiole_present;
bool postpetiole_present{false};
/// Postpetiole length, in mesosomal lengths.
float postpetiole_length;
float postpetiole_length{0.0f};
/// Postpetiole width, in mesosomal lengths.
float postpetiole_width;
float postpetiole_width{0.0f};
/// Postpetiole height, in mesosomal lengths.
float postpetiole_height;
float postpetiole_height{0.0f};
/// Degree of postpetiole spinescence
float postpetiole_spinescence;
float postpetiole_spinescence{0.0f};
/// 3D model of the waist.
std::shared_ptr<render::model> model;
};
/// Polyphenic waist gene.
using ant_waist_gene = polyphenic_ant_gene<ant_waist_phene>;
/// Ant waist gene.
using ant_waist_gene = ant_gene<ant_waist_phene>;
template <>
inline constexpr ant_gene_type ant_waist_gene::type() const noexcept
{
return ant_gene_type::waist;
}
#endif // ANTKEEPER_GAME_ANT_WAIST_GENE_HPP

+ 35
- 60
src/game/ant/genes/ant-wings-gene.cpp View File

@ -17,82 +17,57 @@
* along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
*/
#include "game/ant/genes/ant-wings-gene.hpp"
#include "game/ant/genes/ant-gene-loader.hpp"
#include <engine/resources/resource-loader.hpp>
#include <engine/resources/resource-manager.hpp>
#include <engine/utility/json.hpp>
#include "game/ant/genes/ant-wings-gene.hpp"
#include <engine/render/model.hpp>
#include <stdexcept>
static void deserialize_ant_wings_phene(ant_wings_phene& phene, const json& phene_element, resource_manager& resource_manager)
namespace {
void load_ant_wings_phene(ant_wings_phene& phene, ::resource_manager& resource_manager, deserialize_context& ctx)
{
phene.present = false;
phene.forewings_model = nullptr;
phene.hindwings_model = nullptr;
phene.forewing_length = 0.0f;
phene.forewing_width = 0.0f;
phene.forewing_venation = 0.0f;
phene.hindwing_length = 0.0f;
phene.hindwing_width = 0.0f;
phene.hindwing_venation = 0.0f;
std::uint8_t present{0};
ctx.read8(reinterpret_cast<std::byte*>(&present), 1);
phene.present = static_cast<bool>(present);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.forewing_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.forewing_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.forewing_venation), 1);
// Parse present
if (auto element = phene_element.find("present"); element != phene_element.end())
phene.present = element->get<bool>();
std::uint8_t forewings_model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&forewings_model_filename_length), 1);
std::string forewings_model_filename(forewings_model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(forewings_model_filename.data()), forewings_model_filename_length);
if (phene.present)
{
// Load forewings model
if (auto element = phene_element.find("forewings_model"); element != phene_element.end())
phene.forewings_model = resource_manager.load<render::model>(element->get<std::string>());
// Load hindwings model
if (auto element = phene_element.find("hindwings_model"); element != phene_element.end())
phene.hindwings_model = resource_manager.load<render::model>(element->get<std::string>());
// Parse forewing length
if (auto element = phene_element.find("forewing_length"); element != phene_element.end())
phene.forewing_length = element->get<float>();
// Parse forewing width
if (auto element = phene_element.find("forewing_width"); element != phene_element.end())
phene.forewing_width = element->get<float>();
// Parse forewing venation
if (auto element = phene_element.find("forewing_venation"); element != phene_element.end())
phene.forewing_venation = element->get<float>();
// Parse hindwing length
if (auto element = phene_element.find("hindwing_length"); element != phene_element.end())
phene.hindwing_length = element->get<float>();
// Parse hindwing width
if (auto element = phene_element.find("hindwing_width"); element != phene_element.end())
phene.hindwing_width = element->get<float>();
// Parse hindwing venation
if (auto element = phene_element.find("hindwing_venation"); element != phene_element.end())
phene.hindwing_venation = element->get<float>();
phene.forewings_model = resource_manager.load<render::model>(forewings_model_filename);
}
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.hindwing_length), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.hindwing_width), 1);
ctx.read32<std::endian::little>(reinterpret_cast<std::byte*>(&phene.hindwing_venation), 1);
std::uint8_t hindwings_model_filename_length{0};
ctx.read8(reinterpret_cast<std::byte*>(&hindwings_model_filename_length), 1);
std::string hindwings_model_filename(hindwings_model_filename_length, '\0');
ctx.read8(reinterpret_cast<std::byte*>(hindwings_model_filename.data()), hindwings_model_filename_length);
if (phene.present)
{
phene.hindwings_model = resource_manager.load<render::model>(hindwings_model_filename);
}
}
} // namespace
template <>
std::unique_ptr<ant_wings_gene> resource_loader<ant_wings_gene>::load(::resource_manager& resource_manager, deserialize_context& ctx)
{
// Load JSON data
auto json_data = resource_loader<nlohmann::json>::load(resource_manager, ctx);
// Validate gene file
auto wings_element = json_data->find("wings");
if (wings_element == json_data->end())
throw std::runtime_error("Invalid wings gene.");
// Allocate gene
std::unique_ptr<ant_wings_gene> wings = std::make_unique<ant_wings_gene>();
std::unique_ptr<ant_wings_gene> gene = std::make_unique<ant_wings_gene>();
// Deserialize gene
deserialize_ant_gene(*wings, &deserialize_ant_wings_phene, *wings_element, resource_manager);
load_ant_gene(*gene, resource_manager, ctx, &load_ant_wings_phene);
return wings;
return gene;
}

+ 24
- 18
src/game/ant/genes/ant-wings-gene.hpp View File

@ -20,7 +20,7 @@
#ifndef ANTKEEPER_GAME_ANT_WINGS_GENE_HPP
#define ANTKEEPER_GAME_ANT_WINGS_GENE_HPP
#include "game/ant/genes/polyphenic-ant-gene.hpp"
#include "game/ant/genes/ant-gene.hpp"
#include <engine/render/model.hpp>
#include <memory>
@ -29,35 +29,41 @@
*/
struct ant_wings_phene
{
/// 3D model of the forewings.
std::shared_ptr<render::model> forewings_model;
/// 3D model of the hindwings.
std::shared_ptr<render::model> hindwings_model;
/// Wings presence.
bool present;
bool present{false};
/// Forewing length, in mesosomal lengths.
float forewing_length;
float forewing_length{0.0f};
/// Forewing width, in mesosomal lengths.
float forewing_width;
float forewing_width{0.0f};
/// Degree of forewing venation. A value of `1.0` indicates a highly-developed venation pattern, while `0.0` indicates a complete absence of visible venation.
float forewing_venation;
float forewing_venation{0.0f};
/// Forewing length, in mesosomal lengths.
float hindwing_length;
/// 3D model of the forewings.
std::shared_ptr<render::model> forewings_model;
/// Forewing width, in mesosomal lengths.
float hindwing_width;
/// Hindwing length, in mesosomal lengths.
float hindwing_length{0.0f};
/// Hindwing width, in mesosomal lengths.
float hindwing_width{0.0f};
/// Degree of hindwing venation. A value of `1.0` indicates a highly-developed venation pattern, while `0.0` indicates a complete absence of visible venation.
float hindwing_venation;
float hindwing_venation{0.0f};
/// 3D model of the hindwings.
std::shared_ptr<render::model> hindwings_model;
};
/// Polyphenic wings gene.
using ant_wings_gene = polyphenic_ant_gene<ant_wings_phene>;
/// Ant wings gene.
using ant_wings_gene = ant_gene<ant_wings_phene>;
template <>
inline constexpr ant_gene_type ant_wings_gene::type() const noexcept
{
return ant_gene_type::wings;
}
#endif // ANTKEEPER_GAME_ANT_WINGS_GENE_HPP

+ 2
- 2
src/game/components/ant-caste-component.hpp View File

@ -20,12 +20,12 @@
#ifndef ANTKEEPER_GAME_ANT_CASTE_COMPONENT_HPP
#define ANTKEEPER_GAME_ANT_CASTE_COMPONENT_HPP
#include "game/ant/ant-caste.hpp"
#include "game/ant/ant-caste-type.hpp"
struct ant_caste_component
{
/// Caste type.
ant_caste type;
ant_caste_type caste_type;
/// Subcaste type.
//ant_subcaste subtype;

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

@ -358,7 +358,7 @@ public:
double3 rgb_wavelengths;
const ecoregion* active_ecoregion;
std::shared_ptr<ecoregion> active_ecoregion;
render::anti_aliasing_method anti_aliasing_method;

+ 2
- 2
src/game/spawn.cpp View File

@ -37,7 +37,7 @@ entity::id spawn_ant_egg(::game& ctx, const ant_genome& genome, bool fertilized,
// Construct model component
model_component model_component;
model_component.render_model = genome.egg->phene.model;
model_component.render_model = genome.egg->phenes.front().model;
model_component.instance_count = 0;
model_component.layers = ~0;
ctx.entity_registry->emplace<::model_component>(egg_eid, model_component);
@ -60,7 +60,7 @@ entity::id spawn_ant_larva(::game& ctx, const ant_genome& genome, const float3&
// Construct model component
model_component model_component;
model_component.render_model = genome.larva->phene.model;
model_component.render_model = genome.larva->phenes.front().model;
model_component.instance_count = 0;
model_component.layers = ~0;
ctx.entity_registry->emplace<::model_component>(larva_eid, model_component);

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

@ -131,9 +131,9 @@ main_menu_state::main_menu_state(::game& ctx, bool fade_in):
[&ctx]()
{
ctx.state_machine.pop();
ctx.state_machine.emplace(std::make_unique<nuptial_flight_state>(ctx));
//ctx.state_machine.emplace(std::make_unique<nuptial_flight_state>(ctx));
//ctx.state_machine.emplace(std::make_unique<collection_menu_state>(ctx));
//ctx.state_machine.emplace(std::make_unique<nest_selection_state>(ctx));
ctx.state_machine.emplace(std::make_unique<nest_selection_state>(ctx));
}
);
};

+ 5
- 3
src/game/states/nest-selection-state.cpp View File

@ -79,7 +79,9 @@ nest_selection_state::nest_selection_state(::game& ctx):
// Create observer
::world::create_observer(ctx);
}
::world::enter_ecoregion(ctx, *ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco"));
ctx.active_ecoregion = ctx.resource_manager->load<::ecoregion>("seedy-scrub.eco");
::world::enter_ecoregion(ctx, *ctx.active_ecoregion);
debug::log::trace("Generating genome...");
std::random_device rng;
@ -87,7 +89,7 @@ nest_selection_state::nest_selection_state(::game& ctx):
debug::log::trace("Generated genome");
debug::log::trace("Building worker phenome...");
ant_phenome worker_phenome = ant_phenome(*genome, ant_caste::worker);
ant_phenome worker_phenome = ant_phenome(*genome, ant_caste_type::worker);
debug::log::trace("Built worker phenome...");
debug::log::trace("Generating worker model...");
@ -98,7 +100,7 @@ nest_selection_state::nest_selection_state(::game& ctx):
entity::id worker_eid = ctx.entity_registry->create();
transform_component worker_transform_component;
worker_transform_component.local = math::transform<float>::identity;
worker_transform_component.local.translation = {0, 0, -20};
worker_transform_component.local.translation = {0, 0, -4};
worker_transform_component.world = worker_transform_component.local;
worker_transform_component.warp = true;
ctx.entity_registry->emplace<transform_component>(worker_eid, worker_transform_component);

+ 11
- 11
src/game/states/nuptial-flight-state.cpp View File

@ -121,7 +121,7 @@ nuptial_flight_state::nuptial_flight_state(::game& ctx):
(
[&](entity::id entity_id, const auto& caste)
{
if (caste.type == ant_caste::male)
if (caste.caste_type == ant_caste_type::male)
{
ctx.entity_registry->emplace_or_replace<name_component>
(
@ -971,21 +971,21 @@ void nuptial_flight_state::select_entity(entity::id entity_id)
const auto& name = ctx.entity_registry->get<::name_component>(selected_eid).name;
std::string format_string;
switch (caste.type)
switch (caste.caste_type)
{
case ::ant_caste::queen:
case ::ant_caste_type::queen:
format_string = ::get_string(ctx, "named_queen_label_format");
break;
case ::ant_caste::worker:
case ::ant_caste_type::worker:
format_string = ::get_string(ctx, "named_worker_label_format");
break;
case ::ant_caste::soldier:
case ::ant_caste_type::soldier:
format_string = ::get_string(ctx, "named_soldier_label_format");
break;
case ::ant_caste::male:
case ::ant_caste_type::male:
format_string = ::get_string(ctx, "named_male_label_format");
break;
@ -998,21 +998,21 @@ void nuptial_flight_state::select_entity(entity::id entity_id)
}
else
{
switch (caste.type)
switch (caste.caste_type)
{
case ::ant_caste::queen:
case ::ant_caste_type::queen:
selection_text.set_content(get_string(ctx, "queen_caste_name"));
break;
case ::ant_caste::worker:
case ::ant_caste_type::worker:
selection_text.set_content(get_string(ctx, "worker_caste_name"));
break;
case ::ant_caste::soldier:
case ::ant_caste_type::soldier:
selection_text.set_content(get_string(ctx, "soldier_caste_name"));
break;
case ::ant_caste::male:
case ::ant_caste_type::male:
selection_text.set_content(get_string(ctx, "male_caste_name"));
break;

+ 1
- 1
src/game/world.cpp View File

@ -524,7 +524,7 @@ void enter_ecoregion(::game& ctx, const ecoregion& ecoregion)
debug::log::trace("Entering ecoregion {}...", ecoregion.name);
{
// Set active ecoregion
ctx.active_ecoregion = &ecoregion;
//ctx.active_ecoregion = &ecoregion;
// Set location
::world::set_location(ctx, ecoregion.elevation, ecoregion.latitude, ecoregion.longitude);

Loading…
Cancel
Save